bonus-material-app/src/pages/back/backCodeAdd.vue

836 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="accept page-common">
<div class="card">
<uni-row :gutter="24">
<uni-col :span="6">任务创建</uni-col>
<uni-col :span="6">
<view class="coding-btn" @tap="codeSearch">编码检索</view>
</uni-col>
<uni-col :span="6">
<view class="coding-btn" @tap="codeScanIdentify">编码识别</view>
</uni-col>
<uni-col :span="6">
<view class="coding-btn" @tap="codeScan">二维码识别</view>
</uni-col>
</uni-row>
</div>
<ScanQrCode
ref="scanQrCodeRef"
@scanSuccess="handleScanSuccess"
@scanError="handleScanError"
/>
<div class="card">
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="6">设备编码</uni-col>
<uni-col :span="16">
<uni-easyinput v-model="maInfo.maCode" placeholder="请输入设备编码" maxlength="20" />
</uni-col>
</uni-row>
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="6">退料单位:</uni-col>
<uni-col :span="16">
<uni-easyinput type="textarea" v-model="maInfo.unitName" autoHeight disabled="true" :clearable="false" class="readonly-input"/>
</uni-col>
</uni-row>
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="6">退料工程:</uni-col>
<uni-col :span="16">
<uni-easyinput type="textarea" v-model="maInfo.proName" autoHeight disabled="true" :clearable="false" class="readonly-input" />
</uni-col>
</uni-row>
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="6">退料人:</uni-col>
<uni-col :span="16">
<uni-easyinput placeholder="请输入退料人" maxlength="10" v-model="backPerson" />
</uni-col>
</uni-row>
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="6">联系电话:</uni-col>
<uni-col :span="16">
<uni-easyinput placeholder="请输入联系电话" maxlength="11" v-model="phone" />
</uni-col>
</uni-row>
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="8">物资类型:</uni-col>
<uni-col :span="16">
{{ maInfo.typeName }}
</uni-col>
</uni-row>
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="8">规格型号:</uni-col>
<uni-col :span="16">
{{ maInfo.typeModelName }}
</uni-col>
</uni-row>
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="8">设备状态:</uni-col>
<uni-col :span="16">
{{ maInfo.maStatusName }}
</uni-col>
</uni-row>
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="6">外观判定:</uni-col>
<uni-col :span="16">
<!-- <uni-easyinput placeholder="请输入内容" v-model="apDetection"/> -->
<radio-group @change="changeRadio">
<radio value="完好" checked style="margin-right: 5px">完好</radio>
<radio value="不合格">不合格</radio>
</radio-group>
</uni-col>
</uni-row>
<uni-row :gutter="24" style="display: flex; align-items: center; margin-bottom: 20px">
<uni-col :span="4">附件:</uni-col>
<uni-col :span="20">
<div class="upload-container">
<div v-for="(img, index) in imgList" :key="index" class="upload-item">
<image :src="img.url" style="width: 160rpx; height: 160rpx" mode="aspectFill"></image>
<view class="delete-btn" @click.stop="deleteImage(index)">×</view>
<PreviewImg :imgUrl="img.url" />
</div>
<div class="upload" @click="uploadImg" v-if="imgList.length < 3">+</div>
</div>
</uni-col>
</uni-row>
<uni-row style="display: flex; align-items: center">
<uni-col :span="4">备注:</uni-col>
<uni-col :span="20">
<uni-easyinput placeholder="请输入备注" v-model="remark" :clearable="false" />
</uni-col>
</uni-row>
</div>
<div class="btn">
<!-- <button class="btn-cont" @click="reject">取消</button> -->
<button class="btn-cont" @click="submitCode">确认</button>
</div>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getMachine, insertBack, getMachineByQrCodeApi,getMachineByCodeApi } from '../../services/back.js'
import ScanQrCode from '@/pages/devicesSearch/ScanQrCode.vue'
import { baseURL } from '@/utils/http'
import { useMemberStore } from '@/stores'
import { decryptWithSM4, encryptWithSM4, hashWithSM3AndSalt } from '@/utils/sm'
import PreviewImg from '@/components/PreviewImg/index.vue'
const memberStore = useMemberStore()
const backPerson = ref('')
const phone = ref('')
const apDetection = ref('完好') //外观判定
const imgBeseUrl = ref('') //图片展示
const imgList = ref([])
const bmFileInfos = ref([])
const qrCode = ref('') //二维码
const maInfo = ref({}) //二维码
const scanQrCodeRef = ref(null)
const remark = ref('')
const isSubmit = ref(false)
// 二维码扫码
const codeScan = async () => {
qrCode.value = ''
if (scanQrCodeRef.value) {
scanQrCodeRef.value.scanQrCode()
}
// var mpaasScanModule = uni.requireNativePlugin('Mpaas-Scan-Module')
// mpaasScanModule.mpaasScan(
// {
// // 扫码识别类型参数可多选qrCode、barCode不设置默认识别所有
// scanType: ['qrCode', 'barCode'],
// // 是否隐藏相册默认false不隐藏
// hideAlbum: false,
// //ios需要设置这个参数只支持中英文 zh-Hans、en默认中文
// language: 'en',
// //相册选择照片识别错误提示(ios)
// failedMsg: '未识别到二维码,请重试',
// //Android支持全屏需要设置此参数
// screenType: 'full',
// },
// (ret) => {
// console.log(ret)
// if (ret.resp_code == 10) {
// uni.showToast({ title: '用户取消', icon: 'none' })
// maInfo.value = {}
// }
// if (ret.resp_code == 11) {
// uni.showToast({ title: '扫码失败', icon: 'none' })
// }
// if (ret.resp_code == 1000) {
// // uni.showToast({ title: '扫码成功', icon: 'none' })
// qrCode.value = ret.resp_result
// codeToBack()
// }
// },
// )
}
// 二维码
const codeToBack = async () => {
if (qrCode.value == '') {
uni.showToast({ title: '扫码识别失败', icon: 'none' })
} else {
let param = {
qrCode: qrCode.value,
}
//通过二维码获取相绑定的设备编码
const res = await getMachineByQrCodeApi(param)
console.log(res)
if (res.code == 200) {
if (res.data.length > 0) {
maInfo.value = res.data[0]
console.log('22222222', maInfo.value)
} else {
uni.showToast({ title: '扫码二维码未绑定设备编码!', icon: 'none' })
}
} else {
uni.showToast({ title: res.data.msg, icon: 'none' })
}
}
}
const changeRadio = (e) => {
console.log(e.detail.value)
apDetection.value = e.detail.value
}
const codeSearch = async () => {
console.log("xxxxxxxxxxxxx",maInfo.value.maCode)
if(!maInfo.value.maCode){
uni.showToast({ title: '请先输入设备编码!', icon: 'none' })
return
}
let param = {
maCode: maInfo.value.maCode,
}
//通过二维码获取相绑定的设备编码
const res = await getMachineByCodeApi(param)
console.log(res)
if (res.code == 200) {
if(res.data){
maInfo.value = res.data
console.log('22222222', maInfo.value)
}else{
uni.showToast({ title: '未查询到该设备编号或该编码非您负责的设备!', icon: 'none' })
}
} else {
uni.showToast({ title: res.data.msg, icon: 'none' })
}
}
//提交
const submitCode = () => {
if (maInfo.value.agreementId == undefined) {
uni.showToast({ title: '请先扫码确认退料单位,退料工程!', icon: 'none' })
} else if (backPerson.value == '') {
uni.showToast({ title: '请填写退料人!', icon: 'none' })
} else {
let info = {
agreementId: maInfo.value.agreementId,
backPerson: backPerson.value,
phone: phone.value,
proId: maInfo.value.proId,
unitId: maInfo.value.unitId,
}
let detail = [
{
maId: maInfo.value.maId,
maCode: maInfo.value.maCode,
typeId: maInfo.value.typeId,
apDetection: apDetection.value,
goodNum: apDetection.value == '完好' ? 1 : 0,
badNum: apDetection.value == '不合格' ? 1 : 0,
bmFileInfos: bmFileInfos.value,
preNum: 1,
remark: remark.value,
},
]
try {
if (isSubmit.value) return
isSubmit.value = true
uni.showLoading({ title: '提交中...', mask: true })
let param = {
backApplyInfo: info,
backApplyDetailsList: detail,
}
insertBack(param)
.then((res) => {
console.log(res)
if (res.code == 200) {
uni.showToast({ title: '新增成功', icon: 'none' })
uni.navigateTo({ url: `/pages/back/index` })
// uni.navigateBack({
// delta: 1, // 返回到已存在的页面
// })
} else {
uni.showToast({ title: res.msg, icon: 'none' })
}
})
.catch((error) => {
console.log(error)
})
} catch (error) {
console.log('🚀 ~ submitCode ~ error:', error)
} finally {
isSubmit.value = false
uni.hideLoading()
}
}
}
const deleteImage = (index) => {
imgList.value.splice(index, 1)
bmFileInfos.value.splice(index, 1)
}
//上传
const uploadImg = () => {
const count = 3 - imgList.value.length
if (count <= 0) {
uni.showToast({ title: '最多上传3张图片', icon: 'none' })
return
}else{
uni.showActionSheet({
itemList: ['拍照', '从相册选择'],
success: (res) => {
if (res.tapIndex === 0) {
getCameraFj()
} else if (res.tapIndex === 1) {
// 从相册选择
getPhotoFj()
}
},
fail: (err) => {
console.error('操作菜单选择失败:', err)
},
})
}
}
// 附件拍照
const getCameraFj = () => {
navigator.camera.getPicture(onCameraSuccessFj, onCameraErrorFj, {
quality: 50,
destinationType: window.Camera.DestinationType.DATA_URL,
sourceType: window.Camera.PictureSourceType.CAMERA,
})
}
// 附件从相册选择
const getPhotoFj = () => {
navigator.camera.getPicture(onCameraSuccessFj, onCameraErrorFj, {
quality: 50,
destinationType: window.Camera.DestinationType.DATA_URL,
sourceType: window.Camera.PictureSourceType.SAVEDPHOTOALBUM,
})
}
const onCameraErrorFj = (message) => {
console.log(message)
}
// 将 base64 数据转换为 Blob 对象
// const base64ToBlob = (base64Data, contentType = 'image/jpeg') => {
// const byteCharacters = atob(base64Data.split(',')[1]);
// const byteNumbers = new Array(byteCharacters.length);
// for (let i = 0; i < byteCharacters.length; i++) {
// byteNumbers[i] = byteCharacters.charCodeAt(i);
// }
// const byteArray = new Uint8Array(byteNumbers);
// return new Blob([byteArray], { type: contentType });
// }
const onCameraSuccessFj = (file) => {
uploadSignUrlFj(file)
}
const generateRandomString = (length) => {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
const uploadSignUrlFj = (file) => {
const base64Data = file
uni.request({
url: '/file/uploadBase64',
method: 'POST',
data: {
base64File:base64Data,
fileName: `${generateRandomString(10)}_${Date.now()}.png`,
fileType: 'image/png'
},
success: (uploadRes) => {
if(!uploadRes.data.code){
uploadRes = JSON.parse(decryptWithSM4(uploadRes.data))
}else{
uploadRes = JSON.parse(uploadRes.data)
}
if (uploadRes.code && uploadRes.code == 200) {
imgList.value.push({
url: uploadRes.data.url, // Show local path first
serverUrl: uploadRes.data.url // Store server URL
})
bmFileInfos.value.push({
name: uploadRes.data.name,
url: uploadRes.data.url,
taskType: '10'
})
uni.showToast({ title: '上传成功', icon: 'none' })
} else {
uni.showToast({ title: '上传失败', icon: 'none' })
}
},
fail: (err) => {
console.error('上传失败', err)
uni.showToast({ title: '上传失败', icon: 'none' })
}
})
}
// uni.chooseImage({
// count: count, // Allow to select up to remaining slots
// sizeType: ['original', 'compressed'],
// sourceType: ['album', 'camera'],
// success: (res) => {
// const tempFilePaths = res.tempFilePaths
// tempFilePaths.forEach((filePath, index) => {
// uni.uploadFile({
// url: '/file/upload',
// filePath: filePath,
// name: 'file',
// success: (uploadRes) => {
// uploadRes = JSON.parse(uploadRes.data)
// if (uploadRes.code && uploadRes.code == 200) {
// imgList.value.push({
// url: filePath, // Show local path first
// serverUrl: uploadRes.data.url // Store server URL
// })
// bmFileInfos.value.push({
// name: uploadRes.data.name,
// url: uploadRes.data.url,
// taskType: '10'
// })
// if (index === tempFilePaths.length - 1) {
// uni.showToast({ title: '上传成功', icon: 'none' })
// }
// } else {
// uni.showToast({ title: '上传失败', icon: 'none' })
// }
// },
// fail: (err) => {
// console.error('上传失败', err)
// uni.showToast({ title: '上传失败', icon: 'none' })
// }
// })
// })
// }
// })
// 处理扫描成功事件
const handleScanSuccess = (result) => {
qrCode.value = result?.data?.split('?qrcode=')[1] || result?.data
console.log("xxxxxxxxxxx",result)
console.log("yyyyyyyyyyy",qrCode.value)
if (qrCode.value == '') {
uni.showToast({ title: '扫码识别失败', icon: 'none' })
} else if(qrCode.value == '操作已取消'){
qrCode.value = ''
uni.showToast({ title: '操作已取消', icon: 'none' })
}else {
getMaInfoScan()
}
}
// 处理扫描失败事件
const handleScanError = (error) => {
console.error('扫描出错:', error.message)
uni.showToast({ title: error.message, icon: 'none' })
}
//查看是否是该规格型号
const getMaInfoScan = async () => {
let param = {
qrCode: qrCode.value,
}
//通过二维码获取相绑定的设备编码
const res = await getMachineByQrCodeApi(param)
console.log(res)
if (res.code == 200) {
if (res.data.length > 0) {
maInfo.value = res.data[0]
console.log('22222222', maInfo.value)
} else {
uni.showToast({ title: '扫码二维码未绑定设备编码!', icon: 'none' })
}
} else {
uni.showToast({ title: res.data.msg, icon: 'none' })
}
}
onLoad((options) => {
console.log(options)
// backPerson.value = memberStore.userInfo.nickName
})
</script>
<script>
export default {
methods: {
codeScanIdentify() {
// this.$refs.scanQrCodeRef.scanQrCode()
console.log('编码识别')
uni.showActionSheet({
itemList: ['拍照', '从相册选择'],
success: (res) => {
if (res.tapIndex === 0) {
this.getCamera()
} else if (res.tapIndex === 1) {
// 从相册选择
this.getPhoto()
}
},
fail: (err) => {
console.error('操作菜单选择失败:', err)
},
})
},
// 拍照
getCamera() {
navigator.camera.getPicture(this.onCameraSuccess, this.onCameraError, {
quality: 50,
destinationType: window.Camera.DestinationType.DATA_URL,
sourceType: window.Camera.PictureSourceType.CAMERA,
})
},
// 从相册选择
getPhoto() {
navigator.camera.getPicture(this.onCameraSuccess, this.onCameraError, {
quality: 50,
destinationType: window.Camera.DestinationType.DATA_URL,
sourceType: window.Camera.PictureSourceType.SAVEDPHOTOALBUM,
})
},
onCameraError(message) {
console.log(message)
},
onCameraSuccess(file) {
// const file1 = "data:image/jpeg;base64," + file;
const file1 = file
let params = {
image: file1,
jiju_type: '',
auth_lic:
'xIWDlaDVdijcBB4mjhGCPYk5Kvk8tHZJbUn+vW+ih15+MYx98e/PXyBmKL5gFcWMPznLgDA15QuSAnZQSLddwdy9HkZgtuQDEEZZ351Eyb1eiDUccUnyoSGIrNimbx5TooBNNPYqU4qJeFrPJXAqjBHzRrxoBxuR2CEGKQPgHC4=',
}
this.testParams = params
uni.request({
url: '/material/app/ocr/getOcrCode',
method: 'post',
data: params,
header: {
'Content-Type': 'application/json', // 根据后端要求设置请求头,常见的 POST 请求数据格式为 JSON
},
success: (res) => {
const { data: resData } = res
if (resData.data.data.result) {
this.getProjectInfoByCode(resData.data.data.result)
} else {
uni.showToast({
title: '识别失败!' + resData.data.msg,
icon: 'none',
})
}
},
fail: (err) => {
uni.showToast({
title: '请求失败:' + err.errMsg,
icon: 'none',
})
},
})
},
// 根据code查询工程等信息
getProjectInfoByCode(code) {
console.log('根据code查询工程等信息', code)
uni.showToast({
title: '识别成功!' + code,
icon: 'none',
duration: 2000,
})
},
},
}
</script>
<style lang="scss" scoped>
.readonly-input {
::v-deep .uni-easyinput__content.is-disabled {
min-height: 30px !important;
height: auto !important;
opacity: 1; /* 覆盖禁用状态的透明度 */
background-color: #fff; /* 覆盖灰色背景 */
color: #333; /* 覆盖文字颜色,设置为和正常状态一样 */
.uni-easyinput__content-input {
color: #333; /* 确保输入框内文字颜色也被覆盖 */
}
}
}
.upload-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.upload-item {
position: relative;
width: 160rpx;
height: 160rpx;
}
.delete-btn {
position: absolute;
top: -10px;
right: -10px;
width: 30rpx;
height: 30rpx;
background: #ff4d4f;
color: white;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 24rpx;
z-index: 1;
}
::v-deep .uni-radio-input {
width: 16px;
height: 16px;
}
.accept {
padding: 24rpx;
height: 95vh;
word-break: break-all;
background-color: #f7f8fa;
display: flex;
flex-direction: column;
// 卡片样式
.card {
padding: 32rpx;
background-color: #fff;
border-radius: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
margin-bottom: 24rpx;
// 卡片标题
> div:first-child {
font-size: 32rpx;
font-weight: 600;
color: #262626;
margin-bottom: 24rpx;
position: relative;
padding-left: 24rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 28rpx;
background: #3784fb;
border-radius: 6rpx;
}
}
// 表单样式
:deep(.uni-forms) {
.uni-forms-item {
padding: 18rpx 0;
margin-bottom: 0;
border-bottom: 2rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.uni-forms-item__label {
color: #8c8c8c;
}
span {
color: #262626;
font-size: 28rpx;
}
}
}
// 扫码按钮样式
.coding-btn {
height: 70rpx;
line-height: 70rpx;
background: linear-gradient(135deg, #4b8eff 0%, #3784fb 100%);
border-radius: 12rpx;
text-align: center;
color: #fff;
font-size: 24rpx;
font-weight: 600;
box-shadow: 0 6rpx 20rpx rgba(55, 132, 251, 0.2);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
opacity: 0.9;
box-shadow: 0 2rpx 8rpx rgba(55, 132, 251, 0.2);
}
// 检索按钮样式
&.search-btn {
background: #fff7eb;
color: #fa8c16;
border: 2rpx solid #fa8c16;
box-shadow: none;
&:active {
background: #fff3e0;
}
}
}
// 扫码区域
.scan-area {
width: 100%;
height: 240rpx;
margin: 24rpx 0;
border: 2rpx dashed #d9d9d9;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
color: #8c8c8c;
font-size: 28rpx;
}
// 信息展示行
:deep(.uni-row) {
/* margin-bottom: 24rpx; */
&:last-child {
margin-bottom: 0;
}
.uni-col-6 {
color: #8c8c8c;
font-size: 28rpx;
}
.uni-col-16 {
color: #262626;
font-size: 28rpx;
}
// 输入框样式
.uni-easyinput__content {
background-color: #f7f8fa;
border: 2rpx solid #e8e8e8;
border-radius: 12rpx;
height: 75rpx;
padding: 0 24rpx;
transition: all 0.3s ease;
&:focus-within {
border-color: #3784fb;
box-shadow: 0 0 0 2rpx rgba(55, 132, 251, 0.1);
}
.uni-easyinput__content-input {
font-size: 28rpx;
height: 75rpx;
line-height: 75rpx;
}
}
}
// 上传区域样式
.upload {
width: 160rpx;
height: 160rpx;
background-color: #f7f8fa;
border: 2rpx dashed #d9d9d9;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 48rpx;
color: #bfbfbf;
transition: all 0.3s ease;
&:active {
background-color: #f0f0f0;
border-color: #3784fb;
}
image {
width: 100%;
height: 100%;
border-radius: 12rpx;
object-fit: cover;
}
}
}
// 底部按钮
.btn {
margin-top: auto;
padding: 32rpx;
// background: #fff;
// box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.05);
.btn-cont {
width: 100%;
height: 88rpx;
line-height: 88rpx;
text-align: center;
background: linear-gradient(135deg, #4b8eff 0%, #3784fb 100%);
color: #fff;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 600;
box-shadow: 0 6rpx 20rpx rgba(55, 132, 251, 0.2);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
opacity: 0.9;
box-shadow: 0 2rpx 8rpx rgba(55, 132, 251, 0.2);
}
}
}
}
</style>