feat: 以图搜图集成拍照功能,支持直接调起摄像头搜图
This commit is contained in:
@ -33,6 +33,17 @@
|
||||
</div>
|
||||
</el-upload>
|
||||
|
||||
<!-- 拍照按钮 -->
|
||||
<el-button
|
||||
v-if="!previewUrl"
|
||||
type="primary"
|
||||
class="camera-btn"
|
||||
@click="openCamera"
|
||||
>
|
||||
<el-icon><VideoCamera /></el-icon>
|
||||
调起摄像头拍照
|
||||
</el-button>
|
||||
|
||||
<div v-if="searching" class="loading-tip">
|
||||
<el-icon class="is-loading"><Loading /></el-icon>
|
||||
<span>正在识别图片并检索...</span>
|
||||
@ -94,15 +105,33 @@
|
||||
<template #footer>
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 拍照弹窗 -->
|
||||
<el-dialog
|
||||
v-model="cameraVisible"
|
||||
title="拍照"
|
||||
width="95%"
|
||||
style="max-width: 480px; height: 80vh; padding: 0;"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@close="closeCamera"
|
||||
>
|
||||
<WebRtcCamera
|
||||
@cancel="closeCamera"
|
||||
@photo-submit="handleCameraSubmit"
|
||||
/>
|
||||
</el-dialog>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Camera, Loading, Picture, WarningFilled } from '@element-plus/icons-vue'
|
||||
import { Camera, Loading, Picture, WarningFilled, VideoCamera } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { imageSearch, type ImageSearchItem } from '@/api/common/upload'
|
||||
import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@ -126,6 +155,9 @@ const searching = ref(false)
|
||||
const searched = ref(false)
|
||||
const results = ref<ImageSearchItem[]>([])
|
||||
|
||||
// 拍照相关
|
||||
const cameraVisible = ref(false)
|
||||
|
||||
watch(() => props.modelValue, (val) => {
|
||||
visible.value = val
|
||||
if (!val) {
|
||||
@ -137,6 +169,27 @@ watch(visible, (val) => {
|
||||
emit('update:modelValue', val)
|
||||
})
|
||||
|
||||
// 拍照相关方法
|
||||
const openCamera = () => {
|
||||
cameraVisible.value = true
|
||||
}
|
||||
|
||||
const closeCamera = () => {
|
||||
cameraVisible.value = false
|
||||
}
|
||||
|
||||
const handleCameraSubmit = (file: File) => {
|
||||
// 关闭拍照弹窗
|
||||
closeCamera()
|
||||
|
||||
// 生成预览
|
||||
currentFile.value = file
|
||||
previewUrl.value = URL.createObjectURL(file)
|
||||
|
||||
// 立即触发搜图
|
||||
doSearch(file)
|
||||
}
|
||||
|
||||
const handleFileChange = (uploadFile: any) => {
|
||||
const file = uploadFile.raw
|
||||
if (!file) return
|
||||
@ -179,6 +232,9 @@ const doSearch = async (file: File) => {
|
||||
}
|
||||
|
||||
const clearImage = () => {
|
||||
if (previewUrl.value) {
|
||||
URL.revokeObjectURL(previewUrl.value)
|
||||
}
|
||||
previewUrl.value = ''
|
||||
currentFile.value = null
|
||||
results.value = []
|
||||
@ -188,7 +244,6 @@ const clearImage = () => {
|
||||
|
||||
const fullImageUrl = (path: string) => {
|
||||
if (!path) return '';
|
||||
// 直接原样返回,完全信任后端传过来的 image_url
|
||||
return path.startsWith('http') ? path : path;
|
||||
}
|
||||
|
||||
@ -219,6 +274,9 @@ const handleClose = () => {
|
||||
}
|
||||
|
||||
const resetState = () => {
|
||||
if (previewUrl.value) {
|
||||
URL.revokeObjectURL(previewUrl.value)
|
||||
}
|
||||
previewUrl.value = ''
|
||||
currentFile.value = null
|
||||
searching.value = false
|
||||
@ -234,6 +292,12 @@ const resetState = () => {
|
||||
min-height: 380px;
|
||||
}
|
||||
|
||||
/* 拍照按钮 */
|
||||
.camera-btn {
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* ── 左侧上传区 ── */
|
||||
.upload-section {
|
||||
flex: 0 0 220px;
|
||||
|
||||
Reference in New Issue
Block a user