427 lines
11 KiB
Vue
427 lines
11 KiB
Vue
<template>
|
||
<view>
|
||
<view class="default">
|
||
<!-- 删除按钮 -->
|
||
<view class="clear" v-if="vdata.hasImg && isShowClear && userIsShowClear">
|
||
<!-- -->
|
||
<image src="../../static/img/close.svg" @click.stop="logoutPopup.open()" mode="aspectFill"></image>
|
||
<!-- <image src="../../static/img/clear.svg" @click.stop="logoutPopup.open()"></image> -->
|
||
</view>
|
||
<view @click="previewImg" class="img-bg" v-if="vdata.hasImg">
|
||
<image :src="vdata.assemblyUrl" class="img-suc" mode="aspectFill"></image>
|
||
</view>
|
||
<image
|
||
v-if="!vdata.hasImg"
|
||
class="camera"
|
||
@click="chooseImg(['album', 'camera'])"
|
||
src="/static/iconImg/upload-picture.svg"
|
||
></image>
|
||
</view>
|
||
<!-- 图片预览(手写非原生) -->
|
||
<enlarge
|
||
v-if="isPreview"
|
||
:changeIsShow="props.isShowClear"
|
||
:imgs="vdata.assemblyUrl"
|
||
@enlargeClose="enlargeClose"
|
||
@chooseImg="chooseImg"
|
||
/>
|
||
<!-- 删除图片二次确认 -->
|
||
<uni-popup ref="logoutPopup" type="dialog">
|
||
<uni-popup-dialog mode="base" :before-close="true" @close="logoutPopup.close()" @confirm="clear">
|
||
<template #title>
|
||
<view class="tip-content">确定要删除该图片吗?</view>
|
||
</template>
|
||
</uni-popup-dialog>
|
||
</uni-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import appConfig from "@/config/appConfig.js"
|
||
import { ref, reactive, watch, onMounted, nextTick } from "vue"
|
||
import { $ossFilesForm, $imgInfoDetail } from "@/http/apiManager.js"
|
||
import storageManage from "@/util/storageManage.js"
|
||
import enlarge from "./enlarge.vue" // 图片预览
|
||
import useBackPress from "@/hooks/useBackPress.js" // 返回阻断函数
|
||
import { sm4DecryptByResData } from "@/util/encryptUtil.js"
|
||
|
||
const logoutPopup = ref(null) // 二次确认弹框
|
||
|
||
const props = defineProps({
|
||
upLoadUrl: { type: String, default: "/api/ossFiles/singleFile" }, // 默认图片
|
||
imgUrl: { type: String, default: "" }, // 默认图片
|
||
recogObjectType: { type: String, default: "" }, // 识别对象类型(idcard, idcard_back, bankcard, business_license)
|
||
uploadCount: { type: Number, default: 1 }, // 上传图片张数
|
||
size: { type: Number, default: 2 }, // 图片限制大小,单位M
|
||
imgTypes: { type: Array, default: () => ["jpg", "jpeg", "png"] }, // 图片类型限制,如: ['jpg', 'jpeg']
|
||
isShowClear: { type: Boolean, default: true }, // 进件成功不展示删除按钮与更换按钮
|
||
ocrFlag: { type: String, default: "" }, // ocr识别标志,图片类型: idCard-身份证,bankCard-银行卡, license-营业执照
|
||
userIsShowClear: { type: Boolean, default: true }, // 在其余页面中是否展示删除按钮
|
||
})
|
||
|
||
onMounted(() => {
|
||
if (props.imgUrl) {
|
||
vdata.hasImg = true
|
||
vdata.assemblyUrl = props.imgUrl
|
||
}
|
||
})
|
||
|
||
// 关闭图片预览
|
||
const enlargeClose = () => {
|
||
isPreview.value = false
|
||
// #ifdef H5 || APP-PLUS
|
||
inactive()
|
||
// #endif
|
||
}
|
||
|
||
const vdata = reactive({
|
||
hasImg: false,
|
||
assemblyUrl: "",
|
||
})
|
||
|
||
watch(
|
||
() => props.imgUrl,
|
||
(newVal, oldVal) => {
|
||
nextTick(() => {
|
||
newVal ? (vdata.hasImg = true) : (vdata.hasImg = false)
|
||
vdata.assemblyUrl = newVal
|
||
})
|
||
}
|
||
)
|
||
|
||
const emit = defineEmits(["uploadSuccess", "clear"])
|
||
|
||
// OCR识别函数
|
||
function imgInfoDetail(res) {
|
||
$imgInfoDetail({
|
||
imgUrl: res.data,
|
||
type: props.ocrFlag,
|
||
}).then(({ bizData }) => {
|
||
if (Object.keys(bizData).length < 1) {
|
||
// uni.showToast({
|
||
// title: '图片识别失败',
|
||
// icon: 'none'
|
||
// })
|
||
} else {
|
||
uni.showToast({
|
||
title: "图片识别成功,已自动回填内容,请检查核对",
|
||
icon: "none",
|
||
})
|
||
}
|
||
res.ocrInfo = bizData
|
||
return emit("uploadSuccess", res)
|
||
})
|
||
}
|
||
|
||
function chooseImg(index) {
|
||
console.log(index)
|
||
if (props.isShowClear) {
|
||
uni.chooseImage({
|
||
count: props.uploadCount,
|
||
sizeType: ["compressed"],
|
||
sourceType: index,
|
||
crop: { quality: 20 },
|
||
|
||
success: (chooseImageRes) => {
|
||
isPreview.value = false //关闭图片预览
|
||
const msg = beforeUpload(chooseImageRes)
|
||
if (msg != "success") return uni.showToast({ title: msg, icon: "none" })
|
||
|
||
// 根据form信息,判断图片上传地址
|
||
// 此处额外验证,上传的图片是否含有name属性,如果没有则用path代替
|
||
let sourceFileName
|
||
if (chooseImageRes.tempFiles[0].name) {
|
||
sourceFileName = chooseImageRes.tempFiles[0].name
|
||
} else {
|
||
sourceFileName = chooseImageRes.tempFiles[0].path
|
||
}
|
||
|
||
$ossFilesForm({
|
||
bizType: "applyment",
|
||
sourceFileName: sourceFileName,
|
||
sourceFileSize: chooseImageRes.tempFiles[0].size,
|
||
}).then(({ bizData }) => {
|
||
let url,
|
||
isOss,
|
||
ossImgUrl = ""
|
||
if (bizData.formActionUrl === "LOCAL_SINGLE_FILE_URL") {
|
||
url = appConfig.env.JEEPAY_BASE_URL + props.upLoadUrl
|
||
isOss = false
|
||
} else {
|
||
url = bizData.formActionUrl
|
||
ossImgUrl = { data: bizData.ossFileUrl }
|
||
isOss = true
|
||
}
|
||
|
||
// 调用图片上传方法
|
||
uploadImg(chooseImageRes.tempFilePaths, url, bizData.formParams, isOss, ossImgUrl)
|
||
console.log(url,'bizData.formParamsbizData.formParamsbizData.formParams');
|
||
})
|
||
},
|
||
})
|
||
}
|
||
}
|
||
|
||
// 上传图片
|
||
function uploadImg(tempFilePaths, url, formParams, isOss, ossImgUrl) {
|
||
const token = storageManage.token()
|
||
|
||
var successCount = 0 //多图时,上传成功数量
|
||
var qualification = [] //多图存储
|
||
|
||
uni.showLoading({ title: "上传中..." })
|
||
//循环上传图片
|
||
|
||
tempFilePaths.forEach((tempFilePath) => {
|
||
console.log(tempFilePath);
|
||
uni.uploadFile({
|
||
url: url,
|
||
filePath: tempFilePath,
|
||
name: "file",
|
||
header: {
|
||
itoken: token,
|
||
},
|
||
formData: formParams,
|
||
// 代表完成的函数 注:此处可以传入三个函数 success (成功)/ fail(失败) / complete (完成)
|
||
complete(res) {
|
||
uni.hideLoading()
|
||
|
||
// oss接口特有情况
|
||
if (isOss) {
|
||
if (res.statusCode != 200) {
|
||
return uni.showToast({ title: "请求失败,请重试", icon: "none" })
|
||
}
|
||
|
||
// 如果存在OCR 识别信息,那么要调用ocr识别函数
|
||
if (props.ocrFlag) return imgInfoDetail(ossImgUrl)
|
||
emit("uploadSuccess", ossImgUrl)
|
||
return (vdata.hasImg = true)
|
||
}
|
||
// res 即接口返回数据包
|
||
let {
|
||
statusCode, // 状态码
|
||
data, // 数据
|
||
msg, // 信息
|
||
errMsg, // 错误信息
|
||
} = res
|
||
|
||
// 接收请求,执行响应操作
|
||
if (statusCode != 200) {
|
||
uni.showToast({
|
||
title: "请求失败,请重试,statusCode:" + statusCode,
|
||
icon: "none",
|
||
mask: true,
|
||
duration: 2000,
|
||
})
|
||
return
|
||
}
|
||
|
||
if (typeof data == "string") {
|
||
data = JSON.parse(data)
|
||
}
|
||
|
||
// 图片上传解密
|
||
if (data.encryptData) {
|
||
data.data = sm4DecryptByResData(data.encryptData)
|
||
}
|
||
|
||
//状态码为1001(未登录)
|
||
if (data.code == 1001) {
|
||
uni.showToast({
|
||
title: "请登录",
|
||
icon: "none",
|
||
mask: true,
|
||
duration: 1500,
|
||
})
|
||
setTimeout(function () {
|
||
uni.reLaunch({
|
||
url: "/pages/login/login",
|
||
})
|
||
}, 1500)
|
||
return
|
||
}
|
||
|
||
if (data.code != 0) {
|
||
uni.showToast({
|
||
title: data.msg || "请求失败,请重试",
|
||
duration: 2000,
|
||
mask: true,
|
||
icon: "none",
|
||
})
|
||
return
|
||
}
|
||
|
||
// 如果存在OCR 识别信息,那么要调用ocr识别函数
|
||
if (props.ocrFlag) return imgInfoDetail(data)
|
||
// 没有遇到以上的情况
|
||
emit("uploadSuccess", data)
|
||
vdata.hasImg = true
|
||
},
|
||
})
|
||
})
|
||
}
|
||
// 上传图片前的校验
|
||
function beforeUpload(chooseImageRes) {
|
||
const tempFiles = chooseImageRes.tempFiles
|
||
|
||
let msg = "success"
|
||
|
||
if (tempFiles) {
|
||
for (let i = 0; i < tempFiles.length; i++) {
|
||
// 图片地址
|
||
let tempUrl = tempFiles[i].name || tempFiles[i].path
|
||
if (!tempUrl) {
|
||
msg = "请选择图片"
|
||
return msg
|
||
}
|
||
// 校验图片大小
|
||
if (tempFiles[i].size > props.size * 1024 * 1024) {
|
||
msg = "单张图片请不超过" + props.size + "MB"
|
||
return msg
|
||
}
|
||
// 校验后缀
|
||
if (!checkSuffix(tempUrl)) {
|
||
msg = "仅支持【" + props.imgTypes + "】格式的图片"
|
||
return msg
|
||
}
|
||
}
|
||
} else {
|
||
msg = "请选择图片"
|
||
return msg
|
||
}
|
||
|
||
if (chooseImageRes.tempFilePaths.length > props.uploadCount) {
|
||
msg = "最多上传" + props.uploadCount + "张图片"
|
||
return msg
|
||
}
|
||
|
||
return msg
|
||
}
|
||
// 校验图片后缀
|
||
function checkSuffix(fileName) {
|
||
const suffix = getFileSuffix(fileName).toLowerCase()
|
||
if (props.imgTypes.includes(suffix)) {
|
||
return true
|
||
}
|
||
|
||
return false
|
||
}
|
||
// 获取图片后缀
|
||
function getFileSuffix(fileName) {
|
||
if (!fileName || fileName.indexOf(".") < 0 || fileName.length <= 1) {
|
||
return ""
|
||
}
|
||
return fileName.substring(fileName.lastIndexOf(".") + 1)
|
||
}
|
||
|
||
let isPreview = ref(false) // 图片预览是否展示
|
||
// 预览图片
|
||
function previewImg() {
|
||
isPreview.value = true
|
||
|
||
// #ifdef H5 || APP-PLUS
|
||
active()
|
||
// #endif
|
||
// onceVar.imgView(true)
|
||
|
||
// let urls = [];
|
||
// urls.push(props.imgUrl)
|
||
|
||
// uni.previewImage({
|
||
// urls: urls
|
||
// });
|
||
}
|
||
|
||
// 叉号 清除图片
|
||
function clear() {
|
||
vdata.hasImg = false
|
||
emit("clear")
|
||
logoutPopup.value.close()
|
||
}
|
||
|
||
// #ifdef H5 || APP-PLUS
|
||
const { active, inactive } = useBackPress(enlargeClose) // onBackPress 阻断返回
|
||
// #endif
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
// 图片预览
|
||
.preview-img {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
background-color: #000;
|
||
z-index: 25;
|
||
}
|
||
.camera {
|
||
width: 50rpx;
|
||
height: 50rpx;
|
||
}
|
||
.default {
|
||
position: relative;
|
||
width: 120rpx;
|
||
height: 120rpx;
|
||
background-color: #fff;
|
||
border-radius: 5rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 1rpx dashed #cccdd9;
|
||
}
|
||
.img-bg {
|
||
position: relative;
|
||
width: 120rpx;
|
||
height: 120rpx;
|
||
background: #f1f1f1;
|
||
border-radius: 12rpx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 10;
|
||
/* margin-right: 30rpx; */
|
||
image {
|
||
height: 100%;
|
||
width: 100%;
|
||
}
|
||
}
|
||
.img-def {
|
||
width: 43rpx;
|
||
height: 37rpx;
|
||
}
|
||
|
||
.img-suc {
|
||
width: 100%;
|
||
/* height: 180rpx; */
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.clear {
|
||
position: absolute;
|
||
top: -10rpx;
|
||
left: 90rpx;
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
border-radius: 50%;
|
||
z-index: 12;
|
||
background: rgba(0, 0, 0, 0.7);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
image {
|
||
width: 30rpx;
|
||
height: 30rpx;
|
||
}
|
||
}
|
||
.tip-content {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: 120rpx;
|
||
font-size: 32rpx;
|
||
font-weight: 700;
|
||
color: #3981ff;
|
||
}
|
||
</style>
|