|
|
@@ -37,31 +37,47 @@
|
|
|
<span>请拍摄或选择面单图片进行识别</span>
|
|
|
</div>
|
|
|
|
|
|
- <van-uploader
|
|
|
- v-model="uploadImages"
|
|
|
- :max-count="1"
|
|
|
- :before-read="beforeReadImage"
|
|
|
- :after-read="afterReadImage"
|
|
|
- preview-full-image
|
|
|
- capture="camera"
|
|
|
- accept="image/*"
|
|
|
- >
|
|
|
- <template #preview-cover="{ file }">
|
|
|
- <div class="preview-cover">
|
|
|
- <van-icon name="photo" />
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </van-uploader>
|
|
|
-
|
|
|
- <div class="upload-footer">
|
|
|
+ <div class="camera-section">
|
|
|
+ <div class="camera-button" @click="openCamera">
|
|
|
+ <van-icon name="photo" size="40" />
|
|
|
+ <div class="camera-text">点击拍照</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 隐藏的上传组件,用于处理从相册选择 -->
|
|
|
+ <van-uploader
|
|
|
+ v-model="uploadImages"
|
|
|
+ :max-count="1"
|
|
|
+ :before-read="beforeReadImage"
|
|
|
+ :after-read="afterReadImage"
|
|
|
+ preview-full-image
|
|
|
+ accept="image/*"
|
|
|
+ :show-upload="false"
|
|
|
+ style="display: none;"
|
|
|
+ ref="uploaderRef"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 图片预览 -->
|
|
|
+ <div v-if="uploadImages.length > 0" class="image-preview">
|
|
|
+ <img :src="uploadImages[0].content" class="preview-image" />
|
|
|
+ <van-button
|
|
|
+ type="danger"
|
|
|
+ size="small"
|
|
|
+ @click="removeImage"
|
|
|
+ class="remove-btn"
|
|
|
+ >
|
|
|
+ 重新拍摄
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="upload-footer" v-if="uploading">
|
|
|
<van-button
|
|
|
type="primary"
|
|
|
block
|
|
|
:loading="uploading"
|
|
|
- @click="submitOCR"
|
|
|
- :disabled="!uploadImages.length"
|
|
|
+ disabled
|
|
|
>
|
|
|
- {{ uploading ? '上传中...' : '上传识别' }}
|
|
|
+ 自动上传中...
|
|
|
</van-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -90,6 +106,75 @@ const warehouse = store.warehouse
|
|
|
|
|
|
const uploadImages = ref([])
|
|
|
const uploading = ref(false)
|
|
|
+const uploaderRef = ref(null)
|
|
|
+
|
|
|
+// 打开相机
|
|
|
+const openCamera = () => {
|
|
|
+ // 创建隐藏的input元素来触发相机
|
|
|
+ const input = document.createElement('input')
|
|
|
+ input.type = 'file'
|
|
|
+ input.accept = 'image/*'
|
|
|
+ input.capture = 'camera'
|
|
|
+
|
|
|
+ input.onchange = (e) => {
|
|
|
+ const file = e.target.files[0]
|
|
|
+ if (file) {
|
|
|
+ // 模拟van-uploader的文件对象结构
|
|
|
+ const fileItem = {
|
|
|
+ file: file,
|
|
|
+ content: URL.createObjectURL(file),
|
|
|
+ status: 'uploading'
|
|
|
+ }
|
|
|
+ uploadImages.value = [fileItem]
|
|
|
+
|
|
|
+ // 触发图片处理
|
|
|
+ afterReadImage(fileItem)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ input.click()
|
|
|
+}
|
|
|
+
|
|
|
+// 移除图片
|
|
|
+const removeImage = () => {
|
|
|
+ uploadImages.value = []
|
|
|
+}
|
|
|
+
|
|
|
+// 自动上传图片
|
|
|
+const autoUploadImage = async (file) => {
|
|
|
+ if (!warehouse) {
|
|
|
+ showFailToast('未获取到仓库信息')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查图片大小是否超过2MB
|
|
|
+ if (file.size > 2 * 1024 * 1024) {
|
|
|
+ showFailToast('图片大小不能超过2MB')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ uploading.value = true
|
|
|
+ const toast = showLoadingToast('自动上传识别中...')
|
|
|
+
|
|
|
+ try {
|
|
|
+ const response = await uploadOCRImage(file, warehouse)
|
|
|
+
|
|
|
+ closeToast()
|
|
|
+
|
|
|
+ if (response.code === 200) {
|
|
|
+ showNotify({ type: 'success', message: '面单上传成功' })
|
|
|
+ // 上传成功后重置表单
|
|
|
+ uploadImages.value = []
|
|
|
+ } else {
|
|
|
+ showNotify({ type: 'danger', message: response.message || '上传失败' })
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ closeToast()
|
|
|
+ showNotify({ type: 'danger', message: '识别过程发生异常: ' + (err.message || '未知错误') })
|
|
|
+ } finally {
|
|
|
+ uploading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
// 检查图片格式和大小
|
|
|
const beforeReadImage = (file) => {
|
|
|
@@ -124,6 +209,8 @@ const afterReadImage = async (file) => {
|
|
|
const originalFile = fileItem.file
|
|
|
|
|
|
if (originalFile) {
|
|
|
+ let finalFile = originalFile
|
|
|
+
|
|
|
// 检查文件大小,如果大于1MB则进行压缩
|
|
|
if (originalFile.size > 1 * 1024 * 1024) {
|
|
|
showNotify({
|
|
|
@@ -134,6 +221,7 @@ const afterReadImage = async (file) => {
|
|
|
try {
|
|
|
// 压缩图片到1MB以内
|
|
|
const compressedFile = await compressImage(originalFile, 1 * 1024 * 1024)
|
|
|
+ finalFile = compressedFile
|
|
|
|
|
|
// 更新文件对象
|
|
|
fileItem.file = compressedFile
|
|
|
@@ -156,6 +244,9 @@ const afterReadImage = async (file) => {
|
|
|
} else {
|
|
|
console.log(`图片大小符合要求,无需压缩: ${(originalFile.size / 1024).toFixed(2)}KB`)
|
|
|
}
|
|
|
+
|
|
|
+ // 压缩完成后自动上传
|
|
|
+ await autoUploadImage(finalFile)
|
|
|
}
|
|
|
}
|
|
|
} catch (error) {
|
|
|
@@ -167,51 +258,7 @@ const afterReadImage = async (file) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 提交OCR识别
|
|
|
-const submitOCR = async () => {
|
|
|
- if (!uploadImages.value.length) {
|
|
|
- showFailToast('请先选择图片')
|
|
|
- return
|
|
|
- }
|
|
|
|
|
|
- if (!warehouse) {
|
|
|
- showFailToast('未获取到仓库信息')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- // 检查图片大小是否超过2MB
|
|
|
- const image = uploadImages.value[0]
|
|
|
- if (image.file.size > 2 * 1024 * 1024) {
|
|
|
- showFailToast('图片大小不能超过2MB')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- uploading.value = true
|
|
|
- const toast = showLoadingToast('识别中...')
|
|
|
-
|
|
|
- try {
|
|
|
- const formData = new FormData()
|
|
|
- formData.append('file', image.file)
|
|
|
- formData.append('warehouse', warehouse)
|
|
|
-
|
|
|
- const response = await uploadOCRImage(image.file, warehouse)
|
|
|
-
|
|
|
- closeToast()
|
|
|
-
|
|
|
- if (response.code === 200) {
|
|
|
- showNotify({ type: 'success', message: '面单上传成功' })
|
|
|
- // 上传成功后重置表单
|
|
|
- uploadImages.value = []
|
|
|
- } else {
|
|
|
- showNotify({ type: 'danger', message: response.message || '上传失败' })
|
|
|
- }
|
|
|
- } catch (err) {
|
|
|
- closeToast()
|
|
|
- showNotify({ type: 'danger', message: '识别过程发生异常: ' + (err.message || '未知错误') })
|
|
|
- } finally {
|
|
|
- uploading.value = false
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -287,6 +334,53 @@ onMounted(() => {
|
|
|
text-align: center
|
|
|
background: rgba(0, 0, 0, 0.3)
|
|
|
|
|
|
+.camera-section
|
|
|
+ display: flex
|
|
|
+ flex-direction: column
|
|
|
+ align-items: center
|
|
|
+ margin-bottom: 20px
|
|
|
+
|
|
|
+.camera-button
|
|
|
+ width: 120px
|
|
|
+ height: 120px
|
|
|
+ border: 2px dashed #ccc
|
|
|
+ border-radius: 8px
|
|
|
+ display: flex
|
|
|
+ flex-direction: column
|
|
|
+ align-items: center
|
|
|
+ justify-content: center
|
|
|
+ cursor: pointer
|
|
|
+ transition: all 0.3s
|
|
|
+ background: #f8f8f8
|
|
|
+
|
|
|
+.camera-button:hover
|
|
|
+ border-color: #1989fa
|
|
|
+ background: #f0f8ff
|
|
|
+
|
|
|
+.camera-button:active
|
|
|
+ transform: scale(0.95)
|
|
|
+
|
|
|
+.camera-text
|
|
|
+ margin-top: 8px
|
|
|
+ font-size: 14px
|
|
|
+ color: #666
|
|
|
+
|
|
|
+.image-preview
|
|
|
+ display: flex
|
|
|
+ flex-direction: column
|
|
|
+ align-items: center
|
|
|
+ margin-bottom: 20px
|
|
|
+
|
|
|
+.preview-image
|
|
|
+ width: 200px
|
|
|
+ height: 200px
|
|
|
+ object-fit: cover
|
|
|
+ border-radius: 8px
|
|
|
+ margin-bottom: 10px
|
|
|
+
|
|
|
+.remove-btn
|
|
|
+ margin-top: 10px
|
|
|
+
|
|
|
:deep(.van-uploader__upload)
|
|
|
width: 100px
|
|
|
height: 100px
|