提交 6d643a3c authored 作者: JaxBBLL's avatar JaxBBLL

feat: use local image file

上级 93f179e4
<template>
<view class="upload-container">
<!-- 图片展示区域 -->
<view class="image-list">
<!-- 添加按钮 -->
<view
v-if="images.length < maxCount"
class="add-btn"
@click="chooseImage"
>
</view>
<view
v-for="(item, index) in images"
:key="index"
class="image-item"
@click="previewImage(index)"
>
<image :src="item" class="image" mode="aspectFill"></image>
<text class="delete-icon" @click.stop="deleteImage(index)">×</text>
</view>
</view>
<!-- 提示文字 -->
<view class="tip">
<slot name="tip">
请对检查项进行拍照留存(限{{
maxCount
}}张)。发现“异常、告警”时,需拍照留存。
</slot>
</view>
</view>
</template>
<script>
export default {
name: "CommonUpload",
props: {
value: {
type: Array,
default: () => [],
},
maxCount: {
type: Number,
default: 5, // 默认最多上传 5 张图片
},
sourceType: {
type: Array,
default: () => ["camera"], // 默认从相机拍摄
},
sizeType: {
type: Array,
default: () => ["compressed"], // 默认压缩图 ["original", "compressed"]
},
},
data() {
return {
images: this.value, // 绑定的图片数组
};
},
watch: {
value(newVal) {
this.images = newVal;
},
images(newVal) {
this.$emit("input", newVal); // 同步更新父组件绑定的数据
},
},
methods: {
// 检查并请求权限
// async checkAndRequestPermission() {
// // 定义所需权限
// const permissions = [];
// if (this.sourceType.includes("camera")) {
// permissions.push("android.permission.CAMERA"); // 相机权限
// }
// if (this.sourceType.includes("album")) {
// permissions.push("android.permission.READ_EXTERNAL_STORAGE"); // 相册权限
// }
// // 检查权限状态
// const hasPermission = await new Promise((resolve) => {
// plus.android.requestPermissions(
// ["android.permission.CAMERA"],
// (result) => {
// let granted = true;
// for (let i = 0; i < result.granted.length; i++) {
// if (!result.granted[i]) {
// granted = false;
// break;
// }
// }
// resolve(granted);
// },
// (error) => {
// console.error("权限请求失败:", error.message);
// resolve(false);
// }
// );
// });
// if (!hasPermission) {
// // 用户拒绝授权,弹出提示
// uni.showModal({
// title: "权限提示",
// content:
// "您拒绝了必要的权限,可能导致功能无法正常使用。是否前往设置页面开启权限?",
// success: (modalRes) => {
// if (modalRes.confirm) {
// // 打开应用设置页面
// plus.runtime.openURL(
// "app-settings://", // 跳转到系统设置页面
// (err) => {
// console.error("跳转设置页面失败:", err.message);
// }
// );
// }
// },
// });
// return false;
// }
// return true;
// },
// // 选择图片
// async chooseImage() {
// // 检查权限
// const isAuthorized = await this.checkAndRequestPermission();
// if (!isAuthorized) return;
// const count = this.maxCount - this.images.length; // 剩余可选图片数量
// uni.chooseImage({
// count: count,
// sizeType: this.sizeType,
// sourceType: this.sourceType, // 使用传递的 sourceType
// success: async (res) => {
// const tempFilePaths = res.tempFilePaths;
// for (const filePath of tempFilePaths) {
// const base64 = await this.convertFileToBase64(filePath);
// this.images.push(base64);
// }
// },
// fail: (err) => {
// console.error("选择图片失败:", err);
// uni.showToast({
// title: "选择图片失败,请重试",
// icon: "none",
// });
// },
// });
// },
// 选择图片
chooseImage() {
plus.android.requestPermissions(
["android.permission.CAMERA"],
(result) => {
console.log("success");
resolve();
},
(error) => {
console.error("权限请求失败:", error.message);
resolve(false);
}
);
const count = this.maxCount - this.images.length; // 剩余可选图片数量
uni.chooseImage({
count: count,
sizeType: this.sizeType,
sourceType: this.sourceType, // 使用传递的 sourceType
success: async (res) => {
const tempFilePaths = res.tempFilePaths;
for (const filePath of tempFilePaths) {
const base64 = await this.convertFileToBase64(filePath);
this.images.push(base64);
}
},
fail(e) {
console.log(e, "faild");
},
});
},
// 预览图片
previewImage(index) {
uni.previewImage({
current: index,
urls: this.images,
});
},
// 删除图片
deleteImage(index) {
this.images.splice(index, 1);
},
// 转换文件为 Base64
convertFileToBase64(filePath) {
return new Promise((resolve, reject) => {
plus.io.resolveLocalFileSystemURL(
filePath,
(entry) => {
entry.file(
(file) => {
const reader = new plus.io.FileReader();
reader.onloadend = (evt) => {
resolve(evt.target.result); // 返回 Base64 数据
};
reader.readAsDataURL(file); // 读取文件并转换为 Base64
},
(error) => {
reject("获取文件对象失败:" + error.message);
}
);
},
(error) => {
reject("解析文件路径失败:" + error.message);
}
);
});
},
},
};
</script>
<style scoped lang="scss">
.upload-container {
}
.image-list {
display: flex;
flex-wrap: wrap;
}
.image-item {
position: relative;
width: 72px;
height: 72px;
margin-right: 10px;
}
.image {
width: 100%;
height: 100%;
box-sizing: border-box;
}
.delete-icon {
position: absolute;
top: -6.4px;
right: -6.4px;
background-color: #ff4d4f;
color: #fff;
width: 12.8px;
height: 12.8px;
border-radius: 50%;
text-align: center;
line-height: 12.8px;
font-size: 9.6px;
}
.add-btn {
position: relative;
width: 72px;
height: 72px;
border: 1px dashed #ccc;
cursor: pointer;
margin-right: 10px;
box-sizing: border-box;
&::before {
position: absolute;
content: "";
width: 30px;
height: 2px;
background-color: #ccc;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
}
&::after {
position: absolute;
content: "";
width: 2px;
height: 30px;
background-color: #ccc;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
}
}
.tip {
font-size: 12px;
color: #999;
margin-top: 5px;
}
</style>
/**
* 在公共文档目录下递归创建多级文件夹
* @param {*} relativePath
* @returns
*/
export async function createFolder(relativePath) {
try {
// 1. 获取根目录对象(网页1、网页5)
const rootEntry = await new Promise((resolve, reject) => {
plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, resolve, reject);
}).then((fs) => fs.root);
// 2. 路径标准化处理(网页5、网页7)
const pathSegments = relativePath.split("/").filter(Boolean);
let currentDir = rootEntry;
// 3. 递归创建目录(网页1、网页5、网页8)
for (const segment of pathSegments) {
currentDir = await new Promise((resolve, reject) => {
currentDir.getDirectory(
segment,
{ create: false },
(dir) => resolve(dir), // 目录已存在直接返回(网页7逻辑)
() =>
currentDir.getDirectory(
// 目录不存在时创建(网页5方法)
segment,
{ create: true },
resolve,
reject
)
);
});
}
return currentDir;
} catch (error) {
console.error(`目录创建失败: ${error.message}`);
throw new Error(`操作失败: ${error.code}`);
}
}
/**
* 复制相册图片
* @param {*} sourcePath
* @param {*} targetPath
* @returns
*/
export async function copyImage(sourcePath, targetPath) {
try {
// 1. 处理iOS路径格式问题[1](@ref)
const normalizedSource = plus.io.convertLocalFileSystemURL(sourcePath);
const normalizedTarget = plus.io.convertLocalFileSystemURL(targetPath);
// 2. 解析源文件对象
const sourceEntry = await new Promise((resolve, reject) => {
plus.io.resolveLocalFileSystemURL(normalizedSource, resolve, reject);
});
if (!sourceEntry.isFile) throw new Error("源路径不是文件");
// 3. 分解目标路径为目录和文件名
const targetDirPath = normalizedTarget.substring(
0,
normalizedTarget.lastIndexOf("/")
);
const targetFileName = normalizedTarget.split("/").pop();
// 4. 获取目标目录对象
const targetDirEntry = await new Promise((resolve, reject) => {
plus.io.resolveLocalFileSystemURL(targetDirPath, resolve, (err) => {
reject(new Error(`目标目录不存在: ${targetDirPath}`));
});
});
// 5. 执行文件复制
const newEntry = await new Promise((resolve, reject) => {
sourceEntry.copyTo(targetDirEntry, targetFileName, resolve, (err) => {
// 处理文件已存在的覆盖逻辑
if (err.code === 12) {
// 文件已存在错误码
targetDirEntry.getFile(
targetFileName,
{ create: false },
(existEntry) =>
existEntry.remove(() =>
sourceEntry.copyTo(
targetDirEntry,
targetFileName,
resolve,
reject
)
),
reject
);
} else {
reject(err);
}
});
});
// 6. 返回标准化路径(移除file://前缀)
return newEntry.toURL().replace(/^file:\/\//, "");
} catch (error) {
console.error(`文件复制失败: ${error.message}`);
throw new Error(`操作失败: ${error.message}`);
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论