问题修改

This commit is contained in:
hayu 2025-08-12 15:00:41 +08:00
parent 8eb66958e4
commit 64ba11f2b0
2 changed files with 318 additions and 283 deletions

View File

@ -36,83 +36,123 @@
</view>
<view class="table-list-item">
<uni-forms :model="codeData" label-width="100" :border="true">
<uni-forms-item label="物资名称:" name="materialType">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.materialType }}</text>
<uni-forms-item label="设备类型:" name="maName">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.maName }}</text>
</uni-forms-item>
<uni-forms-item label="物资类型:" name="materialName">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.materialName }}</text>
</uni-forms-item>
<uni-forms-item label="规格型号:" name="materialModel">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.materialModel }}</text>
<uni-forms-item label="规格型号:" name="maModel">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.maModel }}</text>
</uni-forms-item>
<uni-forms-item label="设备编码:" name="maCode">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.maCode }}</text>
</uni-forms-item>
<uni-forms-item label="检验结论:" name="statusName">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.statusName }}</text>
<!-- <uni-forms-item label="设备状态:" name="maStatus">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.maStatus }}</text>
</uni-forms-item> -->
<uni-forms-item label="本次检修时间:" name="thisCheckTime">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.thisCheckTime }}</text>
</uni-forms-item>
<uni-forms-item label="本次检修时间:" name="inspectionTime">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.inspectionTime }}</text>
<uni-forms-item label="下次检修时间:" name="nextCheckTime">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.nextCheckTime }}</text>
</uni-forms-item>
<uni-forms-item label="下次检修时间:" name="nextInspectionTime">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.nextInspectionTime }}</text>
<uni-forms-item label="出入库次数:" name="inOutNum">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.inOutNum }}</text>
</uni-forms-item>
<uni-forms-item label="初次入库:" name="inTime">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.inTime }}</text>
</uni-forms-item>
<uni-forms-item label="服务工程次数:" name="serviceNum">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.serviceNum }}</text>
</uni-forms-item>
<uni-forms-item label="检验次数:" name="serviceNum">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.serviceNum }}</text>
</uni-forms-item>
<uni-forms-item label="更换配件次数:" name="checkNum">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.checkNum }}</text>
</uni-forms-item>
<uni-forms-item label="检修员:" name="inspectionPerson">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.inspectionPerson }}</text>
</uni-forms-item>
<uni-forms-item label="检验员:" name="inspectionVerifier">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.inspectionVerifier }}</text>
<uni-forms-item label="报废:" name="scrapTime">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.scrapTime }}</text>
</uni-forms-item>
<uni-forms-item label="联系电话:" name="contactNumber">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.contactNumber }}</text>
<uni-forms-item label="生产厂家:" name="statusName">
<text style="height: 100%;display: flex;align-items: center;">{{}}</text>
</uni-forms-item>
<uni-forms-item label="领料工程:" name="materialProject">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.materialProject }}</text>
<uni-forms-item label="领料单位:" name="leaseUnit">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.leaseUnit }}</text>
</uni-forms-item>
<uni-forms-item label="领料单位:" name="materialUnit">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.materialUnit }}</text>
<uni-forms-item label="领料工程:" name="leaseProject">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.leaseProject }}</text>
</uni-forms-item>
<uni-forms-item label="领料时间:" name="leaseTime">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.leaseTime }}</text>
</uni-forms-item>
<uni-forms-item label="退料单位:" name="backUnit">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.backUnit }}</text>
</uni-forms-item>
<uni-forms-item label="退料工程:" name="backProject">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.backProject }}</text>
</uni-forms-item>
<uni-forms-item label="退料时间:" name="backTime">
<text style="height: 100%;display: flex;align-items: center;">{{ codeData.backTime }}</text>
</uni-forms-item>
</uni-forms>
</view>
</view>
<!-- 相机预览页面 - 修改为固定全屏 -->
<!-- 相机预览页面 -->
<view v-if="showCamera" class="camera-wrapper">
<!-- 相机预览容器 - 单独放置 -->
<view class="camera-preview-container"></view>
<view v-if="showCamera" class="camera-container">
<!-- 顶部提示 -->
<view class="top-tip">
<text class="tip-text">请将识别编码置于取景框内完成扫描</text>
</view>
<!-- 取景框 -->
<view class="viewfinder-container">
</view>
<!-- UI控制层 - 独立于相机预览 -->
<view class="camera-ui-layer">
<!-- 底部控制区 -->
<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 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 v-if="isProcessing" class="loading-overlay">
<view class="loading-content">
<view class="loading-spinner"></view>
<text class="loading-text">正在识别中...</text>
</view>
</view>
</view>
<!-- 隐藏的canvas用于图片处理 -->
<canvas
canvas-id="imageCanvas"
style="position: fixed; top: -9999px; left: -9999px; width: 1px; height: 1px;"
></canvas>
<div style="width: 100%;">
<ElectronicSeal :maCode="codeData?.maCode" :maId="codeData?.maId" />
</div>
</view>
</template>
<script>
import ImageUtils from "../../services/utils/imageUtils";
import {decryptWithSM4} from "../../utils/sm";
import {getDeviceListAPI} from "../../services/picking/outbound";
import ElectronicSeal from '@/components/ElectronicSeal/index.vue'
export default {
components: { ElectronicSeal },
data() {
return {
showCamera: false,
@ -301,7 +341,7 @@ export default {
}
//
const cameraWrapper = document.querySelector('.camera-preview-container');
const cameraWrapper = document.querySelector('.viewfinder-container');
if (!cameraWrapper) {
reject(new Error('找不到相机容器'));
return;
@ -309,8 +349,8 @@ export default {
const rect = cameraWrapper.getBoundingClientRect();
const options = {
x: rect.left-100,
y: rect.top-100,
x: rect.left,
y: rect.top,
width: rect.width,
height: rect.height,
camera: CameraPreview.CAMERA_DIRECTION?.BACK || 'back',
@ -435,36 +475,13 @@ export default {
if (!CameraPreview) {
throw new Error('相机插件不可用');
}
//
console.log('拍照前聚焦...');
await this.performFocusBeforeCapture();
console.log('开始拍照...');
const imageData = await new Promise((resolve, reject)=>
{
const options = {
quality: 85,
targetHeight: 1920,
targetWidth: 1080
};
CameraPreview.takePicture(
options,
(imageData) => {
console.log('拍照成功');
resolve(imageData);
},
(error) => {
console.error('拍照失败:', error);
reject(new Error(`拍照失败: ${error}`));
}
);
}
)
;
await this.processImage(imageData);
CameraPreview.takePicture({width:640, height:540, quality: 50}, async (base64PictureData) => {
console.log('拍照返回数据',base64PictureData);
await this.processImage(base64PictureData);
});
} catch (error) {
console.error('拍照过程出错:', error);
uni.showToast({
@ -476,98 +493,97 @@ export default {
}
},
//
async performFocusBeforeCapture() {
const CameraPreview = this.getCameraPlugin();
if (!CameraPreview || typeof CameraPreview.setFocus !== 'function') {
console.log('相机插件不支持聚焦,直接拍照');
return;
}
//
removeExifData(pureBase64) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
try {
this.isFocusing = true;
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
console.log('拍照前执行聚焦...');
// dataURLbase64
const dataUrl = canvas.toDataURL('image/jpeg', 0.8);
const cleanPureBase64 = dataUrl.split(',')[1]; //
resolve(cleanPureBase64);
};
await new Promise((resolve, reject)=>
{
//
const focusTimeout = setTimeout(() => {
console.log('拍照前聚焦超时,继续拍照');
this.isFocusing = false;
resolve();
}, 2000); //
img.onerror = () => reject(new Error('图像加载失败'));
CameraPreview.setFocus(
(result) => {
console.log('拍照前聚焦成功:', result);
clearTimeout(focusTimeout);
this.isFocusing = false;
//
setTimeout(resolve, 200);
},
(error) => {
console.error('拍照前聚焦失败:', error);
clearTimeout(focusTimeout);
this.isFocusing = false;
resolve(); // 使
}
);
}
)
;
} catch (error) {
console.error('拍照前聚焦过程出错:', error);
this.isFocusing = false;
}
//
img.src = `data:image/jpeg;base64,${pureBase64}`;
});
},
// - 使ImageUtils
async processImage(imageData) {
this.isProcessing = true;
try {
// base64PictureData base64
const cleanBase64 = await this.removeExifData(imageData);
// cleanBase64 base64
console.log('清理后的纯base64:', cleanBase64);
console.log('开始处理图片...');
// 使ImageUtils
const processedBase64 = await ImageUtils.processImage(imageData, {
maxWidth: 1024,
maxHeight: 1024,
quality: 50,
outputFormat: 'base64'
});
console.log('图片处理完成开始OCR识别...');
const response = await new Promise((resolve, reject)=>
{
uni.request({
url: '/material/app/ocr/getOcrCode',
method: 'POST',
data: {
image: processedBase64,
jiju_type: '',
auth_lic: 'xIWDlaDVdijcBB4mjhGCPYk5Kvk8tHZJbUn+vW+ih15+MYx98e/PXyBmKL5gFcWMPznLgDA15QuSAnZQSLddwdy9HkZgtuQDEEZZ351Eyb1eiDUccUnyoSGIrNimbx5TooBNNPYqU4qJeFrPJXAqjBHzRrxoBxuR2CEGKQPgHC4='
},
timeout: 30000,
success: resolve,
fail: reject
});
}
)
;
if (response.data?.data?.result) {
this.queryCodeParams.maCode = response.data.data.result;
await this.closeCamera();
this.getCode();
uni.showToast({
title: '识别成功',
icon: 'success'
});
} else {
uni.showToast({
title: '未识别到有效编码',
icon: 'none'
});
}
uni.request({
url: '/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
}
console.log("res", res);
console.log("res.data",res.data)
const {data: resData} = res
console.log("resData",resData)
console.log("resData.data",resData.data)
console.log("resData.code",resData.code)
console.log("resData.data.result",resData.data.result)
if (resData.code===0){
if (resData.data.result) {
this.queryCodeParams.maCode = resData.data.result
await this.closeCamera();
await this.getCode();
await uni.showToast({
title: '识别成功',
icon: 'success'
});
} else {
uni.showToast({
title: '识别失败!' + resData.data.msg,
icon: 'none',
})
}
} else {
uni.showToast({
title: '识别失败!',
icon: 'none',
})
}
},
fail: (err) => {
uni.showToast({
title: '请求失败:' + err.errMsg,
icon: 'none',
})
},
})
} catch (error) {
console.error('图片处理或OCR识别失败:', error);
uni.showToast({
@ -578,15 +594,31 @@ export default {
this.isProcessing = false;
}
},
//
//
openGallery() {
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (res) => {
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
this.convertImageToBase64(res.tempFilePaths[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) => {
@ -598,53 +630,95 @@ export default {
}
});
},
// //
// openGallery() {
// uni.chooseImage({
// count: 1,
// sourceType: ['album'],
// success: (res) => {
// if (res.tempFilePaths && res.tempFilePaths.length > 0) {
// this.convertImageToBase64(res.tempFilePaths[0]);
// }
// },
// fail: (error) => {
// console.error(':', error);
// uni.showToast({
// title: '',
// icon: 'none'
// });
// }
// });
// },
// base64 - 使ImageUtils
async convertImageToBase64(filePath) {
async convertImageToBase64(processedBase64) {
this.isProcessing = true;
try {
console.log('开始处理相册图片...');
console.log('相册base64数据', processedBase64);
// 使ImageUtils
const processedBase64 = await ImageUtils.processImage(filePath, {
maxWidth: 1024,
maxHeight: 1024,
quality: 50,
outputFormat: 'base64'
});
// const processedBase64 = await ImageUtils.processImage(filePath, {
// maxWidth: 1024,
// maxHeight: 1024,
// quality: 50,
// outputFormat: 'base64'
// });
console.log('相册图片处理完成开始OCR识别...');
const response = await new Promise((resolve, reject)=>
{
uni.request({
url: '/material/app/ocr/getOcrCode',
method: 'POST',
data: {
image: processedBase64,
jiju_type: '',
auth_lic: 'xIWDlaDVdijcBB4mjhGCPYk5Kvk8tHZJbUn+vW+ih15+MYx98e/PXyBmKL5gFcWMPznLgDA15QuSAnZQSLddwdy9HkZgtuQDEEZZ351Eyb1eiDUccUnyoSGIrNimbx5TooBNNPYqU4qJeFrPJXAqjBHzRrxoBxuR2CEGKQPgHC4='
},
timeout: 30000,
success: resolve,
fail: reject
});
}
)
;
if (response.data?.data?.result) {
this.queryCodeParams.maCode = response.data.data.result;
await this.closeCamera();
this.getCode();
uni.showToast({
title: '识别成功',
icon: 'success'
});
} else {
uni.showToast({
title: '未识别到有效编码',
icon: 'none'
});
}
uni.request({
url: '/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", res);
console.log("res.data",res.data)
const {data: resData} = res
console.log("resData",resData)
console.log("resData.data",resData.data)
console.log("resData.code",resData.code)
console.log("resData.data.result",resData.data.result)
if (resData.code===0){
if (resData.data.result) {
this.queryCodeParams.maCode = resData.data.result
await this.closeCamera();
await this.getCode();
await uni.showToast({
title: '识别成功',
icon: 'success'
});
} else {
uni.showToast({
title: '识别失败!' + resData.data.msg,
icon: 'none',
})
}
} else {
uni.showToast({
title: '识别失败!',
icon: 'none',
})
}
},
fail: (err) => {
uni.showToast({
title: '请求失败:' + err.errMsg,
icon: 'none',
})
},
});
} catch (error) {
console.error('相册图片处理或OCR识别失败:', error);
uni.showToast({
@ -657,7 +731,7 @@ export default {
},
//
async getCode() {
getCode() {
if (!this.queryCodeParams.maCode.trim()) {
uni.showToast({
title: '请输入设备编码',
@ -666,33 +740,27 @@ export default {
return;
}
try {
const response = await new Promise((resolve, reject)=>
{
uni.request({
url: '/material/ma_machine/getHisByCode',
method: 'GET',
data: {maCode: this.queryCodeParams.maCode},
success: resolve,
fail: reject
});
}
)
;
if (response.data?.data && response.data.data.length > 0) {
this.optionList = response.data.data.map(option => ({
value: option.maId,
text: option.maCode
}));
if (response.data.data.length === 1) {
this.codeData = response.data.data[0];
getDeviceListAPI({'maCode': this.queryCodeParams.maCode}).then(response => {
console.log("xxxxxxxxxxx", response)
if (response.code === 200 && response.data && response.data.length > 0) {
this.optionList = response.data.map(option => ({
value: option.maId,
text: option.maCode
}));
if (response.data.length === 1) {
this.codeData = response.data[0];
}
} else {
uni.showToast({
title: '未查询到该编号信息',
icon: 'none',
duration: 2000
})
}
} else {
uni.showToast({
title: '未查询到该编号信息',
icon: 'none'
});
}
}).catch(error => {
console.error("获取设备信息失败", error)
uni.hideLoading()
})
} catch (error) {
console.error('查询失败:', error);
uni.showToast({
@ -706,26 +774,9 @@ export default {
async changeTag() {
if (!this.queryCodeParams.maId) return;
try {
const response = await new Promise((resolve, reject)=>
{
uni.request({
url: '/material/ma_machine/getHisByCode',
method: 'GET',
data: {maId: this.queryCodeParams.maId},
success: resolve,
fail: reject
});
}
)
;
if (response.data?.data && response.data.data.length > 0) {
this.codeData = response.data.data[0];
} else {
uni.showToast({
title: '获取编号信息失败',
icon: 'none'
});
const response = await getDeviceListAPI({'maId': this.queryCodeParams.maId})
if (response.data && response.data.length !== 0) {
this.codeData = response.data[0]
}
} catch (error) {
console.error("获取编号信息失败", error);
@ -742,7 +793,6 @@ export default {
if (this.cameraStarted) {
const CameraPreview = this.getCameraPlugin();
if (CameraPreview) {
CameraPreview.setOnView(null); //
CameraPreview.stopCamera();
}
this.cameraStarted = false;
@ -771,36 +821,6 @@ export default {
</script>
<style>
/* 新增相机包装器样式 */
.camera-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10000; /* 基础层级 */
}
/* 相机预览容器 - 无内容,仅用于定位 */
.camera-preview-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 50%;
z-index: 1; /* 较低层级 */
}
/* UI控制层 - 显示在相机之上 */
.camera-ui-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2; /* 高于相机预览 */
pointer-events: none; /* 允许点击穿透到相机 */
}
.page-container {
display: flex;
@ -843,15 +863,18 @@ export default {
/* 控制按钮区域 - 需要单独设置可点击 */
.bottom-controls {
/* 原有样式保持不变 */
position: absolute;
bottom: 0;
bottom: 100rpx;
left: 0;
right: 0;
display: flex;
justify-content: space-around; /* 改为space-around使按钮分布更均匀 */
align-items: center;
width: 100%;
z-index: 3; /* 控制按钮在最高层 */
pointer-events: auto; /* 启用点击事件 */
padding: 0 60rpx; /* 添加左右内边距 */
z-index: 3;
pointer-events: auto;
}
.control-btn {
width: 100rpx;
height: 100rpx;
@ -861,6 +884,7 @@ export default {
justify-content: center;
align-items: center;
border: 2rpx solid rgba(255, 255, 255, 0.3);
margin: 0 20rpx; /* 添加按钮间距 */
}
.control-icon {
@ -879,6 +903,7 @@ export default {
align-items: center;
border: 6rpx solid rgba(255, 255, 255, 0.5);
transition: all 0.2s ease;
margin: 0 20rpx; /* 添加按钮间距 */
}
.photo-btn.taking {
@ -951,4 +976,13 @@ export default {
font-size: 32rpx;
font-weight: bold;
}
.viewfinder-container {
position: absolute;
width: 100%;
height: 40%;
margin-top: 150px;
z-index: 10001; /* 提高取景框层级 */
}
</style>

View File

@ -117,11 +117,7 @@ const newInfoList = ref([
url: '/pages/devicesSearch/ocrSearch',
iconSrc: '../../static/searchModel/qrCode.png',
},
// {
// title: 'OCR2',
// url: '/pages/devicesSearch/ocrSearch2',
// iconSrc: '../../static/searchModel/qrCode.png',
// },
// {
// title: 'OCR3',
// url: '/pages/devicesSearch/ocrSearch3',
@ -147,6 +143,11 @@ const newInfoList = ref([
url: '',
iconSrc: '../../static/searchModel/electTag.png',
},
{
title: 'OCR扫描',
url: '/pages/devicesSearch/ocrSearch2',
iconSrc: '../../static/searchModel/qrCode.png',
},
])
// 使 newInfoList