vue3+uniapp实现PDF指定路径下载并自动打开预览

接上篇
用户反馈找不到文件储存位置,需要指定路径下载


image.png

更新js:

<script setup lang="ts">

    const loadData = async () => {
        try {
            loading.value.open('加载中...');
            const res = await getPrint(paramsData.value)

            if (res.Code === '2000') {
                const parsedData = JSON.parse(res.Data)
                const data = Object.freeze(JSON.parse(parsedData.Data)) // 冻结原始数据
                if (data === null || data?.pics.length === 0) {
                    loading.value.close();
                    return uni.showToast({
                        title: '暂无凭证',
                        icon: 'none'
                    });
                }
                responseData.pics = [...data.pics] // 仅复制需要响应式的数据
                responseData.MajorName = data.MajorName

                // 优化图片加载性能
                const fullUrls = data.pics.map(item => 'http://' + configStore.curServiceIp + ':8999/' + item)
                const frozenUrls = Object.freeze(fullUrls) // 冻结URL数组
                // 预加载图片
                preloadImages(frozenUrls)
                    .then(() => {
            loading.value.close();
            console.log('所有图片加载完成')
          })
                    .catch(err => {
            loading.value.close();
            console.error('加载失败的图片:', err)
          });
                // preloadImages(frozenUrls)

                // 清空后设置新数据,确保占位图被完全替换
                swiperList.value = []
                nextTick(() => {
                    swiperList.value = [...frozenUrls]
                })

                
            } else {
                loading.value.close();
                uni.showToast({
                    title: res.Message || '加载失败',
                    icon: 'none'
                });
            }
        } catch (error) {
            loading.value.close();
            uni.showToast({
                title: '加载出错: ' + error.message,
                icon: 'none'
            });
            console.error('loadData error:', error);
        }
    }
    function preloadImages(urls : string[]) : Promise<void[]> {
        return Promise.all<void>(
            urls.map(url => {
                return new Promise<void>((resolve) => {
                    uni.downloadFile({
                        url: url,
                        success: () => resolve(),
                        fail: () => resolve(), // 继续流程不中断
                        complete: () => { } // 确保不会抛出异常
                    });
                });
            })
        );
    }
    async function handleSubmit() {
        const url = 'http://' + configStore.curServiceIp + ':8999/' + responseData.MajorName
        console.log('url', url);
        const fileName = url.split('/').pop()
        loading.value.open('保存中...');
        // 动态申请权限
        plus.android.requestPermissions(
            ['android.permission.WRITE_EXTERNAL_STORAGE'],
            () => {
                // 下载文件到Download目录
                let dtask = plus.downloader.createDownload(
                    url,
                    { filename: `file://storage/emulated/0/Download/${fileName}` },
                    (d, status) => {
                        if (status === 200) {
                            loading.value.close();
                            uni.showModal({
                                title: '系统提示',
                                content: "文件下载成功并保存到(手机内部存储:【Download】 文件夹),请注意查看!",
                                showCancel: false
                            })
                            setTimeout(() => {
                                // 打开下载的文件
                                uni.openDocument({
                                    filePath: `file://storage/emulated/0/Download/${fileName}`,
                                    fileType: 'pdf',
                                    success: () => {
                                        console.log('打开文档成功');
                                    },
                                    fail: (err) => {
                                        console.error('打开文档失败:', err);
                                    }
                                });
                            }, 1500)
                        }
                        loading.value.close();
                    }
                );

                dtask.addEventListener('statechanged', (task) => {
                    if (!dtask) return;
                    switch (task.state) {
                        case 3:
                            const percent = (task.downloadedSize / task.totalSize * 100).toFixed(1);
                            console.log(percent, "percent")
                            //uni.showToast({ title: `下载中: ${percent}%`, icon: "none" });
                            //current.value=percent                 
                            break;
                        case 4:
                            plus.nativeUI.closeWaiting();
                            break;
                    }
                });
                dtask.start();
            },
            () => { uni.showModal({ title: "系统提示", content: "权限被拒绝,无法保存文件!" }); }
        );
    }
    

全部代码

<template>
    <z-paging class="container">
        <template #top>
            <wd-navbar safe-area-inset-top left-arrow title="凭证详情" custom-class="transparent-navbar"
                @click-left="goback">
            </wd-navbar>
        </template>
        <view class="contant">
            <view class="swiper-wrapper">
                <wd-swiper :list="swiperList" v-model:current="current" class="custom-swiper" :indicator="false"
                    :autoplay="false"></wd-swiper>
            </view>

            <view class="footer" v-if="responseData?.pics.length > 0">
                <wd-button type="primary" size="large" @click="handleSubmit" block class="download-btn">全部下载</wd-button>
            </view>
        </view>
        <loadcom ref="loading"></loadcom>
    </z-paging>
</template>

<script setup lang="ts">
import { ref, reactive, nextTick } from "vue"
import { getPrint } from '@/api/print'
import { useConfigStore } from '@/store/config';
const loading = ref(null);
const current = ref<number>(0)
const swiperList = ref<string[]>(['/static/images/emm.png'])
const configStore = useConfigStore();
const responseData = reactive({
    pics: [],
    MajorName: ''
})

const loadData = async () => {
    try {
        loading.value.open('加载中...');
        const res = await getPrint(paramsData.value)

        if (res.Code === '2000') {
            const parsedData = JSON.parse(res.Data)
            const data = Object.freeze(JSON.parse(parsedData.Data)) // 冻结原始数据
            if (data === null || data?.pics.length === 0) {
                loading.value.close();
                return uni.showToast({
                    title: '暂无凭证',
                    icon: 'none'
                });
            }
            responseData.pics = [...data.pics] // 仅复制需要响应式的数据
            responseData.MajorName = data.MajorName

            // 优化图片加载性能
            const fullUrls = data.pics.map(item => 'http://' + configStore.curServiceIp + ':8999/' + item)
            const frozenUrls = Object.freeze(fullUrls) // 冻结URL数组
            // 预加载图片
            preloadImages(frozenUrls)
                .then(() => {
                    loading.value.close();
                    console.log('所有图片加载完成')
                })
                .catch(err => {
                    loading.value.close();
                    console.error('加载失败的图片:', err)
                });
            // preloadImages(frozenUrls)

            // 清空后设置新数据,确保占位图被完全替换
            swiperList.value = ['/static/images/first.png']
            nextTick(() => {
                swiperList.value = [...frozenUrls]
            })

            loading.value.close();
        } else {
            loading.value.close();
            uni.showToast({
                title: res.Message || '加载失败',
                icon: 'none'
            });
        }
    } catch (error) {
        loading.value.close();
        uni.showToast({
            title: '加载出错: ' + error.message,
            icon: 'none'
        });
        console.error('loadData error:', error);
    }
}
function preloadImages(urls: string[]): Promise<void[]> {
    return Promise.all<void>(
        urls.map(url => {
            return new Promise<void>((resolve) => {
                uni.downloadFile({
                    url: url,
                    success: () => resolve(),
                    fail: () => resolve(), // 继续流程不中断
                    complete: () => { } // 确保不会抛出异常
                });
            });
        })
    );
}
async function handleSubmit() {
    const url = 'http://' + configStore.curServiceIp + ':8999/' + responseData.MajorName
    console.log('url', url);
    const fileName = url.split('/').pop()
    // #ifdef MP || APP-PLUS
    loading.value.open('保存中...');
    // 动态申请权限
    plus.android.requestPermissions(
        ['android.permission.WRITE_EXTERNAL_STORAGE'],
        () => {
            // 下载文件到Download目录
            let dtask = plus.downloader.createDownload(
                url,
                { filename: `file://storage/emulated/0/Download/${fileName}` },
                (d, status) => {
                    if (status === 200) {
                        loading.value.close();
                        uni.showModal({
                            title: '系统提示',
                            content: "文件下载成功并保存到(手机内部存储:【Download】 文件夹),请注意查看!",
                            showCancel: false
                        })
                        setTimeout(() => {
                            // 打开下载的文件
                            uni.openDocument({
                                filePath: `file://storage/emulated/0/Download/${fileName}`,
                                fileType: 'pdf',
                                success: () => {
                                    console.log('打开文档成功');
                                },
                                fail: (err) => {
                                    console.error('打开文档失败:', err);
                                }
                            });
                        }, 1500)
                    }
                    loading.value.close();
                }
            );

            dtask.addEventListener('statechanged', (task) => {
                if (!dtask) return;
                switch (task.state) {
                    case 3:
                        const percent = (task.downloadedSize / task.totalSize * 100).toFixed(1);
                        console.log(percent, "percent")
                        //uni.showToast({ title: `下载中: ${percent}%`, icon: "none" });
                        //current.value=percent                 
                        break;
                    case 4:
                        plus.nativeUI.closeWaiting();
                        break;
                }
            });
            dtask.start();
        },
        () => { uni.showModal({ title: "系统提示", content: "权限被拒绝,无法保存文件!" }); }
    );
    // #endif

    // #ifdef H5
        try {
        loading.value.open('下载中...');
        const downloadTask = uni.downloadFile({
            url: url,
            success: (res) => {
                if (res.statusCode === 200) {
                    uni.saveFile({
                        tempFilePath: res.tempFilePath,
                        success: (saveRes) => {
                            uni.showToast({
                                title: '文件保存成功',
                                icon: 'success'
                            });
                            console.log('文件保存路径:', saveRes.savedFilePath);
                            uni.openDocument({
                                filePath: saveRes.savedFilePath,
                                fileType: 'pdf',
                                success: () => {
                                    console.log('打开文档成功');
                                }
                            });
                        }
                    });
                }
            },
            complete: () => {
                loading.value.close();
            }
        });
    } catch (error) {
        loading.value.close();
        uni.showToast({
            title: '下载出错: ' + error.message,
            icon: 'none'
        });
    }
    // #endif
}
const goback = () => {
    uni.navigateBack({})
}
const paramsData = ref({})
onLoad((options) => {
    paramsData.value = options
})
onMounted(() => {
    // 自动旋转
    // #ifdef MP || APP-PLUS
    plus.screen.unlockOrientation()
    // #endif
    loadData()
})
</script>

<style lang="scss" scoped>
/* 整体容器 */
.contant {
    box-sizing: border-box;
    padding: 15px;
    // display: flex;
    // flex-direction: column;
    // margin-top: 50%;
    // background: #f8f9fa; // 浅灰背景提升层次感
    // padding: 16px; // 符合移动端边距规范[8](@ref)
}

/* 轮播图容器 */
.swiper-wrapper {
    // flex: 1;
    // border-radius: 16px; // 圆角设计
    // overflow: hidden; // 隐藏溢出部分
    // box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08); // 柔和阴影增加深度[7](@ref)
    // margin-bottom: 20px; // 与按钮间距
}

/* 轮播图自定义样式 */
.custom-swiper {
    height: 100%;

    ::v-deep .wd-swiper__item img {
        object-fit: contain !important; // 保持图片比例,宽度自适应
        width: 100%;
        height: 100%;
    }
}

/* 底部按钮容器 */
.footer {
    padding: 12px;
}

/* 按钮样式优化 */
.download-btn {
    ::v-deep .wd-button {
        border-radius: 50px !important; // 胶囊按钮
        height: 52px !important; // 增大点击区域[8](@ref)
        font-weight: 600;
        letter-spacing: 1px;
        box-shadow: 0 4px 12px rgba(26, 91, 189, 0.3); // 主色调阴影[1](@ref)
        transition: all 0.3s ease;

        &:active {
            transform: translateY(2px); // 点击反馈
            box-shadow: 0 2px 6px rgba(26, 91, 189, 0.3);
        }
    }
}

:deep() {
    .transparent-navbar {
        --wd-navbar-background: rgba(0, 123, 255, 1) !important;
        background-color: rgba(0, 123, 255, 1) !important;
        background-image: url("@/static/images/notebackground.png");
        position: absolute;
        z-index: 9999;
        margin-bottom: 20rpx;
    }

    .transparent-navbar .wd-icon-arrow-left {
        z-index: 99999;
    }

    /* 修改左箭头为白色 */
    .transparent-navbar .wd-icon-arrow-left::before {
        color: #ffffff !important;
        fill: #ffffff !important;
        /* 如果是 SVG 图标可能需要这个 */
    }

    /* 移除导航栏底部边框(如果存在) */
    .transparent-navbar::after {
        display: none !important;
    }

    /* 确保文字颜色为白色 */
    .transparent-navbar .wd-navbar__text,
    .transparent-navbar .wd-navbar__title {
        color: #ffffff !important;
    }

}


/* 横屏样式 */
@media screen and (orientation: landscape) {
    .container {
        transform: none;
        width: 100vw;
        height: 100vh;
        margin: 0;
        padding: 0;
        overflow-x: hidden;
    }

    .contant {
        height: 100%;
        padding: 0;
    }

    .swiper-wrapper {
        height: 100%;
        width: 100%;
        // margin-top: 10rpx;
    }

    .custom-swiper {
        width: 100%;
        height: 100%;
    }

    .download-btn {
        position: absolute;
        right: 0rpx;
        top: 40rpx;
        z-index: 9999;
    }

    .wd-button.is-large[data-v-aa3a6253] {
        padding: 20rpx;
    }

    .footer {
        padding: 0px;
    }

    :deep() {
        .wd-navbar {
            position: absolute !important;
        }

        .transparent-navbar {
            --wd-navbar-background: rgba(0, 123, 255, 1) !important;
            background-color: rgba(0, 123, 255, 1) !important;
            background-image: url("@/static/images/notebackground.png");
            position: absolute;
            top: 9999px;
            left: 9999px;
            // z-index: 9999;
            // margin-bottom: 20rpx;
        }

        .transparent-navbar .wd-icon-arrow-left {
            z-index: 0;
        }

        /* 修改左箭头为白色 */
        .transparent-navbar .wd-icon-arrow-left::before {
            color: #ffffff !important;
            fill: #ffffff !important;
            /* 如果是 SVG 图标可能需要这个 */
        }

        /* 移除导航栏底部边框(如果存在) */
        .transparent-navbar::after {
            display: none !important;
        }

        /* 确保文字颜色为白色 */
        .transparent-navbar .wd-navbar__text,
        .transparent-navbar .wd-navbar__title {
            color: #ffffff !important;
        }

        .wd-swiper__track {
            height: 100vh !important;
        }

        .wd-swiper__image {
            height: 100% !important;
        }

        .wd-swiper__item img {
            object-fit: contain !important;
            width: auto !important;
            height: 100% !important;
            max-width: 100%;
            // padding-top: 10rpx;
            // box-sizing: border-box;

        }

        .wd-swiper__image div {
            background-size: contain !important;
        }

        .uni-image {
            height: 100% !important;
            width: auto !important;
        }
    }
}

// :deep() {

//  .wd-swiper__track {
//      width: 100% !important;
//      height: 250px !important;

//  }

//  .wd-swiper__image {
//      width: 100% !important;
//      height: 250px !important;
//  }

//  .wd-swiper__image div {
//      background-size: contain !important;
//  }
// }</style>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。