接上篇
用户反馈找不到文件储存位置,需要指定路径下载
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>