daShangDao_scanBook/pages/upload/camera_capture.nvue

421 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="cc-page">
<!-- 正方形相机预览 -->
<ima-camera-view
ref="cameraRef"
:style="'width:' + camSize + 'px;height:' + camSize + 'px;margin-top:' + frameTop + 'px;margin-left:' + frameLeft + 'px;'"
flash="off"
facing="back"
:widthRatio="1"
:heightRatio="1"
@onPictureTaken="onPictureTaken"
@onCameraOpened="onCameraOpened"
></ima-camera-view>
<!-- 正方形取景框(白色边框) -->
<view class="cc-frame" :style="'top:' + frameTop + 'px;left:' + frameLeft + 'px;width:' + camSize + 'px;height:' + camSize + 'px;'"></view>
<!-- ═══ 顶部栏 ═══ -->
<view class="cc-topbar">
<view class="cc-topbar-left">
<view class="cc-topbar-back" @click="goBack">
<text class="cc-back-icon">✕</text>
</view>
</view>
<view class="cc-topbar-center">
<text class="cc-topbar-title">{{ capturedList.length > 0 ? '已拍 ' + capturedList.length + '/9' : '拍照' }}</text>
</view>
<view class="cc-topbar-right">
<view class="cc-flip-btn" @click="flipCamera">
<text class="cc-flip-icon">↺</text>
</view>
</view>
</view>
<!-- ═══ 底部操作栏 ═══ -->
<view class="cc-footer">
<!-- 左侧:缩略图预览 -->
<view class="cc-footer-left">
<view class="cc-thumb-preview" v-if="capturedList.length > 0" @click="previewLast">
<image class="cc-thumb-last" :src="capturedList[capturedList.length-1]" mode="aspectFill"></image>
<text class="cc-thumb-badge">{{ capturedList.length }}</text>
</view>
</view>
<!-- 中间:拍照按钮 -->
<view class="cc-footer-center">
<view class="cc-capture-outer">
<view class="cc-capture-btn" @click="capturePhoto"></view>
</view>
</view>
<!-- 右侧:完成按钮 -->
<view class="cc-footer-right">
<text class="cc-confirm-btn" @click="confirmCapture" v-if="capturedList.length > 0">完成 {{ capturedList.length }}</text>
</view>
</view>
<!-- ═══ 缩略图横条超过1张时 ═══ -->
<view class="cc-thumb-bar" v-if="capturedList.length > 1">
<scroll-view scroll-x="true" show-scrollbar="false" style="flex-direction:row;">
<view style="flex-direction:row;">
<view class="cc-thumb-item" v-for="(img, idx) in capturedList" :key="idx">
<image class="cc-thumb-img" :src="img" mode="aspectFill" @click.stop="previewPhoto(idx)"></image>
<view class="cc-thumb-del" @click.stop="deletePhoto(idx)">
<text class="cc-del-icon">✕</text>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- ═══ 自定义图片预览(正方形) ═══ -->
<view class="cc-preview-overlay" v-if="previewVisible" @click="previewVisible = false">
<view class="cc-preview-close" @click.stop="previewVisible = false">
<text class="cc-preview-close-icon">✕</text>
</view>
<image class="cc-preview-img" :src="previewSrc" mode="aspectFill" :style="'width:' + previewSize + 'px;height:' + previewSize + 'px;'"></image>
</view>
</view>
</template>
<script>
export default {
data() {
return {
capturedList: [],
cameraReady: false,
facing: 'back',
winWidth: 750,
winHeight: 1334,
camSize: 750,
frameTop: 110,
frameLeft: 0,
// 自定义预览
previewVisible: false,
previewSrc: '',
previewSize: 600
}
},
onLoad() {
var that = this
uni.getSystemInfo({
success: function(res) {
that.winWidth = res.windowWidth
that.winHeight = res.windowHeight
that.previewSize = Math.floor(res.windowWidth * 0.85)
// 取景框放在中间偏上一点
var barH = 110
var bottomArea = 240
var availableH = res.windowHeight - barH - bottomArea
var size = Math.min(res.windowWidth, availableH)
that.camSize = size
that.frameTop = barH + Math.floor((availableH - size) / 2)
that.frameLeft = Math.floor((res.windowWidth - size) / 2)
}
})
},
methods: {
onCameraOpened() {
this.cameraReady = true
console.log('相机已就绪')
},
capturePhoto() {
if (this.capturedList.length >= 9) {
uni.showToast({ title: '最多拍9张', icon: 'none' })
return
}
if (!this.cameraReady) {
uni.showToast({ title: '相机未就绪', icon: 'none' })
return
}
this.$refs.cameraRef.takePhoto()
},
onPictureTaken(e) {
var path = ''
if (e.detail) {
path = e.detail.path || ''
}
if (path) {
this.capturedList.push(path)
}
},
flipCamera() {
this.facing = this.facing === 'back' ? 'front' : 'back'
this.$refs.cameraRef.changeFacing(this.facing)
},
deletePhoto(idx) {
this.capturedList.splice(idx, 1)
},
goBack() {
if (this.capturedList.length > 0) {
uni.showModal({
title: '提示',
content: '确定退出拍照?已拍照片将丢失',
success: function(res) {
if (res.confirm) { uni.navigateBack() }
}
})
} else {
uni.navigateBack()
}
},
confirmCapture() {
if (this.capturedList.length === 0) {
uni.showToast({ title: '请先拍照', icon: 'none' })
return
}
var pages = getCurrentPages()
var prevPage = pages[pages.length - 2]
if (prevPage) {
prevPage.$vm.capturedPhotoList = this.capturedList
}
uni.navigateBack()
},
// 放大预览指定图片(正方形显示)
previewPhoto(idx) {
if (this.capturedList.length > 0 && idx >= 0 && idx < this.capturedList.length) {
this.previewSrc = this.capturedList[idx]
this.previewVisible = true
}
},
// 放大预览最新一张
previewLast() {
this.previewPhoto(this.capturedList.length - 1)
}
}
}
</script>
<style>
.cc-page {
flex: 1;
background-color: #000000;
position: relative;
}
/* 取景框(白色边框,视觉引导) */
.cc-frame {
position: absolute;
border-width: 2rpx;
border-color: rgba(255,255,255,0.5);
border-style: solid;
z-index: 4;
background-color: transparent;
}
/* ═══ 顶部栏 ═══ */
.cc-topbar {
position: absolute;
top: 0; left: 0; right: 0;
height: 110px;
padding-top: 50px;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding-left: 24rpx;
padding-right: 24rpx;
z-index: 8;
background: linear-gradient(to bottom, rgba(0,0,0,0.5), transparent);
}
.cc-topbar-left {
width: 100rpx;
}
.cc-topbar-back {
width: 80rpx; height: 80rpx;
border-radius: 80rpx;
background-color: rgba(0,0,0,0.35);
align-items: center; justify-content: center;
}
.cc-back-icon {
color: #ffffff;
font-size: 44rpx;
text-align: center;
}
.cc-topbar-center {
flex: 1;
align-items: center;
}
.cc-topbar-title {
color: #ffffff;
font-size: 40rpx;
font-weight: 700;
}
.cc-topbar-right {
flex-direction: row;
align-items: center;
}
/* 翻转按钮(在右上角) */
.cc-flip-btn {
width: 84rpx; height: 84rpx;
border-radius: 84rpx;
border-width: 3rpx;
border-color: rgba(255,255,255,0.3);
border-style: solid;
align-items: center; justify-content: center;
background-color: rgba(0,0,0,0.25);
}
.cc-flip-icon {
color: #ffffff;
font-size: 44rpx;
font-weight: 700;
text-align: center;
}
/* ═══ 底部操作栏 ═══ */
.cc-footer {
position: absolute;
bottom: 0; left: 0; right: 0;
height: 240rpx;
padding-bottom: 40rpx;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding-left: 40rpx;
padding-right: 40rpx;
z-index: 8;
background: linear-gradient(to top, rgba(0,0,0,0.6), transparent);
}
.cc-footer-left {
flex-direction: row;
align-items: center;
flex: 1;
}
.cc-footer-center {
align-items: center;
justify-content: center;
}
.cc-footer-right {
flex-direction: row;
align-items: center;
justify-content: flex-end;
flex: 1;
}
/* 拍照按钮(放大) */
.cc-capture-outer {
width: 120rpx; height: 120rpx;
border-radius: 120rpx;
border-width: 6rpx;
border-color: rgba(255,255,255,0.6);
border-style: solid;
align-items: center; justify-content: center;
}
.cc-capture-btn {
width: 106rpx; height: 106rpx;
border-radius: 106rpx;
background-color: #ffffff;
}
.cc-capture-btn:active {
background-color: #dddddd;
}
/* 完成按钮(在底部右侧) */
.cc-confirm-btn {
color: #ffffff;
font-size: 30rpx;
font-weight: 700;
padding-left: 36rpx; padding-right: 36rpx;
padding-top: 16rpx; padding-bottom: 16rpx;
border-width: 2rpx;
border-color: #ffffff;
border-style: solid;
background-color: transparent;
lines: 1;
}
/* 缩略图预览(最新一张) */
.cc-thumb-preview {
width: 100rpx; height: 100rpx;
border-radius: 12rpx;
overflow: hidden;
position: relative;
border-width: 2rpx;
border-color: rgba(255,255,255,0.3);
border-style: solid;
}
.cc-thumb-last {
width: 100rpx; height: 100rpx;
}
.cc-thumb-badge {
position: absolute;
top: -8rpx; right: -8rpx;
min-width: 34rpx; height: 34rpx;
border-radius: 34rpx;
background-color: #409eff;
color: #ffffff;
font-size: 22rpx;
text-align: center;
line-height: 34rpx;
padding-left: 6rpx; padding-right: 6rpx;
}
/* 缩略图横条 */
.cc-thumb-bar {
position: absolute;
bottom: 260rpx; left: 0; right: 0;
padding-left: 24rpx; padding-right: 24rpx;
padding-top: 14rpx; padding-bottom: 14rpx;
z-index: 8;
}
.cc-thumb-item {
width: 120rpx; height: 120rpx;
border-radius: 10rpx;
overflow: hidden;
position: relative;
border-width: 2rpx;
border-color: rgba(255,255,255,0.3);
border-style: solid;
margin-right: 16rpx;
background-color: #333333;
}
.cc-thumb-img {
width: 120rpx; height: 120rpx;
}
.cc-thumb-del {
position: absolute;
top: -8rpx; right: -8rpx;
width: 40rpx; height: 40rpx;
border-radius: 40rpx;
background-color: rgba(0,0,0,0.55);
align-items: center; justify-content: center;
border-width: 2rpx;
border-color: rgba(255,255,255,0.3);
border-style: solid;
}
.cc-del-icon {
color: #ffffff;
font-size: 22rpx;
}
/* ═══ 自定义正方形预览 ═══ */
.cc-preview-overlay {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background-color: rgba(0,0,0,0.9);
z-index: 20;
align-items: center;
justify-content: center;
}
.cc-preview-close {
position: absolute;
top: 60px; right: 30rpx;
width: 60rpx; height: 60rpx;
border-radius: 60rpx;
background-color: rgba(255,255,255,0.2);
align-items: center; justify-content: center;
z-index: 21;
}
.cc-preview-close-icon {
color: #ffffff;
font-size: 36rpx;
}
.cc-preview-img {
border-radius: 8rpx;
border-width: 2rpx;
border-color: rgba(255,255,255,0.2);
border-style: solid;
}
</style>