绿满眶商城微信小程序-uniapp
8个文件已修改
1个文件已添加
1900 ■■■■■ 已修改文件
api/video.js 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manifest.json 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/commodity-square/commoditySquare.vue 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/kitchen/KitchenVideo.vue 1336 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/mine/deposit/operation.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/order/fillorder.vue 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabbar/index/home.vue 315 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/video.js
@@ -26,7 +26,7 @@
 * 
 * @param params
 */
 export function getRecommendVideos(params) {
 export async function getRecommendVideos(params) {
  return http.request({
    url: "/lmk/video/recommend",
    method: Method.GET,
@@ -35,6 +35,44 @@
  });
}
/**
 * 获取大健康推荐视频
 *
 * @param params
 */
 export function getHealthRecommendVideos(params) {
  return http.request({
    url: "/lmk/video/health/recommend",
    method: Method.GET,
    needToken: true,
    params: params
  });
}
/**
 * 获取厨神分类
 *
 * @param params
 */
 export function getkitchenTypeList() {
  return http.request({
    url: "/lmk/video/kitchen/type",
    method: Method.GET,
    needToken: true,
  });
}
/**
 * 获取厨神视频列表
 *
 * @param params
 */
 export function getkitchenVideoList(params) {
  return http.request({
    url: "/lmk/video/kitchen/recommend",
    method: Method.GET,
    needToken: true,
    params: params
  });
}
/**
 * 获取视频悬挂商品
 * 
@@ -197,4 +235,4 @@
    method: Method.POST,
    needToken: true
  });
}
}
manifest.json
@@ -213,7 +213,8 @@
        //     "version" : "1.3.0",
        //     "provider" : "wx2b03c6e691cd7370"
        // }
        "requiredPrivateInfos" : [ "chooseLocation", "getLocation" ]
        "requiredPrivateInfos" : [ "chooseLocation", "getLocation" ],
        "lazyCodeLoading": "requiredComponents"
    },
    "h5" : {
        "devServer" : {
pages.json
@@ -1438,6 +1438,15 @@
                    "navigationBarTitleText": "大健康"
                }
            }]
        },
        {
            "root": "pages/kitchen",
            "pages": [{
                "path": "KitchenVideo",
                "style": {
                    "navigationBarTitleText": "厨神"
                }
            }]
        }
        // ,
        // {
pages/commodity-square/commoditySquare.vue
@@ -1,6 +1,9 @@
<template>
    <view class="container">
        <input type="text" v-show="false" v-model="flushDom" />
        <view class="search">
            <u-search class="nav-search" @blur='searchGoods' placeholder="搜索商品" :show-action="false"></u-search>
        </view>
        <view class="commoditySquare">
            <view class="left" style="width: 310rpx;">
                <view class="commoditySquareItem" v-for="(item,index) in goodsList1"
@@ -45,14 +48,14 @@
            <view class="openShowLeft" @click="showDrawer('showLeft')" v-if="!showLeft">
                <uni-icons type="right" size="30"></uni-icons>
            </view>
            <uni-drawer ref="showLeft" mode="left" width="120" @change="change($event,'showLeft')"
                class="navigationLeft">
                <view class="typeNavigation">
            <uni-drawer ref="showLeft" mode="left" width="120" height="94vh" @change="change($event,'showLeft')"
                :cus-style="true" class="navigationLeft">
                <scroll-view class="typeNavigation" :scroll-y="true" show-scrollbar="false">
                    <view class="typeNavigationItem" :class="{typeNavigationItemCheck:currentCategort ==item.id}"
                        @click="chooseCategory(item.id)" v-for="item in categoryList" :key="item.id">
                        {{item.name}}
                    </view>
                </view>
                </scroll-view>
            </uni-drawer>
        </view>
        <view style="display: flex;align-items: center;justify-content: center;margin-top: 20rpx;" v-if="canLoadMore">
@@ -72,6 +75,9 @@
    export default {
        data() {
            return {
                //记录两列高度
                listHeight1: 0,
                listHeight2: 0,
                //是否显示打开左侧弹窗
                showLeft: false,
                //商品导航分类
@@ -97,6 +103,14 @@
            }
        },
        methods: {
            async searchGoods(keyWard) {
                this.getGoodsParam.keyword = keyWard
                this.getGoodsParam.pageNumber = 1
                this.getGoodsParam.categoryId = ''
                this.goodsList1 = []
                this.goodsList2 = []
                await this.getgoodsData();
            },
            confirm() {},
            // 打开窗口
            showDrawer(e) {
@@ -115,9 +129,24 @@
                const height = e.detail.height;
                this[arrName][index].width = 310 + 'rpx';
                //计算宽高比
                const videoHeight = 310 / (wight / height)
                this[arrName][index].height = Math.floor(videoHeight) + 'rpx';
                const videoHeight = Math.floor(310 / (wight / height))
                this[arrName][index].height = videoHeight + 'rpx';
                this[arrName][index].show = true;
                //计算集合高度
                if (arrName === 'goodsList2') {
                    if (videoHeight > 300) {
                        this.listHeight2 += videoHeight;
                    } else if (videoHeight < 300) {
                        this.listHeight2 -= videoHeight;
                    }
                }
                if (arrName === 'goodsList1') {
                    if (videoHeight > 300) {
                        this.listHeight1 += videoHeight;
                    } else if (videoHeight < 300) {
                        this.listHeight1 -= videoHeight;
                    }
                }
                console.log(this[arrName][index].width, this[arrName][index].height)
                this.flushDom = new Date();
            },
@@ -132,13 +161,7 @@
                let list = await getCategoryList(0);
                this.categoryList = list.data.result
            },
            async chooseCategory(id) {
                if (this.currentCategort === id) return
                this.canLoadMore = false;
                this.currentCategort = id
                this.getGoodsParam.categoryId = id
                this.getGoodsParam.keyword = ''
                this.getGoodsParam.pageNumber = 1
            async getgoodsData() {
                const goodsList = await getGoodsList(this.getGoodsParam);
                const sts = await getSTSToken();
                const stsUrl = sts.data.data.endpoint
@@ -153,11 +176,45 @@
                        item.goodsVideo = stsUrl + '/' + item.goodsVideo
                    }
                })
                //计算两个数组的长度 用于解决瀑布流两边高度不一致问题
                //平分给两个数组
                const middle = Math.ceil(goodsList.data.result.records.length / 2);
                this.goodsList1 = goodsList.data.result.records.slice(0, middle);
                this.goodsList2 = goodsList.data.result.records.slice(middle);
                const goodsSize = goodsList.data.result.records.length;
                let middle = Math.ceil(goodsSize / 2);
                //判断那个集合长度高 重新分配集合数据
                const diffHeight = this.listHeight1 - this.listHeight2;
                //list1长度大于list2
                if (diffHeight > 0) {
                    const needCount = Math.floor(diffHeight / 300)
                    if (needCount > 6) {
                        middle = 0;
                    } else {
                        middle -= needCount;
                    }
                } else if(diffHeight < 0) {
                    const needCount = Math.abs(Math.floor(diffHeight / 300))
                    if (needCount > 6) {
                        middle += 6
                    } else {
                        middle = needCount;
                    }
                }
                this.goodsList1 = [...this.goodsList1, ...goodsList.data.result.records.slice(0, middle)];
                this.goodsList2 = [...this.goodsList2, ...goodsList.data.result.records.slice(middle)];
                this.maxPages = goodsList.data.result.pages
                // if(this.listHeight1===0||this.listHeight2===0)}
                this.listHeight1 += middle * 300;
                this.listHeight2 += (goodsSize - middle) * 300
            },
            async chooseCategory(id) {
                this.canLoadMore = false;
                this.currentCategort = id
                this.getGoodsParam.categoryId = id
                this.getGoodsParam.keyword = ''
                this.getGoodsParam.pageNumber = 1
                this.goodsList1 = [];
                this.goodsList2 = [];
                await this.getgoodsData();
                console.log(this.maxPages)
            }
        },
@@ -169,49 +226,12 @@
            this.getGoodsParam.pageNumber = 1
            this.getGoodsParam.categoryId = ""
            this.getGoodsParam.keyword = ""
            const goodsList = await getGoodsList(this.getGoodsParam);
            const sts = await getSTSToken();
            const stsUrl = sts.data.data.endpoint
            // 处理数据
            goodsList.data.result.records.forEach(item => {
                if (item.thumbnail !== '' && item.thumbnail !== null && item.thumbnail.indexOf('http') ===
                    -1) {
                    item.thumbnail = stsUrl + '/' + item.thumbnail
                }
                if (item.goodsVideo !== '' && item.goodsVideo !== null && item.goodsVideo.indexOf(
                        'http') === -1) {
                    item.goodsVideo = stsUrl + '/' + item.goodsVideo
                }
            })
            //平分给两个数组
            const middle = Math.ceil(goodsList.data.result.records.length / 2);
            this.goodsList1 = goodsList.data.result.records.slice(0, middle);
            this.goodsList2 = goodsList.data.result.records.slice(middle);
            this.maxPages = goodsList.data.result.pages
            console.log(this.maxPages)
            await this.getgoodsData()
        },
        async onReachBottom() {
            if (this.getGoodsParam.pageNumber < this.maxPages) {
                this.getGoodsParam.pageNumber++;
                const goodsList = await getGoodsList(this.getGoodsParam);
                const sts = await getSTSToken();
                const stsUrl = sts.data.data.endpoint
                // 处理数据
                goodsList.data.result.records.forEach(item => {
                    if (item.thumbnail !== '' && item.thumbnail !== null && item.thumbnail.indexOf('http') ===
                        -1) {
                        item.thumbnail = stsUrl + '/' + item.thumbnail
                    }
                    if (item.goodsVideo !== '' && item.goodsVideo !== null && item.goodsVideo.indexOf(
                            'http') === -1) {
                        item.goodsVideo = stsUrl + '/' + item.goodsVideo
                    }
                })
                //平分给两个数组
                const middle = Math.ceil(goodsList.data.result.records.length / 2);
                this.goodsList1 = [...this.goodsList1, ...goodsList.data.result.records.slice(0, middle)];
                this.goodsList2 = [...this.goodsList2, ...goodsList.data.result.records.slice(middle)];
                this.maxPages = goodsList.data.result.pages
                await this.getgoodsData()
            } else {
                this.canLoadMore = true;
            }
@@ -265,8 +285,16 @@
    .openShowLeft {
        position: fixed;
        top: 30rpx;
        top: 120rpx;
        left: 0;
        align-items: center;
        justify-content: flex-start;
        background-color: #b6b6b6;
        opacity: 0.8;
        z-index: 999;
        height: 70rpx;
        width: 50rpx;
        border-radius: 0 50% 50% 0;
    }
    .navigationLeft {
@@ -303,8 +331,10 @@
    .typeNavigation {
        box-sizing: border-box;
        padding: 10rpx;
        position: relative;
        height: 100%;
        // position: relative;
    }
    .typeNavigationItem {
@@ -327,4 +357,13 @@
        top: 20rpx;
        right: 0;
    }
    .nav-search {
        padding-left: 30rpx !important;
        padding-right: 20rpx !important;
        // position: fixed;
        // top: 0;
        // width: 500rpx;
        // z-index: 9999;
    }
</style>
pages/kitchen/KitchenVideo.vue
New file
@@ -0,0 +1,1336 @@
<template>
    <view class="video-container">
        <!-- 视频列表 -->
        <swiper class="video-swiper" vertical circular :current="currentIndex" @change="onSwiperChange">
            <view class="showLeft" @click="showDrawer('showLeft')" v-if="!showLeft">
                <uni-icons type="right" size="30"></uni-icons>
            </view>
            <swiper-item v-for="(item, index) in videoList" :key="item.id">
                <view style="width: 100%;height: 100%;" v-if="item.videoContentType === 'video'">
                    <!-- 播放按钮(仅当视频暂停时显示) -->
                    <view class="play-icon" @click="togglePlay(index)" v-if="!currentVideoIsPlaying">
                        <image src="/static/video/play.png" style="width: 45px;height: 45px" mode="aspectFit"></image>
                    </view>
                    <video :id="'video'+index" :ref="'video'+index" :src="item.videoUrl"
                        :autoplay="currentIndex === index" :controls="false" :loop="true" :object-fit="item.objectFit"
                        :enable-progress-gesture="false" class="video-item" @play="onPlay(item.id, index)"
                        @pause="onPause(index)" @ended="onEnded(index)" @click="togglePlay(index)"
                        @timeupdate="onTimeUpdate($event)" @loadedmetadata="onLoadedMetadata($event)"></video>
                    <!-- 自定义控制条 -->
                    <view @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd"
                        class="container">
                        <!-- 进度条 - 整个区域可拖动 -->
                        <view class="process-warp" :style="{ opacity: showProcess ? 1 : 0 }">
                            <!-- 显示当前进度 -->
                            <view class="progress-text">{{ hasPlayTime }}/{{formartDuration[index]}}</view>
                            <view class="progress-bar" id="progressBar">
                                <!-- 已填充部分 -->
                                <view class="progress-fill" :style="{ width: progress + '%' }"></view>
                            </view>
                        </view>
                    </view>
                </view>
                <view style="width: 100%; height: 100%;" v-else-if="item.videoContentType === 'img'">
                    <uni-swiper-dot :info="item.imgs" :current="currentImgIndex" mode="round"
                        style="width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;"
                        :dots-styles="{width: 24, bottom: 24,selectedBackgroundColor: 'green', backgroundColor: 'gray'}">
                        <swiper class="swiper-box" @change="imgChange" :autoplay="true" :interval="3000">
                            <swiper-item v-for="img in item.imgs" :key="img">
                                <view class="swiper-item">
                                    <!-- 调整 image 样式,使其居中且按比例缩放 -->
                                    <image :src="img" mode="aspectFit"
                                        style="width: 100%; height: 100%; display: block; margin: 0 auto;"></image>
                                </view>
                            </swiper-item>
                        </swiper>
                    </uni-swiper-dot>
                </view>
                <!-- 悬挂商品链接层 -->
                <view class="goods-link-warp" v-if="false">
                    <view class="goods-link">
                        <view class="goods-container">
                            <!-- 商品图片 -->
                            <image class="goods-image" :src="item.goods.imageUrl" mode="aspectFill"></image>
                            <!-- 商品信息 -->
                            <view class="goods-info">
                                <text class="goods-name">{{item.goods.name}}</text>
                                <view class="price-section">
                                    <text class="current-price">¥{{item.goods.price}}</text>
                                    <text class="original-price"
                                        v-if="item.goods.originalPrice">¥{{item.goods.originalPrice}}</text>
                                </view>
                                <text class="sales-count">{{item.goods.saleNum}}人已购</text>
                            </view>
                            <!-- 购买按钮 -->
                            <view class="buy-button">
                                <text>购买</text>
                            </view>
                        </view>
                    </view>
                </view>
                <!-- 视频信息层 -->
                <view class="video-info">
                    <view>
                        <text class="video-author">@{{item.authorName}}</text>
                    </view>
                    <view style="width: 100%;word-wrap: break-word;white-space: normal;overflow-wrap: break-word;">
                        <text class="video-title">{{item.title}}</text>
                        <text class="video-tag" v-for="(tag, index) in item.tagList"
                            :key="tag.id">#{{tag.tagName}}</text>
                    </view>
                </view>
                <!-- 右侧互动按钮 -->
                <view class="action-buttons" v-if="false">
                    <view class="avatar-container">
                        <image class="avatar" @click="jumpToHomePage(item.authorId)" :src="item.authorAvatar"
                            mode="aspectFill"></image>
                        <!-- 关注图标 - 使用绝对定位 -->
                        <view v-if="!item.subscribeThisAuthor" class="follow-icon"
                            @click="subscribeAuth(index, item.authorId)">
                            <text class="iconfont">&#xe629;</text>
                        </view>
                    </view>
                    <view class="action-item" @click="toggleCollect(item, index)">
                        <text class="iconfont" v-if="item.collected">&#xe605;</text>
                        <text class="iconfont" v-else>&#xe601;</text>
                        <text style="font-size: 10px;font-weight: lighter;">{{item.collectNum}}</text>
                    </view>
                    <view class="action-item" @click="showComments(item)">
                        <text class="iconfont">&#xe7f7;</text>
                        <text style="font-size: 10px;font-weight: lighter;">{{item.commentNum}}</text>
                    </view>
                </view>
            </swiper-item>
        </swiper>
        <!-- 评论弹窗 -->
        <uni-popup ref="commentPopup" type="bottom" :is-mask-click="true" @maskClick="closeCommentPopup">
            <view class="comment-popup">
                <view class="popup-header">
                    <text class="popup-title" v-if="!commentForm.replyId">评论({{commentsTotal}})</text>
                    <view class="reply-title" v-else>
                        <text>回复 @{{commentForm.replyUserNickname}}</text>
                        <text class="cancel-reply" @click="cancelReply">取消</text>
                    </view>
                    <text class="iconfont close-icon" @click="closeCommentPopup">&#xe675;</text>
                </view>
                <scroll-view class="comment-list" scroll-y :show-scrollbar="false" @scrolltolower="getCommentPage">
                    <view v-if="commentLoading" class="loading">
                        <uni-load-more status="loading"></uni-load-more>
                    </view>
                    <view v-else-if="comments.length === 0" class="empty">
                        暂无评论,快来发表第一条评论吧~
                    </view>
                    <view v-else class="comment-item" v-for="(comment, index) in comments" :key="comment.id">
                        <view style="display: flex;">
                            <image class="comment-avatar" :src="comment.userAvatar || '/static/default-avatar.png'">
                            </image>
                            <view class="comment-content">
                                <text class="nickname">{{comment.userNickname}}</text>
                                <text class="content">{{comment.commentContent}}</text>
                                <view style="position: relative;">
                                    <text class="time">{{formatTime(comment.createTime)}}</text>
                                    <text @click="openReply(comment)" class="reply-btu time">回复</text>
                                    <text v-if="!comment.hasThumbsUp" class="thumbs-up time iconfont"
                                        @click="thubmsUp(comment.id, index, null)">&#xe614;<text
                                            v-show="comment.thumbsUpNum > 0"
                                            class="thumbs-num">{{comment.thumbsUpNum}}</text></text>
                                    <text v-else class="thumbs-up time iconfont"
                                        @click="cancelThumbsUp(comment.id, index, null)">&#xe607;<text
                                            v-show="comment.thumbsUpNum > 0"
                                            class="thumbs-num">{{comment.thumbsUpNum}}</text></text>
                                </view>
                            </view>
                        </view>
                        <!-- 回复列表 -->
                        <view class="reply-list" v-if="comment.replies && comment.replies.length > 0">
                            <view class="reply-item" v-for="(reply, replyIndex) in comment.replies" :key="reply.id">
                                <view class="reply-content">
                                    <view style="display: flex;">
                                        <image class="comment-reply-avatar"
                                            :src="reply.replyUserAvatar || '/static/default-avatar.png'"></image>
                                        <text class="nickname">{{reply.userNickname}}</text>
                                        <text v-if="reply.replyUserId && reply.masterCommentId !== reply.replyId"
                                            class="reply-to"><text style="margin-right: 10rpx;font-size: 28rpx;"
                                                class="iconfont">&#xe666;</text>{{reply.replyUserNickname}}</text>
                                    </view>
                                    <text class="content">{{reply.commentContent}}</text>
                                    <view class="reply-footer">
                                        <text class="time">{{formatTime(reply.createTime)}}</text>
                                        <text @click="openReply(comment, reply)" class="reply-btu time">回复</text>
                                        <text v-if="!reply.hasThumbsUp" class="thumbs-up time iconfont"
                                            @click="thubmsUp(reply.id, index, replyIndex)">&#xe614;<text
                                                v-show="reply.thumbsUpNum > 0"
                                                class="thumbs-num">{{reply.thumbsUpNum}}</text></text>
                                        <text v-else class="thumbs-up time iconfont"
                                            @click="cancelThumbsUp(reply.id, index, replyIndex)">&#xe607;<text
                                                v-show="reply.thumbsUpNum > 0"
                                                class="thumbs-num">{{reply.thumbsUpNum}}</text></text>
                                    </view>
                                </view>
                            </view>
                        </view>
                        <view class="view-more-replies" v-if="comment.replyTotalCount > 0 && !comment.expandReply"
                            @click="loadRepliesPage(comment, index)">
                            <text class="line">——</text>展开{{comment.replyTotalCount}}条回复 ↓
                        </view>
                        <view class="reply-op"
                            v-if="comment.replyTotalCount > replyCommentQuery.pageNumber * replyCommentQuery.pageSize && comment.expandReply">
                            <view @click="loadNextPageReply(index)" class="reply-op-item"><text
                                    class="line">——</text>展开更多<text class="iconfont textSideIcon">&#xeb8d;</text></view>
                            <view @click="retractReplyComment(index)" class="reply-op-item" style="margin-left: 50rpx;">
                                收起<text class="iconfont textSideIcon">&#xeb9b;</text></view>
                        </view>
                        <view class="reply-op"
                            v-else-if="comment.replyTotalCount <= replyCommentQuery.pageNumber * replyCommentQuery.pageSize && comment.expandReply">
                            <view @click="retractReplyComment(index)" class="reply-op-item"><text
                                    class="line">——</text>收起<text class="iconfont textSideIcon">&#xeb9b;</text></view>
                        </view>
                    </view>
                </scroll-view>
                <view class="comment-input-area">
                    <input ref="commentInput" class="comment-input" v-model="commentForm.commentContent"
                        :placeholder="commentForm.replyId ? `回复 @${commentForm.replyUserNickname}` : '写下你的评论...'"
                        placeholder-class="placeholder" />
                    <button class="submit-btn" @click="submitComment"
                        :disabled="!commentForm.commentContent.trim()">发送</button>
                </view>
            </view>
        </uni-popup>
        <uni-drawer ref="showLeft" mode="left" width="120" :cus-style="true" height="93vh"
            @change="change($event,'showLeft')" class="navigationLeft">
            <scroll-view class="typeNavigation" :scroll-y="true" :show-scrollbar="false">
                <view class="typeNavigationItem" :class="{typeNavigationItemCheck:currentCategort ==item.id}"
                    @click="chooseCategory(item.id)" v-for="item in categoryList" :key="item.id">
                    {{item.typeName}}
                </view>
            </scroll-view>
        </uni-drawer>
    </view>
</template>
<script>
    import {
        getkitchenTypeList,
        getkitchenVideoList,
        savePlayRecord,
        subscribe,
        getVideoComments,
        addVideoComment,
        thubmsUpComment,
        cancelThubmsUpComment
    } from "@/api/video.js";
    import {
        changeCollect
    } from "@/api/collect.js";
    export default {
        computed: {
            hasPlayTime() {
                return this.sliderFormatTime(this.progress > 0 ? this.duration * this.progress / 100 : 0);
            }
        },
        data() {
            return {
                currentCategort: '',
                categoryList: [],
                currentImgIndex: 0, // 播放到第几张图--索引
                currentTime: 0,
                formartDuration: [],
                duration: 0,
                startX: 0,
                progress: 0, // 视频进度
                startProgress: 0, // 开始滑动时的进度
                barLeft: 0, // 进度条左边界位置
                barWidth: 0, // 进度条宽度
                isDragging: false, // 是否正在拖动
                processHidenTimer: null, // 进度条隐藏定时器
                showProcess: false, // 是否显示进度条
                videoNoMore: false, // 是否还有更多视频
                commentNoMore: false, // 是否还有更多评论
                commentQuery: {
                    pageNumber: 1,
                    pageSize: 5,
                    videoId: '',
                    masterCommentId: ''
                },
                replyCommentQuery: {
                    pageNumber: 1,
                    pageSize: 5,
                    videoId: '',
                    masterCommentId: ''
                },
                commentForm: { // 评论表单数据
                    id: '',
                    videoId: '',
                    commentContent: '',
                    replyId: '',
                    replyUserId: '',
                    replyUserNickname: '',
                    replyUserAvatar: '',
                    masterCommentId: null
                },
                comments: [], // 评论列表
                commentsTotal: 0, // 评论总条数
                commentLoading: false, // 评论加载状态
                startHidenTime: 0, // 记录切换至其它页面的时间,用于计算视频观看时间减去的部分
                totalHidenTime: 0, // 总共隐藏页面的时间
                startPauseTime: 0, // 开始暂停的时间
                totalPauseTime: 0, // 总共暂停的时间
                playRecord: {
                    videoId: null,
                    viewDuration: 0, // 这个视频总共观看了多久
                    playAt: 0, // 这个视频播放到哪了
                    startPlayTime: 0 // 这个视频从什么时候开始播放的
                },
                currentVideoIsPlaying: true, // 当前视频是否正在播放
                isFullScreen: false,
                windowHeight: 0,
                currentIndex: 0, // 当前播放的视频索引
                videoList: [
                ], // 视频列表数据
                videoContexts: [], // 视频上下文对象集合
                loading: false, // 是否正在加载
                videoQuery: {
                    pageNumber: 1,
                    pageSize: 6,
                    videoFrom: 'recommend',
                    videoType: 'cook'
                }
            }
        },
        onShow() {
            this.showDrawer('showLeft')
            this.loadVideos()
            // 如果视频按下暂停后切换页面再回到页面时,只算暂停时间(因为暂停时间和离开页面时间是重复的,只算一个)
            if (this.startHidenTime !== 0 && this.currentVideoIsPlaying) {
                const duration = Date.now() - this.startHidenTime
                this.totalHidenTime += duration
            }
        },
        onHide() {
            this.startHidenTime = Date.now()
        },
        onLoad() {
            this.getKitchenTypeList();
            this.loadVideos();
        },
        onReady() {
            // 初始化视频上下文
            this.initVideoContexts();
        },
        methods: {
            async chooseCategory(id) {
                if (this.currentCategort === id) return
                this.currentCategort = id
                this.videoQuery.pageNumber = 1,
                this.videoQuery.kitchenTypeId = id;
                await this.loadVideos()
            },
            getKitchenTypeList() {
                getkitchenTypeList().then(res => {
                    this.categoryList = res.data.data
                })
            },
            showDrawer(e) {
                this.$refs[e].open()
            },
            // 关闭窗口
            closeDrawer(e) {
                this.$refs[e].close()
            },
            // 抽屉状态发生变化触发
            change(e, type) {
                this[type] = e
            },
            // 轮播图变化
            imgChange(e) {
                this.currentImgIndex = e.detail.current;
            },
            // 获取进度条的位置和尺寸
            getBarRect() {
                const query = uni.createSelectorQuery().in(this);
                query.select('#progressBar').boundingClientRect(rect => {
                    if (rect) {
                        this.barLeft = rect.left;
                        this.barWidth = rect.width;
                    }
                }).exec();
            },
            // 跳转个人主页
            jumpToHomePage(authorId) {
                uni.navigateTo({
                    url: "/pages/video/home-page?authorId=" + authorId
                })
            },
            // 取消点赞
            async cancelThumbsUp(id, commentIndex, replyIndex) {
                const data = {
                    refId: id,
                    thumbsUpType: 'video_comment'
                }
                cancelThubmsUpComment(data).then(res => {
                    if (replyIndex != null) {
                        this.comments[commentIndex].replies[replyIndex].hasThumbsUp = false;
                        this.comments[commentIndex].replies[replyIndex].thumbsUpNum -= 1;
                    } else {
                        this.comments[commentIndex].hasThumbsUp = false;
                        this.comments[commentIndex].thumbsUpNum -= 1;
                    }
                })
            },
            // 评论点赞
            async thubmsUp(id, commentIndex, replyIndex) {
                const data = {
                    refId: id,
                    thumbsUpType: 'video_comment'
                }
                thubmsUpComment(data).then(res => {
                    if (replyIndex != null) {
                        this.comments[commentIndex].replies[replyIndex].hasThumbsUp = true;
                        this.comments[commentIndex].replies[replyIndex].thumbsUpNum += 1;
                    } else {
                        this.comments[commentIndex].hasThumbsUp = true;
                        this.comments[commentIndex].thumbsUpNum += 1;
                    }
                })
            },
            // 加载下一页回复
            loadNextPageReply(index) {
                this.replyCommentQuery.pageNumber++;
                getVideoComments(this.replyCommentQuery).then(res => {
                    this.comments[index].replies = [
                        ...this.comments[index].replies,
                        ...res.data.data.filter(
                            (newItem) => !this.comments[index].replies.some((oldItem) => oldItem.id === newItem
                                .id)
                        ),
                    ];
                })
            },
            // 收起回复
            retractReplyComment(index) {
                this.comments[index].expandReply = false;
                this.comments[index].replies = [];
            },
            // 加载回复
            loadRepliesPage(comment, index) {
                this.replyCommentQuery.pageNumber = 1;
                this.replyCommentQuery.masterCommentId = comment.id
                getVideoComments(this.replyCommentQuery).then(res => {
                    this.comments[index].replies = res.data.data;
                    this.comments[index].expandReply = true;
                })
            },
            resetCommentForm() {
                const videoId = this.commentForm.videoId;
                this.commentForm = { // 评论表单数据
                    id: '',
                    videoId: videoId,
                    commentContent: '',
                    replyId: '',
                    replyUserId: '',
                    replyUserNickname: '',
                    replyUserAvatar: '',
                    masterCommentId: null
                }
            },
            // 取消回复
            cancelReply() {
                this.resetCommentForm()
            },
            // 打开回复框
            openReply(comment, reply = null) {
                if (reply) {
                    comment = reply
                }
                this.commentForm.masterCommentId = comment.masterCommentId ? comment.masterCommentId : comment.id;
                this.commentForm.replyId = comment.id;
                this.commentForm.replyUserId = comment.userId;
                this.commentForm.replyUserNickname = comment.userNickname;
                this.commentForm.replyUserAvatar = comment.userAvatar;
                // 自动聚焦输入框
                this.$nextTick(() => {
                    const input = this.$refs.commentInput;
                    if (input) input.focus();
                });
            },
            // 进度条时间格式化 (00:00)
            sliderFormatTime(seconds) {
                const mins = Math.floor(seconds / 60);
                const secs = Math.floor(seconds % 60);
                return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
            },
            // 格式化时间
            formatTime(time) {
                const date = new Date(time);
                const now = new Date();
                const diff = Math.floor((now - date) / 1000); // 秒
                if (diff < 60) return '刚刚';
                if (diff < 3600) return `${Math.floor(diff / 60)}分钟前`;
                if (diff < 86400) return `${Math.floor(diff / 3600)}小时前`;
                return `${date.getMonth() + 1}月${date.getDate()}日`;
            },
            // 提交评论
            async submitComment() {
                if (!this.commentForm.commentContent.trim()) {
                    uni.showToast({
                        title: '评论内容不能为空',
                        icon: 'none'
                    });
                    return;
                }
                // 发表评论
                addVideoComment(this.commentForm).then(res => {
                    if (res.data.code === 200) {
                        this.resetCommentForm()
                        // 如果是评论别人的回复,那么就将这个发布到replies里面
                        if (res.data.data.replyId) {
                            for (const [index, item] of this.comments.entries()) {
                                if (item.id === res.data.data.replyId) {
                                    item.replies.unshift(res.data.data);
                                    // this.loadRepliesPage(item, index)
                                    break; // 跳出循环
                                }
                            }
                        } else {
                            this.comments.unshift(res.data.data);
                        }
                        console.log("新增后", this.comments);
                        uni.showToast({
                            title: '评论成功'
                        });
                        // 当前视频评论数加一
                        this.commentsTotal += 1;
                        this.videoList[this.currentIndex].commentNum += 1;
                    } else {
                        uni.showToast({
                            title: res.data.msg,
                            icon: 'none'
                        });
                    }
                }).catch(() => {
                    uni.showToast({
                        title: '评论失败',
                        icon: 'none'
                    });
                })
            },
            // 关闭评论弹窗
            closeCommentPopup() {
                this.$refs.commentPopup.close()
                this.showCommentPopup = false;
                this.comments = [];
                this.resetCommentForm()
                this.commentQuery.pageNumber = 1;
                this.commentNoMore = false;
            },
            // 下滑评论区加载评论
            async getCommentPage() {
                if (this.commentNoMore) {
                    return;
                }
                getVideoComments(this.commentQuery).then(res => {
                    if (this.commentQuery.pageNumber === 1) {
                        this.comments = res.data.data
                    } else {
                        this.comments = [
                            ...this.comments,
                            ...res.data.data.filter(
                                (newItem) => !this.comments.some((oldItem) => oldItem.id === newItem.id)
                            ),
                        ];
                    }
                    if (res.data.data.length < this.commentQuery.pageSize) {
                        this.commentNoMore = true;
                        return;
                    }
                    this.commentQuery.pageNumber++;
                })
            },
            // 显示评论弹窗
            async showComments(item) {
                this.commentForm.videoId = item.id;
                this.$refs.commentPopup.open();
                this.commentLoading = true;
                this.commentQuery.videoId = item.id
                this.replyCommentQuery.videoId = item.id
                // 首次加载评论分页大小增加一倍,以产生滚动条,后续可触发
                this.commentQuery.pageSize *= 2;
                getVideoComments(this.commentQuery).then(res => {
                    this.commentsTotal = res.data.total;
                    this.comments = res.data.data;
                    this.commentQuery.pageNumber += 2;
                    this.commentQuery.pageSize /= 2;
                }).catch(() => {
                    uni.showToast({
                        title: '获取评论失败',
                        icon: 'none'
                    });
                }).finally(() => {
                    this.commentLoading = false;
                })
            },
            // 关注作者
            subscribeAuth(index, authorId) {
                this.videoList.forEach(video => {
                    if (video.authorId === authorId) {
                        video.subscribeThisAuthor = true
                    }
                })
                subscribe(authorId).then(res => {
                    if (res.data.code === 200) {
                        uni.showToast({
                            title: '关注成功~',
                            icon: 'none'
                        });
                    } else {
                        this.videoList.forEach(video => {
                            if (video.authorId === authorId) {
                                video.subscribeThisAuthor = false
                            }
                        })
                    }
                })
            },
            // 初始化视频上下文
            initVideoContexts() {
                this.videoContexts = this.videoList.map((_, index) => {
                    let videoContent = uni.createVideoContext(`video${index}`, this);
                    return videoContent;
                });
            },
            // 加载视频数据
            async loadVideos() {
                console.log(this.loading, this.videoNoMore,this.videoQuery)
                if (this.videoQuery.pageNumber == 1) {
                } else if (this.loading || this.videoNoMore) return;
                this.loading = true;
                getkitchenVideoList(this.videoQuery).then(res => {
                    console.log(res, "视频数据");
                    if (this.videoQuery.pageNumber === 1) {
                        this.videoList = res.data.data;
                    } else {
                        this.videoList = [
                            ...this.videoList,
                            ...res.data.data.filter(
                                (newItem) => !this.videoList.some((oldItem) => oldItem.id === newItem.id)
                            ),
                        ];
                    }
                    this.$nextTick(() => {
                        this.initVideoContexts();
                    });
                    this.loading = false;
                    if (res.data.data.length < this.videoQuery.pageSize) {
                        this.videoNoMore = true;
                        return;
                    }
                    this.videoQuery.pageNumber++;
                })
            },
            // 滑动切换视频
            onSwiperChange(e) {
                // 如果视频处于暂停状态往下刷视频,那么需要再计算一次暂停时间
                if (!this.currentVideoIsPlaying) {
                    if (this.startPauseTime !== 0) {
                        const duration = Date.now() - this.startPauseTime
                        this.totalPauseTime += duration
                    }
                }
                // 保存上一个视频的播放记录
                this.savePlayRecord()
                const oldIndex = this.currentIndex;
                this.currentIndex = e.detail.current;
                // 暂停上一个视频
                if (this.videoContexts[oldIndex]) {
                    this.videoContexts[oldIndex].pause();
                }
                this.startPauseTime = 0;
                // 播放当前视频
                if (this.videoContexts[this.currentIndex]) {
                    this.videoContexts[this.currentIndex].play();
                }
            },
            // 收藏/取消收藏
            toggleCollect(item, index) {
                let data = {
                    refId: item.id,
                    collectType: 'video'
                }
                const beforeCollected = item.collected
                const beforeCollectNum = item.collectNum
                if (item.collected) {
                    this.videoList[index].collected = false
                    this.videoList[index].collectNum -= 1
                } else {
                    this.videoList[index].collected = true
                    this.videoList[index].collectNum += 1
                }
                changeCollect(data).then(res => {
                    if (res.data.code !== 200) {
                        this.videoList[index].collected = beforeCollected
                        this.videoList[index].collectNum = beforeCollectNum
                    }
                })
            },
            // 单击屏幕:暂停或继续播放
            togglePlay(index) {
                console.log("单击视频", index, this.videoContexts);
                if (this.currentVideoIsPlaying) {
                    this.videoContexts[index].pause();
                } else {
                    this.videoContexts[index].play();
                }
            },
            // 视频播放事件
            onPlay(id, index) {
                this.getBarRect()
                this.progress = 0
                console.log(id, index, "触发播放");
                if (index === this.currentIndex) {
                    this.currentVideoIsPlaying = true;
                } else {
                    this.currentVideoIsPlaying = false;
                    return
                }
                this.playRecord.videoId = id;
                // 没初始化才赋值,因为一个视频重复播放onPlay会重复触发
                if (this.playRecord.startPlayTime === 0) {
                    this.playRecord.startPlayTime = Date.now();
                }
                if (this.startPauseTime !== 0) {
                    const duration = Date.now() - this.startPauseTime
                    this.totalPauseTime += duration
                }
            },
            // 视频暂停事件
            onPause(index) {
                console.log(index, "触发暂停");
                if (index === this.currentIndex) {
                    this.currentVideoIsPlaying = false;
                } else {
                    this.currentVideoIsPlaying = true;
                    return
                }
                this.startPauseTime = Date.now()
            },
            // 视频结束事件
            onEnded(index) {
                // this.currentVideoIsPlaying = false;
            },
            // 记录播放时长
            onTimeUpdate(e) {
                this.playRecord.playAt = e.detail.currentTime;
                this.currentTime = e.detail.currentTime;
                this.progress = (e.detail.currentTime / this.duration) * 100
            },
            // 触摸开始
            handleTouchStart(e) {
                this.isDragging = true;
                this.showProcess = true;
                this.startProgress = this.progress; // 记录开始时的进度
                this.startX = e.touches[0].pageX;
                console.log("记录开始时的进度", this.startProgress);
                this.videoContexts[this.currentIndex].pause()
                // this.updateProgress(e);
            },
            // 触摸移动
            handleTouchMove(e) {
                if (!this.isDragging || !this.barWidth) return;
                clearTimeout(this.processHidenTimer)
                this.videoContexts[this.currentIndex].pause()
                this.updateProgress(e);
            },
            // 触摸结束
            handleTouchEnd() {
                this.isDragging = false;
                console.log("滑动结束", this.duration * this.progress);
                this.videoContexts[this.currentIndex].seek(this.duration * this.progress / 100)
                this.videoContexts[this.currentIndex].play()
                this.processHidenTimer = setTimeout(() => {
                    this.showProcess = false;
                }, 1000);
            },
            // 更新进度
            updateProgress(e) {
                // 获取当前触摸点X坐标
                const currentX = e.touches[0].pageX;
                // 计算滑动距离(像素)
                const deltaX = currentX - this.startX;
                // 将像素距离转换为进度增量
                const deltaProgress = (deltaX / this.barWidth) * 100;
                console.log("进度增量", deltaProgress);
                // 计算新进度 = 开始时的进度 + 滑动增量
                let newProgress = this.startProgress + deltaProgress;
                // 限制范围在0-100之间
                newProgress = Math.max(0, Math.min(100, newProgress));
                this.progress = newProgress;
            },
            // 获取视频总时长
            onLoadedMetadata(e) {
                this.duration = e.detail.duration;
                this.formartDuration.push(this.sliderFormatTime(this.duration));
                console.log("视频总时长", this.duration);
            },
            // 保存播放记录
            async savePlayRecord() {
                console.log(Date.now(), this.playRecord.startPlayTime, this.totalHidenTime);
                const data = {
                    videoId: this.playRecord.videoId,
                    viewDuration: Date.now() - this.playRecord.startPlayTime - this.totalHidenTime - this
                        .totalPauseTime,
                    playAt: this.playRecord.playAt
                }
                this.playRecord = {
                    videoId: null,
                    viewDuration: 0, // 这个视频总共观看了多久
                    playAt: 0, // 这个视频播放到哪了
                    startPlayTime: 0 // 这个视频从什么时候开始播放的
                }
                this.totalHidenTime = 0
                this.totalPauseTime = 0
                savePlayRecord(data)
            }
        }
    }
</script>
<style scoped>
    ::v-deep .custom-tabbar {
        border-top: none !important;
    }
    .video-container {
        position: relative;
        width: 100%;
        height: 100vh;
        background-color: #000;
    }
    .showLeft {
        display: flex;
        top: 50rpx;
        left: 0;
        align-items: center;
        justify-content: flex-start;
        background-color: #b6b6b6;
        opacity: 0.8;
        position: fixed;
        z-index: 999;
        height: 70rpx;
        width: 50rpx;
        border-radius: 0 50% 50% 0;
    }
    .video-swiper {
        width: 100%;
        height: calc(100% - 50px);
    }
    .video-item {
        width: 100%;
        height: 100%;
        object-fit: cover;
    }
    .play-icon {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 45px;
        height: 45px;
        z-index: 10;
        opacity: 0.6;
    }
    .video-info {
        width: 70%;
        position: absolute;
        bottom: 70px;
        left: 20px;
        color: #f8f8f8;
        z-index: 10;
        letter-spacing: 1px;
    }
    .action-buttons {
        position: absolute;
        right: 20px;
        bottom: 150px;
        display: flex;
        flex-direction: column;
        align-items: center;
        z-index: 10;
    }
    .action-item {
        margin-bottom: 18px;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        color: #fff;
    }
    .avatar-container {
        margin-bottom: 27px;
        position: relative;
        /* 为绝对定位的子元素提供定位上下文 */
        width: 40px;
        height: 40px;
        display: inline-block;
        /* 使容器根据内容调整大小 */
    }
    .avatar {
        border: 2px solid #FFFFFF;
        box-sizing: border-box;
        width: 100%;
        height: 100%;
        border-radius: 50%;
        /* 关键属性,设置为50%即可实现圆形 */
        overflow: hidden;
        /* 确保图片不会超出圆形边界 */
        display: block;
    }
    .follow-icon {
        position: absolute;
        bottom: 0;
        /* 定位到底部 */
        left: 50%;
        /* 水平居中开始位置 */
        transform: translate(-50%, 50%);
        /* 水平居中并向下移动50% */
        width: 18px;
        /* 图标大小 */
        height: 18px;
        background-color: #FF5A5F;
        /* 图标背景色 */
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        /* 轻微阴影 */
    }
    .video-tag {
        margin-left: 5px;
        font-weight: bold;
        color: #eeeeee;
    }
    .video-author {
        font-size: 1.2em;
    }
    /* 商品链接悬挂层样式 */
    .goods-link-warp {
        position: absolute;
        bottom: 160px;
        left: 20px;
        color: #f8f8f8;
        z-index: 10;
    }
    .goods-link {
        position: relative;
        margin: 20rpx 0;
        padding: 12rpx;
        background-color: rgba(255, 255, 255, 0.9);
        border-radius: 12rpx;
        box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
    }
    .goods-container {
        display: flex;
        align-items: center;
    }
    .goods-image {
        width: 120rpx;
        height: 120rpx;
        border-radius: 8rpx;
        margin-right: 20rpx;
    }
    .goods-info {
        flex: 1;
        display: flex;
        flex-direction: column;
        justify-content: center;
    }
    .goods-name {
        font-size: 28rpx;
        color: #333;
        font-weight: bold;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
        margin-bottom: 8rpx;
    }
    .price-section {
        display: flex;
        align-items: center;
        margin-bottom: 6rpx;
    }
    .current-price {
        font-size: 32rpx;
        color: #ff2e4d;
        font-weight: bold;
        margin-right: 12rpx;
    }
    .original-price {
        font-size: 28rpx;
        color: #999;
        text-decoration: line-through;
    }
    .sales-count {
        font-size: 22rpx;
        color: #999;
    }
    .buy-button {
        background: linear-gradient(to right, #ff5a5f, #ff2e4d);
        color: white;
        padding: 10rpx 28rpx;
        border-radius: 20rpx;
        font-size: 26rpx;
        font-weight: bold;
    }
    /* 评论弹窗样式 */
    .comment-popup {
        background-color: #fff;
        border-radius: 20rpx 20rpx 0 0;
        padding-bottom: env(safe-area-inset-bottom);
        height: 60vh;
        display: flex;
        flex-direction: column;
    }
    .popup-header {
        padding: 30rpx;
        display: flex;
        justify-content: space-between;
        align-items: center;
        border-bottom: 1rpx solid #f5f5f5;
    }
    .popup-title {
        font-size: 32rpx;
        font-weight: bold;
    }
    .close-icon {
        /* font-size: 36rpx; */
        color: #999;
    }
    .comment-list {
        flex: 1;
        padding: 0rpx 20rpx 20rpx 20rpx;
        box-sizing: border-box;
        height: calc(60vh - 260rpx);
    }
    .comment-item {
        display: flex;
        flex-direction: column;
        padding: 10rpx 0 20rpx 0;
    }
    .comment-avatar {
        width: 70rpx;
        height: 70rpx;
        border-radius: 50%;
        margin-right: 10rpx;
    }
    .comment-reply-avatar {
        width: 40rpx;
        height: 40rpx;
        border-radius: 50%;
        margin-right: 10rpx;
    }
    .comment-content {
        flex: 1;
    }
    .nickname {
        font-size: 28rpx;
        color: #666;
        display: block;
        margin-bottom: 10rpx;
    }
    .content {
        font-size: 28rpx;
        color: #333;
        display: block;
        margin-bottom: 10rpx;
    }
    .time {
        font-size: 28rpx;
        color: #999;
    }
    .comment-input-area {
        display: flex;
        padding: 20rpx 30rpx;
        align-items: center;
    }
    .comment-input {
        flex: 1;
        background-color: #fff;
        height: 80rpx;
        border: 1px solid #dcdcdc;
        border-radius: 40rpx;
        padding: 0 30rpx;
        font-size: 28rpx;
    }
    .placeholder {
        color: #ccc;
    }
    .submit-btn {
        margin-left: 20rpx;
        background-color: #07c160;
        color: #fff;
        border-radius: 40rpx;
        padding: 0 30rpx;
        height: 80rpx;
        line-height: 80rpx;
        font-size: 28rpx;
    }
    .loading,
    .empty {
        padding: 40rpx 0;
        text-align: center;
        color: #999;
    }
    .reply-list {
        margin-top: 20rpx;
        padding-left: 80rpx;
    }
    .reply-op {
        margin-top: 10rpx;
        padding-left: 80rpx;
        display: flex;
        font-size: 28rpx;
        color: #333;
    }
    .reply-op-item {
        display: flex;
        align-items: center;
        height: 40rpx;
    }
    .reply-item {
        display: flex;
        margin-bottom: 20rpx;
    }
    .reply-content {
        flex: 1;
    }
    .reply-to {
        color: #576b95;
        margin: 0 10rpx;
        font-size: 28rpx;
    }
    .reply-title {
        display: flex;
        align-items: center;
        font-size: 28rpx;
        color: #333;
    }
    .cancel-reply {
        margin-left: 20rpx;
        color: #576b95;
        font-size: 28rpx;
        padding: 6rpx 12rpx;
        background: #f5f5f5;
        border-radius: 20rpx;
    }
    .view-more-replies {
        color: #576b95;
        font-size: 28rpx;
        padding: 10rpx 0;
        padding-left: 80rpx;
    }
    .comment-footer,
    .reply-footer {
        display: flex;
        align-items: center;
        font-size: 28rpx;
        color: #999;
    }
    .reply-btu {
        margin-left: 30rpx;
    }
    .thumbs-up {
        position: absolute;
        right: 20rpx;
        font-size: 32rpx;
        width: 120rpx;
    }
    .textSideIcon {
        font-size: 36rpx;
        margin-left: 5rpx;
    }
    .line {
        margin-right: 10rpx;
        color: #cccccc;
    }
    .thumbs-num {
        margin-left: 4rpx;
    }
    .container {
        display: flex;
        flex-direction: column;
        align-items: center;
        position: absolute;
        bottom: 0;
        width: 100%;
    }
    .progress-bar {
        position: relative;
        width: 100%;
        height: 16px;
        background-color: #eee;
        overflow: hidden;
    }
    .progress-fill {
        position: absolute;
        left: 0;
        top: 0;
        height: 100%;
        background-color: lightgray;
        transition: width 0.1s;
    }
    .process-warp {
        width: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
    }
    .progress-text {
        margin-top: 10px;
        font-size: 14px;
        color: #666;
    }
    .swiper-box {
        width: 100%;
        height: 1400rpx;
    }
    .swiper-item {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
    }
    .currentCategort {
        padding: 10rpx;
    }
    .typeNavigation {
        height: 100%;
        padding: 10rpx;
        box-sizing: border-box;
    }
    .typeNavigationItem {
        padding: 24rpx;
        font-size: 28rpx;
        color: black;
        margin-top: 10rpx;
        border-radius: 12rpx;
        border: 1rpx solid gray;
    }
    .typeNavigationItemCheck {
        background-color: #42b993;
        color: #fff;
        border: 0;
    }
    .container ::v-deep .navigationLeft .uni-drawer__content {
        height: 300rpx !important;
        top: 100rpx !important;
        background-color: lightpink !important;
    }
</style>
pages/mine/deposit/operation.vue
@@ -5,7 +5,8 @@
      <div class="deposit">预存款金额</div>
      <div class="money">¥{{walletNum | unitPrice }}</div>
      <div class="operation-btns">
        <div class="operation-btn light" @click="navigateTo('/pages/mine/deposit/withdrawal')">提现</div>
          <!-- 移除提现按钮 -->
        <div v-if="false" class="operation-btn light" @click="navigateTo('/pages/mine/deposit/withdrawal')">提现</div>
        <div class="operation-btn" @click="navigateTo('/pages/mine/deposit/recharge')">充值</div>
      </div>
    </div>
@@ -37,6 +38,7 @@
  },
  methods: {
    back() {
        console.log("触犯返回页面")
      uni.switchTab({
        url: "/pages/tabbar/user/my",
      });
pages/order/fillorder.vue
@@ -705,16 +705,17 @@
                url: "/pages/order/myOrder?status=0",
              });
            } else {
              // #ifdef MP-WEIXIN
              // 微信小程序中点击创建订单直接开始支付
              this.pay(res.data.result.sn);
              // #endif
                //注释掉直接调取微信支付 走收银台支付
              // // #ifdef MP-WEIXIN
              // // 微信小程序中点击创建订单直接开始支付
              // this.pay(res.data.result.sn);
              // // #endif
              // #ifndef MP-WEIXIN
            //  // #ifndef MP-WEIXIN
              this.navigateTo(
                `/pages/cart/payment/payOrder?trade_sn=${res.data.result.sn}`
              );
              // #endif
            //  // #endif
            }
          } else {
            uni.showToast({
pages/tabbar/index/home.vue
@@ -1,20 +1,26 @@
<template>
  <view class="video-container">
    <!-- 视频列表 -->
    <swiper
      class="video-swiper"
      vertical
      circular
    <swiper
      class="video-swiper"
      vertical
      :current="currentIndex"
      @change="onSwiperChange"
      easing-function="linear"
    >
      <swiper-item v-for="(item, index) in videoList" :key="item.id">
      <swiper-item
        v-for="(item, index) in videoList"
        :key="item.id"
        @touchstart="handleSwiperStart"
        @touchmove="handleSwiperMove"
        @touchend="handleSwiperEnd(item)"
         >
        <view style="width: 100%;height: 100%;" v-if="item.videoContentType === 'video'">
              <!-- 播放按钮(仅当视频暂停时显示) -->
              <view
                class="play-icon"
              <view
                class="play-icon"
                @click="togglePlay(index)"
                v-if="!currentVideoIsPlaying"
                v-show="!currentVideoIsPlaying"
              >
                <image src="/static/video/play.png" style="width: 45px;height: 45px" mode="aspectFit"></image>
              </view>
@@ -22,7 +28,7 @@
                :id="'video'+index"
                :ref="'video'+index"
                :src="item.videoUrl"
                :autoplay="currentIndex === index"
                :autoplay="false"
                :controls="false"
                :loop="true"
                :object-fit="item.objectFit"
@@ -34,10 +40,9 @@
                @click="togglePlay(index)"
                @timeupdate="onTimeUpdate($event)"
                @loadedmetadata="onLoadedMetadata($event)"
              ></video>
              <!-- 自定义控制条 -->
              <view
              <view
                @touchstart="handleTouchStart"
                @touchmove="handleTouchMove"
                @touchend="handleTouchEnd"
@@ -46,11 +51,11 @@
                <view class="process-warp" :style="{ opacity: showProcess ? 1 : 0 }">
                  <!-- 显示当前进度 -->
                  <view class="progress-text">{{ hasPlayTime }}/{{formartDuration}}</view>
                  <view
                    class="progress-bar"
                  <view
                    class="progress-bar"
                    id="progressBar"
                  >
                    <!-- 已填充部分 -->
                    <view class="progress-fill" :style="{ width: progress + '%' }"></view>
                  </view>
@@ -58,10 +63,10 @@
              </view>
        </view>
        <view style="width: 100%; height: 100%;" v-else-if="item.videoContentType === 'img'">
          <uni-swiper-dot
            :info="item.imgs"
            :current="currentImgIndex"
            mode="round"
          <uni-swiper-dot
            :info="item.imgs"
            :current="currentImgIndex"
            mode="round"
            style="width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;"
            :dots-styles="{width: 24, bottom: 24,selectedBackgroundColor: 'green', backgroundColor: 'gray'}"
            >
@@ -69,9 +74,9 @@
              <swiper-item v-for="img in item.imgs" :key="img">
                <view class="swiper-item">
                  <!-- 调整 image 样式,使其居中且按比例缩放 -->
                  <image
                    :src="img"
                    mode="aspectFit"
                  <image
                    :src="img"
                    mode="aspectFit"
                    style="width: 100%; height: 100%; display: block; margin: 0 auto;"
                  ></image>
                </view>
@@ -79,8 +84,8 @@
            </swiper>
          </uni-swiper-dot>
        </view>
        <!-- 悬挂商品链接层 -->
        <view class="goods-link-warp" v-if="item.goodsList.length > 0">
            <view class="goods-link">
@@ -89,7 +94,7 @@
                  <view class="goods-container" @click="jumpToPay(item.id)">
                    <!-- 商品图片 -->
                    <image class="goods-image" :src="goods.thumbnail" mode="aspectFill"></image>
                    <!-- 商品信息 -->
                    <view class="goods-info">
                      <text class="goods-name">{{goods.goodsName}}</text>
@@ -103,8 +108,8 @@
              </swiper>
            </view>
        </view>
        <!-- 视频信息层 -->
        <view class="video-info">
          <view>
@@ -115,7 +120,7 @@
              <text class="video-tag" v-for="(tag, index) in item.tagList" :key="tag.id">#{{tag.tagName}}</text>
          </view>
        </view>
        <!-- 右侧互动按钮 -->
       <view class="action-buttons">
           <view class="avatar-container">
@@ -138,13 +143,13 @@
              <button open-type="share" class="custom-share-btn" :data-obj="item">
                    <text class="iconfont">&#xe602;</text>
                  </button>
          </view>
        </view>
      </swiper-item>
    </swiper>
    <!-- 评论弹窗 -->
    <uni-popup ref="commentPopup" type="bottom" :is-mask-click="true" @maskClick="closeCommentPopup">
      <view class="comment-popup">
@@ -156,23 +161,23 @@
          </view>
          <text class="iconfont close-icon" @click="closeCommentPopup">&#xe675;</text>
        </view>
        <scroll-view class="comment-list" scroll-y :show-scrollbar="false" @scrolltolower="getCommentPage">
          <view v-if="commentLoading" class="loading">
            <uni-load-more status="loading"></uni-load-more>
          </view>
          <view v-else-if="comments.length === 0" class="empty">
            暂无评论,快来发表第一条评论吧~
          </view>
          <view v-else class="comment-item" v-for="(comment, index) in comments" :key="comment.id">
            <view style="display: flex;">
                <image class="comment-avatar" :src="comment.userAvatar || '/static/default-avatar.png'"></image>
                <view class="comment-content">
                  <text class="nickname">{{comment.userNickname}}</text>
                  <text class="content">{{comment.commentContent}}</text>
                  <view style="position: relative;">
                  <view style="position: relative;">
                    <text class="time">{{formatTime(comment.createTime)}}</text>
                    <text @click="openReply(comment)" class="reply-btu time">回复</text>
                    <text v-if="!comment.hasThumbsUp" class="thumbs-up time iconfont" @click="thubmsUp(comment.id, index, null)">&#xe614;<text v-show="comment.thumbsUpNum > 0" class="thumbs-num">{{comment.thumbsUpNum}}</text></text>
@@ -212,19 +217,19 @@
          </view>
        </scroll-view>
        <view class="comment-input-area">
          <input
          <input
            ref="commentInput"
            class="comment-input"
            v-model="commentForm.commentContent"
            :placeholder="commentForm.replyId ? `回复 @${commentForm.replyUserNickname}` : '写下你的评论...'"
            class="comment-input"
            v-model="commentForm.commentContent"
            :placeholder="commentForm.replyId ? `回复 @${commentForm.replyUserNickname}` : '写下你的评论...'"
            placeholder-class="placeholder"
          />
          <button class="submit-btn" @click="submitComment" :disabled="!commentForm.commentContent.trim()">发送</button>
        </view>
      </view>
    </uni-popup>
    <custom-tabbar bgColor="#333333" selected="index" selectedTextColor="#ffffff"></custom-tabbar>
  </view>
</template>
@@ -298,14 +303,20 @@
        isFullScreen: false,
        windowHeight: 0,
        currentIndex: 0, // 当前播放的视频索引
        videoList: [
        ],   // 视频列表数据
        videoList: [],   // 视频列表数据
        videoContexts: [], // 视频上下文对象集合
        videoBufferOffset: 0.1 ,// 视频预加载参数
        videoLiveOffset: 5, // 保留当前视频前后各多少个视频上下文
        touchXY: {  // 监听左滑右滑
            startX: 0,
            endX: 0,
            startY: 0,
            endY: 0
        },
        loading: false,  // 是否正在加载
        videoQuery: {
            pageNumber: 1,
            pageSize: 6,
            pageSize: 10,
            videoFrom: 'recommend'
        }
    }
@@ -316,7 +327,7 @@
         //  this.wxSilentLogin(() => {
            //   this.loadVideos();
         //  })
      // } else {
      // } else {
      //       this.loadVideos();
      // }
      // 如果视频按下暂停后切换页面再回到页面时,只算暂停时间(因为暂停时间和离开页面时间是重复的,只算一个)
@@ -339,13 +350,9 @@
                  saveShareClickRecord({refId: option.videoId, shareUserId: option.userId})
              }
          })
      } else {
      } else {
        this.loadVideos();
      }
  },
  onReady() {
    // 初始化视频上下文
    this.initVideoContexts();
  },
  onShareAppMessage(e) {
    const userInfo = storage.getUserInfo();
@@ -525,11 +532,11 @@
          const date = new Date(time);
          const now = new Date();
          const diff = Math.floor((now - date) / 1000); // 秒
          if (diff < 60) return '刚刚';
          if (diff < 3600) return `${Math.floor(diff / 60)}分钟前`;
          if (diff < 86400) return `${Math.floor(diff / 3600)}小时前`;
          return `${date.getMonth() + 1}月${date.getDate()}日`;
        },
        // 提交评论
@@ -545,7 +552,7 @@
          addVideoComment(this.commentForm).then(res => {
              if(res.data.code === 200) {
                  this.resetCommentForm()
                  // 如果是评论别人的回复,那么就将这个发布到replies里面
                  if(res.data.data.replyId) {
                      for (const [index, item] of this.comments.entries()) {
@@ -657,17 +664,60 @@
      },
    // 初始化视频上下文
    initVideoContexts() {
      this.videoContexts = this.videoList.map((_, index) => {
          let videoContent = uni.createVideoContext(`video${index}`, this);
          return videoContent;
      });
      const start = Math.max(0, this.currentIndex - this.videoLiveOffset);
      const end = Math.min(this.currentIndex + this.videoLiveOffset, this.videoList.length - 1);
      let contextsLength = this.videoContexts.length;
      if (contextsLength === 0) {
          // 第一次初始化
          for (let i = 0; i < this.videoList.length; i++) {
            if (i < start || i > end) {
                this.videoContexts.push(null)
            } else {
                let videoContent = uni.createVideoContext(`video${i}`, this);
                videoContent.seek(this.videoBufferOffset);
                videoContent.pause();
                this.videoContexts.push(videoContent);
            }
          }
      } else {
         for (let i = 0; i < this.videoList.length; i++) {
             contextsLength = this.videoContexts.length
            if (contextsLength - 1 >= i) {
                // 如果已经是null了就不用管,因为视频加载只会在后面push,前面已经设置为null则无需处理
                if (this.videoContexts[i] == null) {
                    continue
                }
                // 超出可视化范围的视频直接释放资源,并置为null
                if (i < start || i > end) {
                    if (this.videoContexts[i]) {
                        this.videoContexts[i].stop();
                        this.videoContexts[i] = null
                    }
                }
            } else {
                if (i < start || i > end) {
                    this.videoContexts.push(null);
                } else {
                    let videoContent = uni.createVideoContext(`video${i}`, this);
                    videoContent.seek(this.videoBufferOffset);
                    videoContent.pause();
                    this.videoContexts.push(videoContent);
                }
            }
         }
      }
      // 将当前视频设置为播放
      if (this.videoContexts[this.currentIndex]) {
          this.videoContexts[this.currentIndex].play()
      }
    },
    // 加载视频数据
    async loadVideos() {
      if (this.loading || this.videoNoMore) return;
      this.loading = true;
      getRecommendVideos(this.videoQuery).then(res => {
          console.log(res, "视频数据");
          if (this.videoQuery.pageNumber === 1) {
@@ -689,10 +739,10 @@
              return;
          }
          this.videoQuery.pageNumber++;
      })
    },
    // 滑动切换视频
    onSwiperChange(e) {
        // 如果视频处于暂停状态往下刷视频,那么需要再计算一次暂停时间
@@ -711,17 +761,82 @@
        if (this.videoContexts[oldIndex]) {
            this.videoContexts[oldIndex].pause();
        }
        this.startPauseTime = 0;
        // 设置当前播放视频的总时长
        this.duration = this.videoList[this.currentIndex].videoDuration;
        this.formartDuration = this.sliderFormatTime(this.duration);
        // 播放当前视频
        if (this.videoContexts[this.currentIndex]) {
            this.videoContexts[this.currentIndex].play();
        }
        // 设置当前播放视频的总时长
        this.duration = this.videoList[this.currentIndex].videoDuration;
        this.formartDuration = this.sliderFormatTime(this.duration);
        this.clearVideoContext()
    },
    // 清除超出视频可视化区域的视频上下文
    async clearVideoContext() {
        // 对超出可视化区域的视频上下文做销毁处理
        const start = Math.max(0, this.currentIndex - this.videoLiveOffset);
        const end = Math.min(this.currentIndex + this.videoLiveOffset, this.videoList.length - 1);
        for (let i = 0; i < this.videoContexts.length; i++) {
            if (i < start || i > end) {
                if (this.videoContexts[i]) {
                    this.videoContexts[i].stop();
                    this.videoContexts[i] = null
                }
            } else {
                if (this.videoContexts[i] == null) {
                    let videoContent = uni.createVideoContext(`video${i}`, this);
                    videoContent.seek(this.videoBufferOffset);
                    videoContent.pause();
                    this.videoContexts[i] = videoContent;
                }
            }
        }
        // 如果剩余视频不足,触发请求获取更多视频
        if (this.videoList.length - 1 < this.currentIndex + this.videoLiveOffset) {
            this.loadVideos()
        }
    },
    // 开始触摸
    handleSwiperStart(e) {
        console.log("开始触摸", e);
        this.touchXY.startX = e.touches[0].pageX
        this.touchXY.startY = e.touches[0].pageY
    },
    // 触摸中
    handleSwiperMove(e) {
        console.log("触摸中", e);
        this.touchXY.endX = e.touches[0].pageX
        this.touchXY.endY = e.touches[0].pageY
    },
    // 结束触摸
    handleSwiperEnd(item) {
        const diffX = this.touchXY.endX - this.touchXY.startX
        const diffY = this.touchXY.endY - this.touchXY.startY
        // 判断是否是横向滑动(X轴变化大于Y轴变化)
        if (Math.abs(diffX) > Math.abs(diffY)) {
          if (diffX > 0) {
            console.log('右滑')
            if (item.goodsList && item.goodsList.length > 0) {
                this.jumpToPay(item.id)
            }
          } else {
            console.log('左滑')
          }
        }
        // 重置坐标
        this.touchXY = {
            startX: 0,
            endX: 0,
            startY: 0,
            endY: 0
        }
    },
    // 收藏/取消收藏
    toggleCollect(item, index) {
      let data = {
@@ -778,9 +893,9 @@
            const duration = Date.now() - this.startPauseTime
            this.totalPauseTime += duration
        }
    },
    // 视频暂停事件
    onPause(index) {
        console.log(index, "触发暂停");
@@ -796,11 +911,11 @@
    onEnded(index) {
      // this.currentVideoIsPlaying = false;
    },
    // 记录播放时长
    onTimeUpdate(e) {
        this.playRecord.playAt = e.detail.currentTime;
        this.currentTime = e.detail.currentTime;
        this.progress = (e.detail.currentTime / this.duration) * 100
    },
@@ -814,7 +929,7 @@
      this.videoContexts[this.currentIndex].pause()
      // this.updateProgress(e);
    },
    // 触摸移动
    handleTouchMove(e) {
      if (!this.isDragging || !this.barWidth) return;
@@ -822,7 +937,7 @@
      this.videoContexts[this.currentIndex].pause()
      this.updateProgress(e);
    },
    // 触摸结束
    handleTouchEnd() {
      this.isDragging = false;
@@ -833,24 +948,24 @@
          this.showProcess = false;
        }, 1000);
    },
    // 更新进度
    updateProgress(e) {
        // 获取当前触摸点X坐标
        const currentX = e.touches[0].pageX;
        // 计算滑动距离(像素)
        const deltaX = currentX - this.startX;
        // 将像素距离转换为进度增量
        const deltaProgress = (deltaX / this.barWidth) * 100;
        console.log("进度增量", deltaProgress);
        // 计算新进度 = 开始时的进度 + 滑动增量
        let newProgress = this.startProgress + deltaProgress;
        // 限制范围在0-100之间
        newProgress = Math.max(0, Math.min(100, newProgress));
        this.progress = newProgress;
    },
    // 获取视频总时长
@@ -862,7 +977,7 @@
    // 保存播放记录
    async savePlayRecord() {
        console.log(Date.now(), this.playRecord.startPlayTime, this.totalHidenTime);
        const data = {
            videoId: this.playRecord.videoId,
            viewDuration: Date.now() - this.playRecord.startPlayTime - this.totalHidenTime - this.totalPauseTime,
@@ -891,12 +1006,12 @@
      height: 100vh;
      background-color: #000;
    }
    .video-swiper {
      width: 100%;
      height: calc(100% - 50px);
    }
    .video-item {
      width: 100%;
      height: 100%;
@@ -912,7 +1027,7 @@
      z-index: 10;
      opacity: 0.6;
    }
    .video-info {
      width: 70%;
      position: absolute;
@@ -922,7 +1037,7 @@
      z-index: 10;
      letter-spacing: 1px;
    }
    .action-buttons {
      position: absolute;
      right: 20px;
@@ -932,7 +1047,7 @@
      align-items: center;
      z-index: 10;
    }
    .action-item {
      margin-bottom: 18px;
      display: flex;
@@ -962,7 +1077,7 @@
      bottom: 0;  /* 定位到底部 */
      left: 50%;  /* 水平居中开始位置 */
      transform: translate(-50%, 50%); /* 水平居中并向下移动50% */
      width: 18px;  /* 图标大小 */
      height: 18px;
      background-color: #FF5A5F; /* 图标背景色 */
@@ -997,27 +1112,27 @@
      border-radius: 12rpx;
      box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
    }
    .goods-container {
      width: 100%;
      display: flex;
      align-items: center;
    }
    .goods-image {
      width: 120rpx;
      height: 120rpx;
      border-radius: 8rpx;
      margin-right: 20rpx;
    }
    .goods-info {
      flex: 1;
      display: flex;
      flex-direction: column;
      justify-content: center;
    }
    .goods-name {
      font-size: 28rpx;
      color: #333;
@@ -1030,31 +1145,31 @@
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    .price-section {
      display: flex;
      align-items: center;
      margin-bottom: 6rpx;
    }
    .current-price {
      font-size: 32rpx;
      color: #ff2e4d;
      font-weight: bold;
      margin-right: 12rpx;
    }
    .original-price {
      font-size: 28rpx;
      color: #999;
      text-decoration: line-through;
    }
    .sales-count {
      font-size: 22rpx;
      color: #999;
    }
    .buy-button {
      background: linear-gradient(to right, #ff5a5f, #ff2e4d);
      color: white;
@@ -1192,16 +1307,16 @@
        align-items: center;
        height: 40rpx;
    }
    .reply-item {
      display: flex;
      margin-bottom: 20rpx;
    }
    .reply-content {
      flex: 1;
    }
    .reply-to {
      color: #576b95;
      margin: 0 10rpx;
@@ -1213,7 +1328,7 @@
      font-size: 28rpx;
      color: #333;
    }
    .cancel-reply {
      margin-left: 20rpx;
      color: #576b95;
@@ -1262,7 +1377,7 @@
      bottom: 0;
      width: 100%;
    }
    .progress-bar {
      position: relative;
      width: 100%;
@@ -1270,7 +1385,7 @@
      background-color: #eee;
      overflow: hidden;
    }
    .progress-fill {
      position: absolute;
      left: 0;
@@ -1312,4 +1427,4 @@
    .custom-share-btn::after {
      border: none;
    }
</style>
</style>
uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue
@@ -1,7 +1,7 @@
<template>
    <view v-if="visibleSync" :class="{ 'uni-drawer--visible': showDrawer }" class="uni-drawer" @touchmove.stop.prevent="clear">
        <view class="uni-drawer__mask" :class="{ 'uni-drawer__mask--visible': showDrawer && mask }" @tap="close('mask')" />
        <view class="uni-drawer__content" :class="{'uni-drawer--right': rightMode,'uni-drawer--left': !rightMode, 'uni-drawer__content--visible': showDrawer}" :style="{width:drawerWidth+'px'}">
        <view class="uni-drawer__content" :class="{'uni-drawer--right': rightMode,'uni-drawer--left': !rightMode, 'uni-drawer__content--visible': showDrawer,'custom-style':cusStyle}" :style="{width:drawerWidth+'px',maxHeight:drawerHeight}">
            <slot />
        </view>
        <!-- #ifdef H5 -->
@@ -62,6 +62,20 @@
            width: {
                type: Number,
                default: 220
            },
            /**
             * 抽屉高度
             */
            height: {
                type: String,
                default: '100vh'
            },
            /**
             * 抽屉高度
             */
            cusStyle: {
                type: Boolean,
                default: false
            }
        },
        data() {
@@ -70,12 +84,15 @@
                showDrawer: false,
                rightMode: false,
                watchTimer: null,
                drawerWidth: 220
                drawerWidth: 220,
                drawerHeight: null,
            }
        },
        created() {
            // #ifndef APP-NVUE
            this.drawerWidth = this.width
            this.drawerHeight = this.height
            console.log("执行了",this.drawerHeight,this.height)
            // #endif
            this.rightMode = this.mode === 'right'
        },
@@ -133,6 +150,10 @@
        bottom: 0;
        background-color: $uni-bg-color;
        transition: transform 0.3s ease;
        overflow-y: auto;
    }
    .custom-style{
        border-radius: 0 24rpx 24rpx 0;
    }
    .uni-drawer--left {