166 lines
4.8 KiB
Vue
166 lines
4.8 KiB
Vue
<template>
|
||
<view class="cam-page">
|
||
<!-- 顶部自定义导航 -->
|
||
<view class="cam-nav" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="cam-nav-back" @click="goBack">
|
||
<u-icon name="arrow-left" color="#fff" size="40"></u-icon>
|
||
</view>
|
||
<view class="cam-nav-title">{{ title }}</view>
|
||
<view class="cam-nav-right"></view>
|
||
</view>
|
||
|
||
<!-- 拍摄态:相机取景 -->
|
||
<block v-if="!captured">
|
||
<camera class="cam-view" :device-position="'back'" :flash="'auto'" @error="onCamError"></camera>
|
||
<!-- 取景框遮罩 -->
|
||
<view class="cam-overlay">
|
||
<view class="cam-frame" :class="orientation === 'landscape' ? 'frame-landscape' : 'frame-portrait'">
|
||
<view class="cam-corner tl"></view>
|
||
<view class="cam-corner tr"></view>
|
||
<view class="cam-corner bl"></view>
|
||
<view class="cam-corner br"></view>
|
||
</view>
|
||
<view class="cam-tip">{{ frameTip }}</view>
|
||
</view>
|
||
<!-- 横版/竖版切换 -->
|
||
<view class="cam-orient">
|
||
<view class="orient-item" :class="{ active: orientation === 'landscape' }" @click="orientation = 'landscape'">横版</view>
|
||
<view class="orient-item" :class="{ active: orientation === 'portrait' }" @click="orientation = 'portrait'">竖版</view>
|
||
</view>
|
||
<!-- 底部操作:相册 / 拍照 -->
|
||
<view class="cam-actions">
|
||
<view class="cam-action-side" @click="pickFromAlbum">
|
||
<u-icon name="photo" color="#fff" size="44"></u-icon>
|
||
<text>相册</text>
|
||
</view>
|
||
<view class="cam-shutter" @click="takePhoto"></view>
|
||
<view class="cam-action-side cam-action-placeholder"></view>
|
||
</view>
|
||
</block>
|
||
|
||
<!-- 预览态:重拍 / 提交 -->
|
||
<block v-else>
|
||
<image class="cam-preview" :src="tempPath" mode="aspectFit"></image>
|
||
<view class="cam-preview-actions">
|
||
<view class="prev-btn prev-retake" @click="retake">重拍</view>
|
||
<view class="prev-btn prev-submit" @click="confirmUse">提交</view>
|
||
</view>
|
||
</block>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
statusBarHeight: 20,
|
||
target: 'license', // license / idFront / idBack / industry
|
||
orientation: 'landscape',
|
||
captured: false,
|
||
tempPath: '',
|
||
cameraCtx: null,
|
||
}
|
||
},
|
||
computed: {
|
||
title() {
|
||
const map = {
|
||
license: '拍摄营业执照',
|
||
idFront: '拍摄身份证人像面',
|
||
idBack: '拍摄身份证国徽面',
|
||
industry: '拍摄行业资质',
|
||
}
|
||
return map[this.target] || '拍摄证件'
|
||
},
|
||
frameTip() {
|
||
const map = {
|
||
license: '请将营业执照完整置于取景框内',
|
||
idFront: '请将身份证人像面置于取景框内',
|
||
idBack: '请将身份证国徽面置于取景框内',
|
||
industry: '请将资质证件完整置于取景框内',
|
||
}
|
||
return map[this.target] || '请将证件完整置于取景框内'
|
||
}
|
||
},
|
||
onLoad(options) {
|
||
if (options && options.target) this.target = options.target
|
||
// 身份证默认横版,营业执照/资质默认竖版
|
||
this.orientation = (this.target === 'idFront' || this.target === 'idBack') ? 'landscape' : 'portrait'
|
||
try {
|
||
const sys = uni.getSystemInfoSync()
|
||
this.statusBarHeight = sys.statusBarHeight || 20
|
||
} catch (e) {}
|
||
},
|
||
onReady() {
|
||
// #ifndef H5
|
||
this.cameraCtx = uni.createCameraContext()
|
||
// #endif
|
||
},
|
||
methods: {
|
||
goBack() {
|
||
uni.navigateBack()
|
||
},
|
||
onCamError(e) {
|
||
console.error('相机错误:', e)
|
||
uni.showModal({
|
||
title: '无法使用相机',
|
||
content: '请检查是否已授予相机权限,或改用相册上传。',
|
||
showCancel: false
|
||
})
|
||
},
|
||
takePhoto() {
|
||
if (!this.cameraCtx) {
|
||
// H5 等不支持 camera 组件的环境,回退到系统拍照
|
||
this.pickFromCamera()
|
||
return
|
||
}
|
||
this.cameraCtx.takePhoto({
|
||
quality: 'high',
|
||
success: (res) => {
|
||
this.tempPath = res.tempImagePath
|
||
this.captured = true
|
||
},
|
||
fail: () => {
|
||
uni.showToast({ title: '拍照失败,请重试', icon: 'none' })
|
||
}
|
||
})
|
||
},
|
||
pickFromCamera() {
|
||
uni.chooseImage({
|
||
count: 1, sizeType: ['compressed'], sourceType: ['camera'],
|
||
success: (res) => {
|
||
const fp = res.tempFilePaths && res.tempFilePaths[0]
|
||
if (!fp) return
|
||
this.tempPath = fp
|
||
this.captured = true
|
||
}
|
||
})
|
||
},
|
||
pickFromAlbum() {
|
||
uni.chooseImage({
|
||
count: 1, sizeType: ['compressed'], sourceType: ['album'],
|
||
success: (res) => {
|
||
const fp = res.tempFilePaths && res.tempFilePaths[0]
|
||
if (!fp) return
|
||
this.tempPath = fp
|
||
this.captured = true
|
||
}
|
||
})
|
||
},
|
||
retake() {
|
||
this.captured = false
|
||
this.tempPath = ''
|
||
},
|
||
confirmUse() {
|
||
if (!this.tempPath) return
|
||
// 把拍摄结果通过事件总线回传给入驻表单页,由其负责上传 + OCR
|
||
uni.$emit('shopEnter:capture', { target: this.target, filePath: this.tempPath })
|
||
uni.navigateBack()
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
@import url("./index.css");
|
||
</style>
|