OCR盘点入库
This commit is contained in:
parent
18a8c1faa5
commit
8bae76a0d6
|
|
@ -0,0 +1,814 @@
|
||||||
|
<template>
|
||||||
|
<!-- 相机预览页面 -->
|
||||||
|
<view v-if="showCamera" class="camera-container">
|
||||||
|
<!-- 顶部提示 -->
|
||||||
|
<view class="top-tip" style="color: red; text-align: center; margin-top: 30px">
|
||||||
|
<text class="tip-text">请将识别编码置于取景框内,完成扫描</text>
|
||||||
|
</view>
|
||||||
|
<!-- 取景框 -->
|
||||||
|
<view class="viewfinder-container"> </view>
|
||||||
|
|
||||||
|
<!-- 底部控制区 -->
|
||||||
|
<view class="bottom-controls">
|
||||||
|
<view class="control-btn" @click="closeCamera">
|
||||||
|
<text class="control-icon">✕</text>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="photo-btn"
|
||||||
|
@click="takePicture"
|
||||||
|
:class="{ taking: isTaking, disabled: isFocusing }"
|
||||||
|
>
|
||||||
|
<view class="photo-btn-inner"></view>
|
||||||
|
</view>
|
||||||
|
<view class="control-btn" @click="openGallery">
|
||||||
|
<text class="control-icon">📷</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 加载提示 -->
|
||||||
|
<view v-if="isProcessing" class="loading-overlay">
|
||||||
|
<view class="loading-content">
|
||||||
|
<view class="loading-spinner"></view>
|
||||||
|
<text class="loading-text">正在识别中...</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="custom-toast"
|
||||||
|
:class="{ show: isShow, top: position === 'top', bottom: position === 'bottom' }"
|
||||||
|
ref="toast"
|
||||||
|
>
|
||||||
|
{{ message }}
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { decryptWithSM4 } from '@/utils/sm'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
jiJuType: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showCamera: false,
|
||||||
|
isTaking: false,
|
||||||
|
isProcessing: false,
|
||||||
|
cameraStarted: false,
|
||||||
|
cameraReady: false,
|
||||||
|
deviceReadyTimeout: null,
|
||||||
|
pluginCheckRetries: 0,
|
||||||
|
maxRetries: 5,
|
||||||
|
// 聚焦相关状态
|
||||||
|
isFocusing: false,
|
||||||
|
focusSuccess: false,
|
||||||
|
showFocusIndicator: false,
|
||||||
|
focusIndicatorStyle: {},
|
||||||
|
autoFocusEnabled: true,
|
||||||
|
focusTimeout: null,
|
||||||
|
// 设备信息
|
||||||
|
systemInfo: null,
|
||||||
|
isOverToday: false,
|
||||||
|
isShow: false,
|
||||||
|
message: '',
|
||||||
|
position: 'bottom',
|
||||||
|
screenHeight: null,
|
||||||
|
screenWidth: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onBackPress(options) {
|
||||||
|
console.log('进了-----')
|
||||||
|
// 相机打开时处理返回事件
|
||||||
|
if (this.showCamera) {
|
||||||
|
console.log('关闭相机...')
|
||||||
|
try {
|
||||||
|
this.stopCamera()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('关闭相机出错:', error)
|
||||||
|
} finally {
|
||||||
|
this.showCamera = false
|
||||||
|
this.cameraStarted = false
|
||||||
|
this.resetFocusState()
|
||||||
|
}
|
||||||
|
return true // 阻止默认返回行为
|
||||||
|
}
|
||||||
|
// 其他情况下允许默认返回
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
this.initializeCordova()
|
||||||
|
// 获取设备信息用于相机配置
|
||||||
|
this.getDeviceInfo()
|
||||||
|
},
|
||||||
|
onHide() {
|
||||||
|
this.cleanup()
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.cleanup()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
show(message, position = 'top', duration = 2000) {
|
||||||
|
this.message = message
|
||||||
|
this.position = position
|
||||||
|
this.isShow = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.isShow = false
|
||||||
|
}, duration)
|
||||||
|
},
|
||||||
|
// 获取设备信息
|
||||||
|
getDeviceInfo() {
|
||||||
|
try {
|
||||||
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
|
console.log('设备信息:', systemInfo)
|
||||||
|
this.systemInfo = systemInfo
|
||||||
|
// 获取屏幕高度和宽度
|
||||||
|
const screenHeight = systemInfo.screenHeight // 屏幕高度:1000
|
||||||
|
const screenWidth = systemInfo.screenWidth // 屏幕宽度:600
|
||||||
|
this.screenHeight = screenHeight
|
||||||
|
this.screenWidth = screenWidth
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取设备信息失败:', error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 初始化Cordova - 改进版本
|
||||||
|
initializeCordova() {
|
||||||
|
console.log('开始初始化Cordova...')
|
||||||
|
this.pluginCheckRetries = 0
|
||||||
|
// 清除之前的超时
|
||||||
|
if (this.deviceReadyTimeout) {
|
||||||
|
clearTimeout(this.deviceReadyTimeout)
|
||||||
|
}
|
||||||
|
// 如果Cordova已经准备好,直接检查插件
|
||||||
|
if (this.isCordovaReady()) {
|
||||||
|
this.onDeviceReady()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 监听deviceready事件
|
||||||
|
document.addEventListener('deviceready', this.onDeviceReady, false)
|
||||||
|
// 设置超时,防止无限等待
|
||||||
|
this.deviceReadyTimeout = setTimeout(() => {
|
||||||
|
console.warn('Cordova初始化超时,尝试直接检查插件')
|
||||||
|
this.checkCameraPlugin()
|
||||||
|
}, 5000)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 检查Cordova是否准备好
|
||||||
|
isCordovaReady() {
|
||||||
|
return !!(window.cordova && (document.readyState === 'complete' || window.cordova.platformId))
|
||||||
|
},
|
||||||
|
|
||||||
|
// 设备准备就绪
|
||||||
|
onDeviceReady() {
|
||||||
|
console.log('Cordova设备准备就绪')
|
||||||
|
// 清除超时
|
||||||
|
if (this.deviceReadyTimeout) {
|
||||||
|
clearTimeout(this.deviceReadyTimeout)
|
||||||
|
this.deviceReadyTimeout = null
|
||||||
|
}
|
||||||
|
// 移除事件监听器,避免重复调用
|
||||||
|
document.removeEventListener('deviceready', this.onDeviceReady)
|
||||||
|
// 检查相机插件
|
||||||
|
this.checkCameraPlugin()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 检查相机插件 - 改进版本
|
||||||
|
checkCameraPlugin() {
|
||||||
|
console.log(`检查相机插件... (尝试 ${this.pluginCheckRetries + 1}/${this.maxRetries})`)
|
||||||
|
// 按优先级检查插件可用性
|
||||||
|
const pluginAvailable = this.getCameraPlugin()
|
||||||
|
if (pluginAvailable) {
|
||||||
|
console.log('相机插件可用:', pluginAvailable)
|
||||||
|
this.cameraReady = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.pluginCheckRetries++
|
||||||
|
if (this.pluginCheckRetries < this.maxRetries) {
|
||||||
|
// 递增延迟重试
|
||||||
|
const delay = Math.min(1000 * this.pluginCheckRetries, 5000)
|
||||||
|
console.log(`插件未就绪,${delay}ms后重试...`)
|
||||||
|
setTimeout(() => {
|
||||||
|
this.checkCameraPlugin()
|
||||||
|
}, delay)
|
||||||
|
} else {
|
||||||
|
console.error('相机插件检查失败,已达到最大重试次数')
|
||||||
|
this.cameraReady = false
|
||||||
|
uni.showToast({
|
||||||
|
title: '相机插件初始化失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 3000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取相机插件引用 - 改进版本
|
||||||
|
getCameraPlugin() {
|
||||||
|
// 按照插件注册的实际路径检查
|
||||||
|
const possiblePaths = [
|
||||||
|
() => window.CameraPreview, // 全局注册的路径
|
||||||
|
]
|
||||||
|
for (let getPlugin of possiblePaths) {
|
||||||
|
try {
|
||||||
|
const plugin = getPlugin()
|
||||||
|
if (plugin && typeof plugin.startCamera === 'function') {
|
||||||
|
console.log('找到相机插件:', plugin)
|
||||||
|
return plugin
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 忽略访问错误,继续尝试下一个路径
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
|
||||||
|
// 打开相机 - 改进版本
|
||||||
|
async openCamera() {
|
||||||
|
console.log('尝试打开相机...')
|
||||||
|
console.log('🚀 ~ jiJuType:', this.jiJuType)
|
||||||
|
// this.$emit('getMaCode', 'W202509-0001')
|
||||||
|
if (!this.cameraReady) {
|
||||||
|
// 再次尝试检查插件
|
||||||
|
this.checkCameraPlugin()
|
||||||
|
if (!this.cameraReady) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '相机插件未准备好,请确保应用已正确安装相机插件,或尝试重启应用',
|
||||||
|
showCancel: false,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 显示相机界面
|
||||||
|
this.showCamera = true
|
||||||
|
// 等待UI更新
|
||||||
|
await this.$nextTick()
|
||||||
|
// 初始化相机
|
||||||
|
await this.initCamera()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('打开相机失败:', error)
|
||||||
|
this.showCamera = false
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || '打开相机失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 初始化相机 - 关键修改
|
||||||
|
// 初始化相机 - 调整坐标计算
|
||||||
|
async initCamera() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const CameraPreview = this.getCameraPlugin()
|
||||||
|
if (!CameraPreview) {
|
||||||
|
reject(new Error('相机插件不可用'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取整个相机包装器的尺寸
|
||||||
|
const cameraWrapper = document.querySelector('.viewfinder-container')
|
||||||
|
if (!cameraWrapper) {
|
||||||
|
reject(new Error('找不到相机容器'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const rect = cameraWrapper.getBoundingClientRect()
|
||||||
|
const options = {
|
||||||
|
x: rect.left,
|
||||||
|
y: rect.top,
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
camera: CameraPreview.CAMERA_DIRECTION?.BACK || 'back',
|
||||||
|
tapPhoto: false,
|
||||||
|
previewDrag: false,
|
||||||
|
toBack: false, // 确保相机在WebView上层
|
||||||
|
alpha: 1,
|
||||||
|
tapFocus: true,
|
||||||
|
disableExifHeaderStripping: false,
|
||||||
|
}
|
||||||
|
console.log('相机配置:', options)
|
||||||
|
CameraPreview.startCamera(
|
||||||
|
options,
|
||||||
|
(result) => {
|
||||||
|
console.log('相机启动成功:', result)
|
||||||
|
this.cameraStarted = true
|
||||||
|
resolve()
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error('相机启动失败:', error)
|
||||||
|
this.cameraStarted = false
|
||||||
|
reject(new Error(`相机启动失败: ${error}`))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 点击聚焦
|
||||||
|
tapToFocus(x, y) {
|
||||||
|
const CameraPreview = this.getCameraPlugin()
|
||||||
|
if (CameraPreview && this.cameraStarted) {
|
||||||
|
CameraPreview.tapToFocus(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
() => console.log('聚焦成功'),
|
||||||
|
(error) => console.error('聚焦失败', error),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 关闭相机
|
||||||
|
async closeCamera() {
|
||||||
|
console.log('关闭相机...')
|
||||||
|
try {
|
||||||
|
await this.stopCamera()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('关闭相机出错:', error)
|
||||||
|
} finally {
|
||||||
|
this.showCamera = false
|
||||||
|
this.cameraStarted = false
|
||||||
|
this.resetFocusState()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 重置聚焦状态
|
||||||
|
resetFocusState() {
|
||||||
|
this.isFocusing = false
|
||||||
|
this.focusSuccess = false
|
||||||
|
this.showFocusIndicator = false
|
||||||
|
if (this.focusTimeout) {
|
||||||
|
clearTimeout(this.focusTimeout)
|
||||||
|
this.focusTimeout = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 停止相机
|
||||||
|
async stopCamera() {
|
||||||
|
if (!this.cameraStarted) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
const CameraPreview = this.getCameraPlugin()
|
||||||
|
if (!CameraPreview) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
CameraPreview.stopCamera(
|
||||||
|
() => {
|
||||||
|
console.log('相机已停止')
|
||||||
|
this.cameraStarted = false
|
||||||
|
resolve()
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error('停止相机失败:', error)
|
||||||
|
this.cameraStarted = false
|
||||||
|
resolve() // 即使失败也继续
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 拍照 - 添加聚焦逻辑
|
||||||
|
async takePicture() {
|
||||||
|
if (!this.cameraStarted || this.isTaking || this.isFocusing) {
|
||||||
|
if (this.isFocusing) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '正在聚焦,请稍候...',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 1000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('开始拍照流程...')
|
||||||
|
this.isTaking = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const CameraPreview = this.getCameraPlugin()
|
||||||
|
if (!CameraPreview) {
|
||||||
|
throw new Error('相机插件不可用')
|
||||||
|
}
|
||||||
|
// 拍照前先进行聚焦
|
||||||
|
console.log('拍照前聚焦...')
|
||||||
|
console.log('开始拍照...')
|
||||||
|
CameraPreview.takePicture(
|
||||||
|
{ width: this.screenWidth, height: this.screenHeight, quality: 50 },
|
||||||
|
async (base64PictureData) => {
|
||||||
|
console.log('拍照返回数据', base64PictureData)
|
||||||
|
await this.processImage(base64PictureData)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('拍照过程出错:', error)
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || '拍照失败',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
this.isTaking = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改后的方法
|
||||||
|
removeExifData(pureBase64) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image()
|
||||||
|
img.onload = () => {
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
|
||||||
|
canvas.width = img.width
|
||||||
|
canvas.height = img.height
|
||||||
|
ctx.drawImage(img, 0, 0)
|
||||||
|
|
||||||
|
// 转换为dataURL然后提取纯base64部分
|
||||||
|
const dataUrl = canvas.toDataURL('image/jpeg', 0.8)
|
||||||
|
const cleanPureBase64 = dataUrl.split(',')[1] // 去掉前缀
|
||||||
|
resolve(cleanPureBase64)
|
||||||
|
}
|
||||||
|
|
||||||
|
img.onerror = () => reject(new Error('图像加载失败'))
|
||||||
|
|
||||||
|
// 临时添加前缀用于加载
|
||||||
|
img.src = `data:image/jpeg;base64,${pureBase64}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理图片
|
||||||
|
async processImage(imageData) {
|
||||||
|
this.isProcessing = true
|
||||||
|
try {
|
||||||
|
// base64PictureData 是纯base64(无前缀)
|
||||||
|
const cleanBase64 = await this.removeExifData(imageData)
|
||||||
|
// cleanBase64 也是纯base64(无前缀)
|
||||||
|
|
||||||
|
console.log('清理后的纯base64:', cleanBase64)
|
||||||
|
console.log('开始OCR识别...')
|
||||||
|
|
||||||
|
uni.request({
|
||||||
|
url:
|
||||||
|
this.jiJuType == 2 ? '/material/app/ocr/getOcrCode' : '/material/app/ocr/getOcrCodeTwo',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
image: cleanBase64,
|
||||||
|
jiju_type: '',
|
||||||
|
auth_lic:
|
||||||
|
'xIWDlaDVdijcBB4mjhGCPYk5Kvk8tHZJbUn+vW+ih15+MYx98e/PXyBmKL5gFcWMPznLgDA15QuSAnZQSLddwdy9HkZgtuQDEEZZ351Eyb1eiDUccUnyoSGIrNimbx5TooBNNPYqU4qJeFrPJXAqjBHzRrxoBxuR2CEGKQPgHC4=',
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/json;charset=UTF-8',
|
||||||
|
},
|
||||||
|
success: async (res) => {
|
||||||
|
if (!res.data.code) {
|
||||||
|
res = JSON.parse(decryptWithSM4(res.data))
|
||||||
|
} else {
|
||||||
|
res = res.data
|
||||||
|
}
|
||||||
|
const { data: resData } = res
|
||||||
|
if (resData.code === 0) {
|
||||||
|
if (resData.data.result) {
|
||||||
|
this.$emit('getMaCode', resData.data.result)
|
||||||
|
await this.closeCamera()
|
||||||
|
await uni.showToast({
|
||||||
|
title: '识别成功',
|
||||||
|
icon: 'success',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('识别失败!' + resData.data.msg)
|
||||||
|
this.show('识别失败!', 'bottom')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.show('识别失败!', 'bottom')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
this.$refs.toast.show('请求失败!', 'bottom')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('图片处理或OCR识别失败:', error)
|
||||||
|
uni.showToast({
|
||||||
|
title: '识别失败,请重试',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
this.isProcessing = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 打开相册
|
||||||
|
openGallery() {
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 1,
|
||||||
|
sourceType: ['album'],
|
||||||
|
success: (res) => {
|
||||||
|
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
|
||||||
|
const filePath = res.tempFilePaths[0]
|
||||||
|
|
||||||
|
// 统一使用XMLHttpRequest处理
|
||||||
|
const xhr = new XMLHttpRequest()
|
||||||
|
xhr.open('GET', filePath, true)
|
||||||
|
xhr.responseType = 'blob'
|
||||||
|
xhr.onload = () => {
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
const blob = xhr.response
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = (e) => {
|
||||||
|
const base64 = e.target.result.split(',')[1]
|
||||||
|
this.convertImageToBase64(base64)
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(blob)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.send()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (error) => {
|
||||||
|
console.error('选择图片失败:', error)
|
||||||
|
uni.showToast({
|
||||||
|
title: '选择图片失败',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 将图片转换为base64
|
||||||
|
async convertImageToBase64(processedBase64) {
|
||||||
|
this.isProcessing = true
|
||||||
|
try {
|
||||||
|
console.log('相册base64数据', processedBase64)
|
||||||
|
console.log('开始OCR识别...')
|
||||||
|
|
||||||
|
uni.request({
|
||||||
|
url:
|
||||||
|
this.jiJuType == 2 ? '/material/app/ocr/getOcrCode' : '/material/app/ocr/getOcrCodeTwo',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
image: processedBase64,
|
||||||
|
jiju_type: '',
|
||||||
|
auth_lic:
|
||||||
|
'xIWDlaDVdijcBB4mjhGCPYk5Kvk8tHZJbUn+vW+ih15+MYx98e/PXyBmKL5gFcWMPznLgDA15QuSAnZQSLddwdy9HkZgtuQDEEZZ351Eyb1eiDUccUnyoSGIrNimbx5TooBNNPYqU4qJeFrPJXAqjBHzRrxoBxuR2CEGKQPgHC4=',
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/json;charset=UTF-8',
|
||||||
|
},
|
||||||
|
success: async (res) => {
|
||||||
|
if (!res.data.code) {
|
||||||
|
res = JSON.parse(decryptWithSM4(res.data))
|
||||||
|
} else {
|
||||||
|
res = res.data
|
||||||
|
}
|
||||||
|
console.log('res.data', res.data)
|
||||||
|
const { data: resData } = res
|
||||||
|
console.log('resData', resData)
|
||||||
|
console.log('resData.data.result', resData.data.result)
|
||||||
|
|
||||||
|
if (resData.code === 0) {
|
||||||
|
if (resData.data.result) {
|
||||||
|
this.$emit('getMaCode', resData.data.result)
|
||||||
|
await this.closeCamera()
|
||||||
|
await uni.showToast({
|
||||||
|
title: '识别成功',
|
||||||
|
icon: 'success',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.show('识别失败!', 'bottom')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.show('识别失败!', 'bottom')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请求失败:' + err.errMsg,
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('相册图片处理或OCR识别失败:', error)
|
||||||
|
this.show('识别失败!', 'bottom')
|
||||||
|
} finally {
|
||||||
|
this.isProcessing = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 清理资源
|
||||||
|
cleanup() {
|
||||||
|
console.log('清理资源...')
|
||||||
|
if (this.cameraStarted) {
|
||||||
|
const CameraPreview = this.getCameraPlugin()
|
||||||
|
if (CameraPreview) {
|
||||||
|
CameraPreview.stopCamera()
|
||||||
|
}
|
||||||
|
this.cameraStarted = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除超时
|
||||||
|
if (this.deviceReadyTimeout) {
|
||||||
|
clearTimeout(this.deviceReadyTimeout)
|
||||||
|
this.deviceReadyTimeout = null
|
||||||
|
}
|
||||||
|
if (this.focusTimeout) {
|
||||||
|
clearTimeout(this.focusTimeout)
|
||||||
|
this.focusTimeout = null
|
||||||
|
}
|
||||||
|
// 移除事件监听
|
||||||
|
document.removeEventListener('deviceready', this.onDeviceReady)
|
||||||
|
// 停止相机
|
||||||
|
if (this.cameraStarted) {
|
||||||
|
this.stopCamera().catch(console.error)
|
||||||
|
}
|
||||||
|
// 重置聚焦状态
|
||||||
|
this.resetFocusState()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.custom-toast {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 9999;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
.custom-toast.top {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.custom-toast.bottom {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.custom-toast.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-container {
|
||||||
|
display: flex;
|
||||||
|
height: auto;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #f7f8fa;
|
||||||
|
padding: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-list-item {
|
||||||
|
background: #fff;
|
||||||
|
padding: 32rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-btn {
|
||||||
|
height: 88rpx;
|
||||||
|
background: #4b8eff;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
box-shadow: 0 6rpx 20rpx rgba(55, 132, 251, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coding-btn {
|
||||||
|
padding: 10rpx 0;
|
||||||
|
color: #fe9a09;
|
||||||
|
background-color: #fff7eb;
|
||||||
|
border: 1px solid #fe9a09;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 控制按钮区域 - 需要单独设置可点击 */
|
||||||
|
.bottom-controls {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100rpx;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around; /* 改为space-around使按钮分布更均匀 */
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 60rpx; /* 添加左右内边距 */
|
||||||
|
z-index: 3;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
.control-btn {
|
||||||
|
width: 100rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: 2rpx solid rgba(255, 255, 255, 0.3);
|
||||||
|
margin: 0 20rpx; /* 添加按钮间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-icon {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-btn {
|
||||||
|
width: 140rpx;
|
||||||
|
height: 140rpx;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: 6rpx solid rgba(255, 255, 255, 0.5);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
margin: 0 20rpx; /* 添加按钮间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-btn.taking {
|
||||||
|
transform: scale(0.9);
|
||||||
|
background-color: rgba(75, 142, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-btn.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-btn-inner {
|
||||||
|
width: 100rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-btn.taking .photo-btn-inner {
|
||||||
|
background-color: #4b8eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-btn.disabled .photo-btn-inner {
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载层 */
|
||||||
|
.loading-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 100; /* 加载层在最高层 */
|
||||||
|
pointer-events: auto; /* 阻止底层交互 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
padding: 60rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
border: 6rpx solid #f3f3f3;
|
||||||
|
border-top: 6rpx solid #4b8eff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
color: #333;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewfinder-container {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 40%;
|
||||||
|
margin-top: 150px;
|
||||||
|
z-index: 10001; /* 提高取景框层级 */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -805,6 +805,18 @@
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/inStorage/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "OCR盘点入库"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/inStorage/details",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "OCR盘点入库"
|
||||||
|
}
|
||||||
|
},
|
||||||
// 材料站 start
|
// 材料站 start
|
||||||
// 首页
|
// 首页
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,253 @@
|
||||||
|
<template>
|
||||||
|
<div class="card">
|
||||||
|
<uni-forms :model="formData" label-width="180rpx" :border="true">
|
||||||
|
<uni-forms-item label="设备编码:" name="maCode" required>
|
||||||
|
<uni-easyinput v-model="formData.maCode" placeholder="请输入内容" />
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="物资名称:" name="typeModelId" required>
|
||||||
|
<eselect
|
||||||
|
ref="treeSelect"
|
||||||
|
:detailValue="formData.typeModelName"
|
||||||
|
:options="typeModelList"
|
||||||
|
@change="changeTypeModel"
|
||||||
|
@clear="clearTypeModel"
|
||||||
|
style="width: 100%; height: 90rpx"
|
||||||
|
></eselect>
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="规格型号:" name="typeId" required>
|
||||||
|
<uni-data-select
|
||||||
|
v-model="formData.typeId"
|
||||||
|
:localdata="typeList"
|
||||||
|
placeholder="请选择规格型号"
|
||||||
|
@change="changeType"
|
||||||
|
></uni-data-select>
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="物资厂家:" name="supplierId">
|
||||||
|
<uni-data-select
|
||||||
|
v-model="formData.supplierId"
|
||||||
|
:localdata="supplierList"
|
||||||
|
placeholder="请选择机具厂家"
|
||||||
|
@change="handleSupplierChange"
|
||||||
|
></uni-data-select>
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="出厂时间:" name="outFacTime">
|
||||||
|
<uni-datetime-picker
|
||||||
|
type="date"
|
||||||
|
v-model="formData.outFacTime"
|
||||||
|
:end="new Date().toISOString().split('T')[0]"
|
||||||
|
@change="handleOutFacTimeChange"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item></uni-forms-item>
|
||||||
|
</uni-forms>
|
||||||
|
|
||||||
|
<div style="margin: 90px 0 30px; display: flex">
|
||||||
|
<button type="" style="width: 45%" @click="handleOpenOcr">重新识别</button>
|
||||||
|
<button type="primary" style="width: 45%" @click="submit">入 库</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<OcrSearch ref="ocrSearch" @getMaCode="getMaCode" :jiJuType="formData.jiJuType" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import eselect from '@/components/tree-select/eselect.vue'
|
||||||
|
import OcrSearch from '@/components/OcrSearch/index.vue'
|
||||||
|
import { getDeviceTypeTreeApi, getTypeListApi, addMaMachineApi } from '@/services/inStorage'
|
||||||
|
import { getSupplierList } from '@/services/information'
|
||||||
|
|
||||||
|
const ocrSearch = ref(null)
|
||||||
|
const opts = ref({})
|
||||||
|
const formData = reactive({
|
||||||
|
maCode: '',
|
||||||
|
typeModelId: '',
|
||||||
|
typeModelName: '',
|
||||||
|
typeId: '',
|
||||||
|
typeName: '',
|
||||||
|
supplierId: '',
|
||||||
|
outFacTime: '',
|
||||||
|
jiJuType: null,
|
||||||
|
})
|
||||||
|
const typeModelList = ref([])
|
||||||
|
const typeList = ref([])
|
||||||
|
const supplierList = ref([])
|
||||||
|
const isSubmit = ref(false)
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
getTypeModelList()
|
||||||
|
opts.value = options.params ? JSON.parse(options.params) : {}
|
||||||
|
console.log('🚀 ~ opts.value:', opts.value)
|
||||||
|
formData.typeId = opts.value.typeId
|
||||||
|
formData.typeModelId = opts.value.typeModelId
|
||||||
|
formData.typeModelName = opts.value.typeModelName
|
||||||
|
formData.jiJuType = opts.value.jiJuType
|
||||||
|
|
||||||
|
if (formData.typeModelId) {
|
||||||
|
getTypeList()
|
||||||
|
}
|
||||||
|
console.log('🚀 ~ formData:', formData)
|
||||||
|
setTimeout(() => {
|
||||||
|
handleOpenOcr()
|
||||||
|
}, 400)
|
||||||
|
fetchSuppliers()
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleOpenOcr = () => {
|
||||||
|
if (!formData.typeId) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请先选择设备类型',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ocrSearch.value.openCamera()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMaCode = (code) => {
|
||||||
|
console.log('🚀 ~ getMaCode ~ code:', code)
|
||||||
|
formData.maCode = code
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTypeModelList = async () => {
|
||||||
|
try {
|
||||||
|
uni.showLoading({ title: '加载中...', mask: true })
|
||||||
|
const res = await getDeviceTypeTreeApi({ level: 3 })
|
||||||
|
console.log('🚀 ~ getDeviceTypeTreeApi ~ res:', res)
|
||||||
|
if (!res.data) return
|
||||||
|
typeModelList.value = transformTree(res.data)
|
||||||
|
console.log('🚀 ~ getTypeModelList ~ typeModelList.value:', typeModelList.value)
|
||||||
|
} catch (error) {
|
||||||
|
console.log('🚀 ~ getTypeModelList ~ error:', error)
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归循环
|
||||||
|
const transformTree = (list) => {
|
||||||
|
return list.map((node) => {
|
||||||
|
const newNode = {
|
||||||
|
...node,
|
||||||
|
name: node.label,
|
||||||
|
}
|
||||||
|
if (Array.isArray(node.children) && node.children.length > 0) {
|
||||||
|
newNode.children = transformTree(node.children)
|
||||||
|
}
|
||||||
|
return newNode
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTypeList = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getTypeListApi({ typeId: formData.typeModelId })
|
||||||
|
console.log('🚀 ~ getTypeList ~ res:', res)
|
||||||
|
if (!res.data) return
|
||||||
|
typeList.value = res.data.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
text: item.typeName,
|
||||||
|
value: item.typeId,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log('🚀 ~ getTypeList ~ error:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeTypeModel = (e) => {
|
||||||
|
console.log('🚀 ~ changeTypeModel ~ e:', e, formData)
|
||||||
|
formData.typeModelId = e.id
|
||||||
|
formData.typeModelName = e.name
|
||||||
|
getTypeList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeType = (e) => {
|
||||||
|
console.log('🚀 ~ changeType ~ e:', e, formData)
|
||||||
|
if (!e) return
|
||||||
|
formData.jiJuType = typeList.value.find((item) => item.typeId == e).jiJuType
|
||||||
|
console.log('🚀 ~ changeType ~ jiJuType.value:', formData)
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearTypeModel = () => {
|
||||||
|
formData.typeId = ''
|
||||||
|
formData.typeName = ''
|
||||||
|
formData.typeModelId = ''
|
||||||
|
formData.typeModelName = ''
|
||||||
|
typeList.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSuppliers = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getSupplierList({ pageNum: 1, pageSize: 99999 })
|
||||||
|
if (res.code === 200) {
|
||||||
|
supplierList.value = res.rows.map((item) => ({
|
||||||
|
value: item.supplierId,
|
||||||
|
text: item.supplier,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取供应商列表失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSupplierChange = (value) => {
|
||||||
|
console.log('🚀 ~ handleSupplierChange ~ value:', value)
|
||||||
|
console.log('🚀 ~ handleSupplierChange ~ formData:', formData)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOutFacTimeChange = (date) => {
|
||||||
|
formData.outFacTime = date
|
||||||
|
console.log('🚀 ~ handleOutFacTimeChange ~ formData:', formData)
|
||||||
|
}
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
if (!formData.maCode) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入设备编号',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
} else if (!formData.typeId) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请选择规格型号',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 弹框确认
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '是否确定入库吗?',
|
||||||
|
success: async (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
try {
|
||||||
|
if (isSubmit.value) return
|
||||||
|
isSubmit.value = true
|
||||||
|
uni.showLoading({ title: '加载中...', mask: true })
|
||||||
|
const res = await addMaMachineApi(formData)
|
||||||
|
console.log('🚀 ~ submit ~ res:', res)
|
||||||
|
uni.showToast({ title: '入库成功', icon: 'success' })
|
||||||
|
formData.maCode = ''
|
||||||
|
handleOpenOcr()
|
||||||
|
} catch (error) {
|
||||||
|
console.log('🚀 ~ submit ~ error:', error)
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading()
|
||||||
|
isSubmit.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card {
|
||||||
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="card">
|
||||||
|
<uni-forms :model="formData" label-width="170rpx" :border="true">
|
||||||
|
<uni-forms-item label="物资名称:" name="typeModelId">
|
||||||
|
<eselect
|
||||||
|
style="width: 100%; height: 90rpx"
|
||||||
|
ref="treeSelect"
|
||||||
|
:options="typeModelList"
|
||||||
|
@change="changeTypeModel"
|
||||||
|
@clear="clearTypeModel"
|
||||||
|
></eselect>
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="规格型号:" name="typeId">
|
||||||
|
<uni-data-select
|
||||||
|
v-model="formData.typeId"
|
||||||
|
:localdata="typeList"
|
||||||
|
placeholder="请选择规格型号"
|
||||||
|
@change="changeType"
|
||||||
|
></uni-data-select>
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item></uni-forms-item>
|
||||||
|
</uni-forms>
|
||||||
|
|
||||||
|
<div style="margin: 90px 0 30px">
|
||||||
|
<button type="primary" @click="handleOpenOcr">OCR识别</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import eselect from '@/components/tree-select/eselect.vue'
|
||||||
|
import { getDeviceTypeTreeApi, getTypeListApi } from '@/services/inStorage'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
typeModelId: '',
|
||||||
|
typeModelName: '',
|
||||||
|
typeId: '',
|
||||||
|
typeName: '',
|
||||||
|
})
|
||||||
|
const typeModelList = ref([])
|
||||||
|
const typeList = ref([])
|
||||||
|
|
||||||
|
onLoad(() => {
|
||||||
|
getTypeModelList()
|
||||||
|
})
|
||||||
|
|
||||||
|
const getTypeModelList = async () => {
|
||||||
|
try {
|
||||||
|
uni.showLoading({ title: '加载中...', mask: true })
|
||||||
|
const res = await getDeviceTypeTreeApi({ level: 3 })
|
||||||
|
console.log('🚀 ~ getDeviceTypeTreeApi ~ res:', res)
|
||||||
|
if (!res.data) return
|
||||||
|
typeModelList.value = transformTree(res.data)
|
||||||
|
console.log('🚀 ~ getTypeModelList ~ typeModelList.value:', typeModelList.value)
|
||||||
|
} catch (error) {
|
||||||
|
console.log('🚀 ~ getTypeModelList ~ error:', error)
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 递归循环
|
||||||
|
const transformTree = (list) => {
|
||||||
|
return list.map((node) => {
|
||||||
|
const newNode = {
|
||||||
|
...node,
|
||||||
|
name: node.label,
|
||||||
|
}
|
||||||
|
if (Array.isArray(node.children) && node.children.length > 0) {
|
||||||
|
newNode.children = transformTree(node.children)
|
||||||
|
}
|
||||||
|
return newNode
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getTypeList = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getTypeListApi({ typeId: formData.typeModelId })
|
||||||
|
console.log('🚀 ~ getTypeList ~ res:', res)
|
||||||
|
if (!res.data) return
|
||||||
|
typeList.value = res.data.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
text: item.typeName,
|
||||||
|
value: item.typeId,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log('🚀 ~ getTypeList ~ error:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const changeTypeModel = (e) => {
|
||||||
|
console.log('🚀 ~ changeTypeModel ~ e:', e, formData)
|
||||||
|
formData.typeModelId = e.id
|
||||||
|
formData.typeModelName = e.name
|
||||||
|
getTypeList()
|
||||||
|
}
|
||||||
|
const changeType = (e) => {
|
||||||
|
console.log('🚀 ~ changeType ~ e:', e, formData)
|
||||||
|
if (!e) return
|
||||||
|
formData.jiJuType = typeList.value.find((item) => item.typeId == e).jiJuType
|
||||||
|
console.log('🚀 ~ changeType ~ jiJuType.value:', formData.jiJuType)
|
||||||
|
}
|
||||||
|
const clearTypeModel = () => {
|
||||||
|
formData.typeId = ''
|
||||||
|
formData.typeName = ''
|
||||||
|
formData.typeModelId = ''
|
||||||
|
formData.typeModelName = ''
|
||||||
|
typeList.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOpenOcr = () => {
|
||||||
|
if (!formData.typeId) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请先选择设备类型',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/inStorage/details?params=${JSON.stringify(formData)}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card {
|
||||||
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -108,6 +108,24 @@
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view class="new-purchase" v-if="inStorageListTwo.length>0">
|
||||||
|
<div class="title-text">
|
||||||
|
<div></div>
|
||||||
|
<div class="purchase-title">盘点管理</div>
|
||||||
|
</div>
|
||||||
|
<view
|
||||||
|
class="purchase-item"
|
||||||
|
:key="index"
|
||||||
|
@tap="onNavigateTo(item.url)"
|
||||||
|
v-for="(item, index) in inStorageListTwo"
|
||||||
|
>
|
||||||
|
<image :src="item.iconSrc" mode="scaleToFill" />
|
||||||
|
<text>
|
||||||
|
{{ item.title }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- <view class="new-purchase" >
|
<!-- <view class="new-purchase" >
|
||||||
<div class="title-text">
|
<div class="title-text">
|
||||||
<div></div>
|
<div></div>
|
||||||
|
|
@ -368,6 +386,22 @@ const boxListTwo = computed(() => {
|
||||||
return boxList.value.filter(item => urlPermissions.value.includes(item.url))
|
return boxList.value.filter(item => urlPermissions.value.includes(item.url))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 盘点入库
|
||||||
|
const inStorageList = ref([
|
||||||
|
{
|
||||||
|
title: 'OCR盘点入库',
|
||||||
|
url: '/pages/inStorage/index',
|
||||||
|
iconSrc: '../../static/workbench/minPai.png',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const inStorageListTwo = computed(() => {
|
||||||
|
// 检查是否为超级管理员
|
||||||
|
if (urlPermissions.value.includes("*:*:*")) {
|
||||||
|
return inStorageList.value
|
||||||
|
}
|
||||||
|
return inStorageList.value.filter(item => urlPermissions.value.includes(item.url))
|
||||||
|
})
|
||||||
// // 库存查询
|
// // 库存查询
|
||||||
// const searchList = ref([
|
// const searchList = ref([
|
||||||
// {
|
// {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { http } from '@/utils/http'
|
||||||
|
|
||||||
|
// 类型树
|
||||||
|
export const getDeviceTypeTreeApi = (data) => {
|
||||||
|
return http({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/material/select/getDeviceTypeTreeThree',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取类型 3级 4级(根据typeId)
|
||||||
|
export const getTypeListApi = (data) => {
|
||||||
|
return http({
|
||||||
|
method: 'GET',
|
||||||
|
url: '/material/ma_machine/getTypeList',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// OCR入库
|
||||||
|
export const addMaMachineApi = (data) => {
|
||||||
|
return http({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/material/ma_machine/addMaMachine',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue