diff --git a/src/components/ImageRecognition.vue b/src/components/ImageRecognition.vue index 1d2c012..f285360 100644 --- a/src/components/ImageRecognition.vue +++ b/src/components/ImageRecognition.vue @@ -57,9 +57,11 @@
驿站:{{ station.name }}
-
- 取件码:{{ code }} - +
+
+ 取件码:{{ code }} + +
@@ -115,21 +117,28 @@ export default { if (!selectedFile.value || isRecognizing.value) return isRecognizing.value = true - recognitionStatus.value = 'AI 识别中...' + recognitionStatus.value = 'AI 识别中,请稍候...' statusClass.value = 'status-processing' try { const formData = new FormData() formData.append('file', selectedFile.value) + // 添加超时处理 + const controller = new AbortController() + const timeoutId = setTimeout(() => controller.abort(), 60000) // 60秒超时 + const response = await apiClient.post('/api/ai/extract_pickup_code', formData, { headers: { 'Content-Type': 'multipart/form-data' - } + }, + signal: controller.signal }) + clearTimeout(timeoutId) // 清除超时 + if (response.data && response.data.code === 200) { - recognitionResult.value = response.data.data + recognitionResult.value = processRecognitionData(response.data.data) recognitionStatus.value = '识别成功!' statusClass.value = 'status-success' } else { @@ -138,22 +147,77 @@ export default { } } catch (error) { console.error('识别失败:', error) - recognitionStatus.value = '识别失败,请重试' + + if (error.name === 'AbortError' || error.code === 'ECONNABORTED') { + recognitionStatus.value = '请求超时,请检查网络或稍后重试' + } else { + recognitionStatus.value = '识别失败,请重试' + } + statusClass.value = 'status-error' } finally { isRecognizing.value = false } } + // 处理识别数据 + const processRecognitionData = (data) => { + // 检查数据是否为数组格式 + if (Array.isArray(data)) { + // 从数组中获取第一个元素 + const firstItem = data[0] + + // 构建格式化文本 + let formattedText = '' + if (firstItem && firstItem.stations) { + firstItem.stations.forEach(station => { + formattedText += `驿站:${station.name}\n` + if (station.pickup_codes && station.pickup_codes.length > 0) { + station.pickup_codes.forEach(code => { + formattedText += `取件码:${code}\n` + }) + } + formattedText += '\n' + }) + } + + // 返回处理后的数据结构 + return { + raw: firstItem || { stations: [] }, + formatted_text: formattedText.trim() + } + } else { + // 如果不是数组格式,直接返回原始数据 + return data + } + } + // 复制到剪贴板 const copyToClipboard = (text) => { + const tempCopyStatus = recognitionStatus.value + const tempStatusClass = statusClass.value + navigator.clipboard.writeText(text) .then(() => { - alert('取件码已复制到剪贴板') + recognitionStatus.value = '取件码已复制到剪贴板' + statusClass.value = 'status-success' + + // 3秒后恢复原状态 + setTimeout(() => { + recognitionStatus.value = tempCopyStatus + statusClass.value = tempStatusClass + }, 3000) }) .catch(err => { console.error('复制失败:', err) - alert('复制失败,请手动复制') + recognitionStatus.value = '复制失败,请手动复制' + statusClass.value = 'status-error' + + // 3秒后恢复原状态 + setTimeout(() => { + recognitionStatus.value = tempCopyStatus + statusClass.value = tempStatusClass + }, 3000) }) } @@ -377,16 +441,24 @@ export default { } .station-item { - padding: 10px; + padding: 15px; background-color: #FFFFFF; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + margin-bottom: 15px; } .station-name { - font-weight: 500; + font-weight: 600; color: #333333; - margin-bottom: 8px; + margin-bottom: 12px; + font-size: 16px; +} + +.pickup-codes-container { + display: flex; + flex-direction: column; + gap: 8px; } .pickup-code { diff --git a/src/services/api.js b/src/services/api.js index 915d543..e5fa55a 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -4,7 +4,7 @@ import config from './config' // 创建 axios 实例 const apiClient = axios.create({ baseURL: config.API_URL, - timeout: 10000, // 请求超时时间 + timeout: 30000, // 增加到30秒 headers: { 'Content-Type': 'application/json' }