Appearance
实现 拍照计数 工具
分类:retirement | 标签:拍照、计数、AI识别 智能拍照识别计数工具,支持物品自动计数
2.1 功能说明
智能拍照识别计数工具,支持物品自动计数
2.2 代码实现
2.2.1 组件结构
本工具是一个基于 Vue 3 <script setup> 语法的单文件组件(SFC),统一包裹在 ToolPageShell 组件内,由它提供页面标题、工具 ID、分类与「使用指南」插槽等通用外壳;核心业务逻辑(响应式状态、计算属性、事件处理函数)全部写在 <script setup> 中,输入/输出通过 el-input、el-button 等 Element Plus 组件与用户交互,所有数据均在浏览器本地处理,不会上传服务器。
2.2.2 核心逻辑概览
<script setup> 中定义的主要函数/方法:
handleFileSelect()handleCameraCapture()loadImage()handleDetect()handleImageLoad()zoomIn()zoomOut()resetZoom()goBack()
2.2.3 关键实现代码
以下是该工具的完整 <script setup> 实现(核心代码)。模板(<template>)与样式(<style>)已省略。
vue
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import {
Picture,
Camera,
Search,
View,
ZoomIn,
ZoomOut,
RefreshRight,
InfoFilled,
ArrowLeft
} from '@element-plus/icons-vue'
import { BeanCounterApi } from '@/api/BeanCounterApi'
import FeedbackForm from '@/components/FeedbackForm.vue'
const router = useRouter()
// 状态管理
const fileInputRef = ref(null)
const cameraInputRef = ref(null)
const imageWrapperRef = ref(null)
const previewUrl = ref(null)
const count = ref(null)
const isDetecting = ref(false)
const currentScale = ref(1)
const currentSource = ref(null)
const selectedFile = ref(null) // 保存当前选择的文件
const activeTab = ref('counter') // Tab页签状态,默认显示拍照计数
// 计算属性
const hasImage = computed(() => !!previewUrl.value)
// 处理文件选择
const handleFileSelect = (event) => {
const file = event.target.files?.[0]
if (file) {
currentSource.value = 'file'
selectedFile.value = file // 保存文件引用
loadImage(file)
}
}
// 处理相机拍摄
const handleCameraCapture = (event) => {
const file = event.target.files?.[0]
if (file) {
currentSource.value = 'camera'
selectedFile.value = file // 保存文件引用
loadImage(file)
}
}
// 加载图片
const loadImage = (file) => {
// 验证文件类型
if (!file.type.startsWith('image/')) {
ElMessage.error('请选择图片文件')
return
}
// 验证文件大小(限制为10MB)
if (file.size > 10 * 1024 * 1024) {
ElMessage.error('图片大小不能超过10MB')
return
}
const reader = new FileReader()
reader.onload = (e) => {
previewUrl.value = e.target.result
count.value = null
resetZoom()
ElMessage.success('图片加载成功')
}
reader.onerror = () => {
ElMessage.error('图片加载失败')
}
reader.readAsDataURL(file)
}
// 开始检测
const handleDetect = async () => {
if (!selectedFile.value) {
ElMessage.warning('请先选择或拍摄图片')
return
}
isDetecting.value = true
count.value = null
try {
// 调用实际的检测API
const response = await BeanCounterApi.upload(selectedFile.value)
// 处理返回结果(response 已经是 {count, result_img} 对象)
if (response && response.count !== undefined) {
count.value = response.count
// 如果有返回标注后的图片,则显示
if (response.result_img) {
previewUrl.value = 'data:image/png;base64,' + response.result_img
}
ElMessage.success(`检测完成,共识别到 ${count.value} 个物品`)
} else {
throw new Error('响应数据格式错误')
}
} catch (error) {
console.error('检测失败:', error)
ElMessage.error(error.msg || error.message || '检测失败,请稍后重试')
count.value = 0
} finally {
isDetecting.value = false
}
}
// 图片加载完成
const handleImageLoad = () => {
console.log('图片加载完成')
}
// 缩放控制
const zoomIn = () => {
currentScale.value = Math.min(currentScale.value * 1.2, 5)
}
const zoomOut = () => {
currentScale.value = Math.max(currentScale.value / 1.2, 0.1)
}
const resetZoom = () => {
currentScale.value = 1
}
// 返回板块列表
const goBack = () => {
router.push('/education')
}2.3 效果截图
暂未生成该工具的效果截图。