daShangDao_scanBook/pages/upload/camera_capture.nvue

404 lines
11 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-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>
<!-- ═══ 缩略图横条 ═══ -->
<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: 0,
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.camSize = res.windowWidth
that.previewSize = Math.floor(res.windowWidth * 0.85)
// 垂直居中顶部栏110px + 底部操作栏240px
var barH = 110
var bottomArea = 240
var availableH = res.windowHeight - barH - bottomArea
if (res.windowWidth < availableH) {
that.frameTop = barH + Math.floor((availableH - res.windowWidth) / 2)
} else {
that.frameTop = barH
}
that.frameLeft = 0
}
})
},
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.resizeTo1080(path)
}
},
// 先添加原图确保UI响应再异步替换为1080×1080
resizeTo1080(srcPath) {
var that = this
// 先占位,让完成按钮立即出现
var idx = this.capturedList.length
this.capturedList.push(srcPath)
// 异步尝试压缩
try {
if (typeof plus !== 'undefined' && plus.zip) {
uni.getImageInfo({
src: srcPath,
success: function(info) {
var w = info.width
var h = info.height
var size = Math.min(w, h)
var cx = Math.floor((w - size) / 2)
var cy = Math.floor((h - size) / 2)
plus.zip.compressImage({
src: srcPath,
dst: '_doc/sq_' + Date.now() + '.jpg',
width: '1080',
height: '1080',
quality: 95,
overwrite: true,
clip: {
x: cx, y: cy,
width: size, height: size
}
},
function(res) {
that.capturedList[idx] = res.target
},
function() {
// 保持原图
})
},
fail: function() {}
})
}
} catch(e) {}
},
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-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-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>