Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
I
inspection-pad-web
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
专网
inspection-pad-web
Commits
6d643a3c
提交
6d643a3c
authored
4月 11, 2025
作者:
JaxBBLL
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: use local image file
上级
93f179e4
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
401 行增加
和
0 行删除
+401
-0
index.vue
components/CommonUpload/index.vue
+0
-0
index0.vue
components/CommonUpload/index0.vue
+294
-0
plus.js
utils/plus.js
+107
-0
没有找到文件。
components/CommonUpload/index.vue
浏览文件 @
6d643a3c
差异被折叠。
点击展开。
components/CommonUpload/index0.vue
0 → 100644
浏览文件 @
6d643a3c
<
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
>
utils/plus.js
0 → 100644
浏览文件 @
6d643a3c
/**
* 在公共文档目录下递归创建多级文件夹
* @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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论