u
This commit is contained in:
1 parent
ce466130c0
commit
9c026f00ad
36 files changed
+2230
-1036
No files matched your search
@@ -1,8 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import type { UploadFile, UploadFileItem } from 'sard-uniapp'
|
||||
import { dialog, isImageUrl, isVideoUrl, toast } from 'sard-uniapp'
|
||||
import { aliyunpluploadApi, deleteAliyunFileApi, deleteFileApi, getUniqueIdApi, recognizeOcrBoxApi, saveObjectApi } from '@/request/api'
|
||||
import { downloadFile, getFileExtension, imageCompress, isImage, uploadFileToAliyun } from '@/utils/file'
|
||||
import { aliyunpluploadApi, deleteAliyunFileApi, deleteFileApi, getUniqueIdApi, recognizeOcrBoxApi, saveObjectApi, uploadTempFileApi } from '@/request/api'
|
||||
import { downloadFile, getFileExtension, imageCompress, isImage } from '@/utils/file'
|
||||
import { uploadToOss } from '@/utils/oss'
|
||||
|
||||
const boxImage = ref(null)
|
||||
|
||||
@@ -24,11 +25,17 @@ const subFileList = ref([])
|
||||
const tipContainerNo = ref('')
|
||||
|
||||
onLoad(async () => {
|
||||
toast.loading('正在初始化中...', {
|
||||
overlay: true,
|
||||
})
|
||||
|
||||
await getUniqueIdApi().then((res) => {
|
||||
if (res.success) {
|
||||
form.value.b_id = res.data
|
||||
}
|
||||
})
|
||||
|
||||
toast.hide()
|
||||
})
|
||||
|
||||
function handleChooseBox() {
|
||||
@@ -46,14 +53,11 @@ function handleChooseBox() {
|
||||
})
|
||||
|
||||
imageCompress(tempFile.path).then((compressRes) => {
|
||||
uploadFileToAliyun(compressRes.path, tempFile.name, 'image').then((res) => {
|
||||
if (res.url) {
|
||||
form.value.containerImageUrl = res.url
|
||||
|
||||
ocrFinish.value = false
|
||||
|
||||
console.log(compressRes)
|
||||
uploadTempFileApi(compressRes.path, tempFile.name).then((res) => {
|
||||
if (res.success) {
|
||||
recognizeOcrBoxApi({
|
||||
fileUrl: form.value.containerImageUrl,
|
||||
fileUrl: res.data.tempUrl,
|
||||
}).then((ocrRes) => {
|
||||
if (ocrRes.success) {
|
||||
toast.success('识别成功,请检查箱号是否正确')
|
||||
@@ -132,31 +136,6 @@ function beforeRead(file: UploadFile): boolean | Promise<UploadFile> {
|
||||
})
|
||||
}
|
||||
|
||||
async function afterRead(fileItem: UploadFileItem) {
|
||||
// 设置上传中状态
|
||||
fileItem.status = 'uploading'
|
||||
fileItem.message = '正在上传'
|
||||
|
||||
fileItem.isUpload = false
|
||||
|
||||
// 上传到阿里云
|
||||
const res = await uploadFileToAliyun(
|
||||
fileItem.file.path,
|
||||
fileItem.file.name,
|
||||
fileItem.file.type,
|
||||
)
|
||||
|
||||
if (!res.url)
|
||||
throw new Error('上传失败:未获取到文件 URL')
|
||||
|
||||
// 上传完成
|
||||
fileItem.status = 'done'
|
||||
fileItem.message = '上传成功'
|
||||
fileItem.url = res.url
|
||||
|
||||
subFileList.value = [...subFileList.value]
|
||||
}
|
||||
|
||||
function beforeRemove(index: number, fileItem: UploadFileItem): boolean | Promise<void> {
|
||||
console.log(fileItem)
|
||||
|
||||
@@ -172,15 +151,13 @@ function beforeRemove(index: number, fileItem: UploadFileItem): boolean | Promis
|
||||
}
|
||||
|
||||
function onRemove(index: number, item: UploadFileItem) {
|
||||
if (!item.isUpload) {
|
||||
return
|
||||
if (item.status === 'done') {
|
||||
deleteAliyunFileApi(item.url).then((res) => {
|
||||
if (res.success) {
|
||||
toast.success('删除成功')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deleteAliyunFileApi(item.url).then((res) => {
|
||||
if (res.success) {
|
||||
toast.success('删除成功')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function handleConfirm() {
|
||||
@@ -204,74 +181,76 @@ async function handleConfirm() {
|
||||
transparent: false,
|
||||
})
|
||||
|
||||
// 图片已经上传成功,保存主表即可
|
||||
const mainTable = {
|
||||
b_id: form.value.b_id,
|
||||
b_container_no: form.value.containerNo,
|
||||
b_container_img: form.value.containerImageUrl,
|
||||
b_ocr_no: form.value.ocrNo,
|
||||
b_ocr_score: form.value.ocrScore || 0.00,
|
||||
}
|
||||
//
|
||||
|
||||
const fileInserts = []
|
||||
// // 图片已经上传成功,保存主表即可
|
||||
// const mainTable = {
|
||||
// b_id: form.value.b_id,
|
||||
// b_container_no: form.value.containerNo,
|
||||
// b_container_img: form.value.containerImageUrl,
|
||||
// b_ocr_no: form.value.ocrNo,
|
||||
// b_ocr_score: form.value.ocrScore || 0.00,
|
||||
// }
|
||||
|
||||
const containerNo = form.value.containerNo
|
||||
// const fileInserts = []
|
||||
|
||||
subFileList.value.forEach(async (fileItem, index) => {
|
||||
const uniqueRes = await getUniqueIdApi()
|
||||
const indexNumber = index + 2
|
||||
// const containerNo = form.value.containerNo
|
||||
|
||||
fileInserts.push({
|
||||
subid: uniqueRes.data,
|
||||
father: form.value.b_id,
|
||||
mx_xh: indexNumber,
|
||||
mx_filename: buildFileName(containerNo, indexNumber, fileItem.file.name),
|
||||
mx_filesize: fileItem.file.size,
|
||||
mx_fileext: getFileExtension(fileItem.file.name),
|
||||
mx_mapfilename: fileItem.url,
|
||||
mx_moduleid: 'b_container',
|
||||
mx_cate_id: '1',
|
||||
})
|
||||
})
|
||||
// subFileList.value.forEach(async (fileItem, index) => {
|
||||
// const uniqueRes = await getUniqueIdApi()
|
||||
// const indexNumber = index + 2
|
||||
|
||||
const uniqueRes = await getUniqueIdApi()
|
||||
// fileInserts.push({
|
||||
// subid: uniqueRes.data,
|
||||
// father: form.value.b_id,
|
||||
// mx_xh: indexNumber,
|
||||
// mx_filename: buildFileName(containerNo, indexNumber, fileItem.file.name),
|
||||
// mx_filesize: fileItem.file.size,
|
||||
// mx_fileext: getFileExtension(fileItem.file.name),
|
||||
// mx_mapfilename: fileItem.url,
|
||||
// mx_moduleid: 'b_container',
|
||||
// mx_cate_id: '1',
|
||||
// })
|
||||
// })
|
||||
|
||||
fileInserts.push({
|
||||
subid: uniqueRes.data,
|
||||
father: form.value.b_id,
|
||||
mx_xh: 0,
|
||||
mx_filename: buildFileName(containerNo, 1, boxImage.value.name),
|
||||
mx_filesize: boxImage.value.size,
|
||||
mx_fileext: getFileExtension(boxImage.value.name),
|
||||
mx_mapfilename: form.value.containerImageUrl,
|
||||
mx_moduleid: 'b_container',
|
||||
mx_cate_id: '0',
|
||||
})
|
||||
// const uniqueRes = await getUniqueIdApi()
|
||||
|
||||
const reqData = [
|
||||
{
|
||||
tableName: 'b_container',
|
||||
keyField: 'b_id',
|
||||
inserts: [mainTable],
|
||||
updates: [],
|
||||
deletes: [],
|
||||
},
|
||||
{
|
||||
tableName: 'bf_file',
|
||||
keyField: 'subid',
|
||||
inserts: fileInserts,
|
||||
updates: [],
|
||||
deletes: [],
|
||||
},
|
||||
]
|
||||
// fileInserts.push({
|
||||
// subid: uniqueRes.data,
|
||||
// father: form.value.b_id,
|
||||
// mx_xh: 0,
|
||||
// mx_filename: buildFileName(containerNo, 1, boxImage.value.name),
|
||||
// mx_filesize: boxImage.value.size,
|
||||
// mx_fileext: getFileExtension(boxImage.value.name),
|
||||
// mx_mapfilename: form.value.containerImageUrl,
|
||||
// mx_moduleid: 'b_container',
|
||||
// mx_cate_id: '0',
|
||||
// })
|
||||
|
||||
saveObjectApi(reqData).then((res) => {
|
||||
if (res.success) {
|
||||
toast.success('保存成功')
|
||||
tipContainerNo.value = form.value.containerNo
|
||||
showResult.value = true
|
||||
}
|
||||
})
|
||||
// const reqData = [
|
||||
// {
|
||||
// tableName: 'b_container',
|
||||
// keyField: 'b_id',
|
||||
// inserts: [mainTable],
|
||||
// updates: [],
|
||||
// deletes: [],
|
||||
// },
|
||||
// {
|
||||
// tableName: 'bf_file',
|
||||
// keyField: 'subid',
|
||||
// inserts: fileInserts,
|
||||
// updates: [],
|
||||
// deletes: [],
|
||||
// },
|
||||
// ]
|
||||
|
||||
// saveObjectApi(reqData).then((res) => {
|
||||
// if (res.success) {
|
||||
// toast.success('保存成功')
|
||||
// tipContainerNo.value = form.value.containerNo
|
||||
// showResult.value = true
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
function buildFileName(containerNo, index, fileName) {
|
||||
@@ -317,107 +296,18 @@ async function continueAdd() {
|
||||
<template>
|
||||
<view class="g3-container">
|
||||
<template v-if="!showResult">
|
||||
<wd-cell-group custom-class="group" title="集装箱号(OCR识别)" border use-slot>
|
||||
<template #title>
|
||||
<sar-icon name="close" size="32rpx" style="margin-right: 16rpx;"/>
|
||||
|
||||
<text>
|
||||
集装箱号(OCR识别)
|
||||
</text>
|
||||
</template>
|
||||
<view class="step-content box">
|
||||
<view v-if="ocrFinish" class="header">
|
||||
<sar-alert
|
||||
v-if="!isError"
|
||||
type="success"
|
||||
show-icon
|
||||
closable
|
||||
:root-style="{
|
||||
width: '100%',
|
||||
}"
|
||||
>
|
||||
识别成功,请检查箱号是否正确!
|
||||
<view>
|
||||
准确率:{{ computedOcrScore }}
|
||||
</view>
|
||||
</sar-alert>
|
||||
<sar-alert
|
||||
v-else
|
||||
type="danger"
|
||||
show-icon
|
||||
closable
|
||||
:root-style="{
|
||||
width: '100%',
|
||||
}"
|
||||
>
|
||||
识别失败,请检查手动填写集装箱号
|
||||
</sar-alert>
|
||||
</view>
|
||||
|
||||
<view class="box-main">
|
||||
<view v-if="!boxImage" class="box-placeholder" @click="handleChooseBox">
|
||||
<sar-icon name="plus" size="156rpx" color="#999" />
|
||||
<view class="g3-content">
|
||||
<wd-cell-group custom-class="group" title="集装箱号(OCR识别)" border use-slot>
|
||||
<template #title>
|
||||
<view style="display:flex;align-items: center;">
|
||||
<sar-icon family="iconfont" name="iconyuanbanben_OCR" size="38rpx" color="var(--sar-primary)" style="margin-right: 16rpx;" />
|
||||
<text>
|
||||
集装箱号(OCR识别)
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view v-else class="box-image">
|
||||
<wd-img
|
||||
:src="boxImage.path"
|
||||
width="100%"
|
||||
height="100%"
|
||||
:enable-preview="true"
|
||||
/>
|
||||
|
||||
<view class="delete-btn" @click="handleDeleteBoxImage()">
|
||||
<sar-icon name="close" size="20rpx" color="#fff" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="box-input">
|
||||
<view class="header">
|
||||
<view class="label-container">
|
||||
<view>集装箱号</view>
|
||||
<view class="required-asterisk">
|
||||
*
|
||||
</view>
|
||||
</view>
|
||||
<view class="format">
|
||||
格式: 4字母 + 7数字
|
||||
</view>
|
||||
</view>
|
||||
<sar-input
|
||||
v-model="form.containerNo"
|
||||
placeholder="请输入箱号"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
|
||||
<wd-cell-group custom-class="group" title="其他图片" border style="margin-top: 32rpx;">
|
||||
<view class="step-content">
|
||||
<sar-upload
|
||||
v-model="subFileList"
|
||||
multiple
|
||||
:after-read="afterRead"
|
||||
:before-read="beforeRead"
|
||||
:before-remove="beforeRemove"
|
||||
@item-click="onItemClick"
|
||||
@remove="onRemove"
|
||||
/>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
<!-- <view class="g3-content">
|
||||
<view class="step">
|
||||
<view class="step-header">
|
||||
<sar-tag theme="primary" size="large">
|
||||
1
|
||||
</sar-tag>
|
||||
|
||||
<view>集装箱号识别(OCR自动识别)</view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
<view class="step-content box">
|
||||
<view v-if="ocrFinish" class="header ">
|
||||
<view v-if="ocrFinish" class="header">
|
||||
<sar-alert
|
||||
v-if="!isError"
|
||||
type="success"
|
||||
@@ -447,10 +337,7 @@ async function continueAdd() {
|
||||
|
||||
<view class="box-main">
|
||||
<view v-if="!boxImage" class="box-placeholder" @click="handleChooseBox">
|
||||
<sar-icon name="image" size="56rpx" color="#999" />
|
||||
<text class="placeholder-text">
|
||||
上传箱号图片,自动识别箱号
|
||||
</text>
|
||||
<sar-icon name="plus" size="156rpx" color="#999" />
|
||||
</view>
|
||||
|
||||
<view v-else class="box-image">
|
||||
@@ -485,35 +372,36 @@ async function continueAdd() {
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
|
||||
<view class="step">
|
||||
<view class="step-header">
|
||||
<sar-tag theme="primary" mark="right" size="large">
|
||||
2、其它照片录入
|
||||
</sar-tag>
|
||||
</view>
|
||||
<wd-cell-group custom-class="group" border use-slot style="margin-top: 32rpx;">
|
||||
<template #title>
|
||||
<view style="display:flex;align-items: center;">
|
||||
<sar-icon family="iconfont" name="tupian" size="38rpx" color="var(--sar-primary)" style="margin-right: 16rpx;" />
|
||||
<text>
|
||||
其他图片
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<view class="step-content">
|
||||
<sar-upload
|
||||
v-model="subFileList"
|
||||
multiple
|
||||
:after-read="afterRead"
|
||||
:before-read="beforeRead"
|
||||
:before-remove="beforeRemove"
|
||||
@item-click="onItemClick"
|
||||
@remove="onRemove"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
|
||||
<view class="g3-footer">
|
||||
<view class="footer-main">
|
||||
<view class="submit-btn" @click="handleConfirm">
|
||||
确认上传
|
||||
</view>
|
||||
<sar-button round root-style="width:100%" icon-family="iconfont" icon="fasongtijiao" @click="handleConfirm">
|
||||
上传
|
||||
</sar-button>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view v-else class="g3-result">
|
||||
@@ -526,7 +414,7 @@ async function continueAdd() {
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<sar-button long style="width: 360rpx;font-size: 38rpx;" @click="continueAdd">
|
||||
<sar-button long style="font-size: 38rpx;" @click="continueAdd">
|
||||
继续录入
|
||||
</sar-button>
|
||||
</sar-result>
|
||||
|
||||
@@ -0,0 +1,627 @@
|
||||
<script lang="ts" setup>
|
||||
import type { UploadFile, UploadFileItem } from 'sard-uniapp'
|
||||
import { dialog, isImageUrl, isVideoUrl, toast } from 'sard-uniapp'
|
||||
import { aliyunpluploadApi, deleteAliyunFileApi, deleteFileApi, getUniqueIdApi, recognizeOcrBoxApi, saveObjectApi, uploadTempFileApi } from '@/request/api'
|
||||
import { downloadFile, getFileExtension, imageCompress, isImage } from '@/utils/file'
|
||||
import { uploadToOss } from '@/utils/oss'
|
||||
|
||||
const boxImage = ref(null)
|
||||
|
||||
const ocrFinish = ref(false)
|
||||
const isError = ref(false)
|
||||
|
||||
const showResult = ref(false)
|
||||
|
||||
const form = ref({
|
||||
b_id: 0,
|
||||
containerNo: '',
|
||||
containerImageUrl: '',
|
||||
ocrScore: 0.00,
|
||||
ocrNo: '',
|
||||
})
|
||||
|
||||
const subFileList = ref([])
|
||||
|
||||
const tipContainerNo = ref('')
|
||||
|
||||
onLoad(async () => {
|
||||
toast.loading('正在初始化中...', {
|
||||
overlay: true,
|
||||
})
|
||||
|
||||
await getUniqueIdApi().then((res) => {
|
||||
if (res.success) {
|
||||
form.value.b_id = res.data
|
||||
}
|
||||
})
|
||||
|
||||
toast.hide()
|
||||
})
|
||||
|
||||
function handleChooseBox() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: (res) => {
|
||||
if (Array.isArray(res.tempFiles) && res.tempFiles.length > 0) {
|
||||
const tempFile: any = res.tempFiles[0]
|
||||
|
||||
boxImage.value = tempFile
|
||||
|
||||
toast.loading('OCR识别中,请稍等 . . .', {
|
||||
overlay: true,
|
||||
transparent: false,
|
||||
})
|
||||
|
||||
imageCompress(tempFile.path).then((compressRes) => {
|
||||
console.log(compressRes)
|
||||
// uploadTempFileApi(compressRes.path, tempFile.name).then((res) => {
|
||||
// console.log(res)
|
||||
// })
|
||||
|
||||
uploadToOss(compressRes.path, tempFile.name, 'image').then((res) => {
|
||||
if (res.url) {
|
||||
form.value.containerImageUrl = res.url
|
||||
|
||||
ocrFinish.value = false
|
||||
|
||||
recognizeOcrBoxApi({
|
||||
fileUrl: form.value.containerImageUrl,
|
||||
}).then((ocrRes) => {
|
||||
if (ocrRes.success) {
|
||||
toast.success('识别成功,请检查箱号是否正确')
|
||||
|
||||
const score = Number(ocrRes?.data?.score ?? 0)
|
||||
form.value.ocrScore = Math.floor(score * 100) / 100
|
||||
|
||||
form.value.containerNo = ocrRes.data.boxNumber
|
||||
form.value.ocrNo = ocrRes.data.boxNumber
|
||||
|
||||
isError.value = false
|
||||
}
|
||||
}).catch(() => {
|
||||
isError.value = true
|
||||
}).finally(() => {
|
||||
ocrFinish.value = true
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
const computedOcrScore = computed(() => {
|
||||
return `${(Math.floor(form.value.ocrScore * 100)).toFixed(0)}%`
|
||||
})
|
||||
|
||||
function resetForm() {
|
||||
boxImage.value = null
|
||||
form.value.containerImageUrl = ''
|
||||
form.value.containerNo = ''
|
||||
form.value.ocrNo = ''
|
||||
form.value.ocrScore = 0.00
|
||||
}
|
||||
|
||||
function handleDeleteBoxImage() {
|
||||
if (!form.value.containerImageUrl) {
|
||||
resetForm()
|
||||
return
|
||||
}
|
||||
|
||||
toast.loading('正在删除中 . . .', {
|
||||
overlay: true,
|
||||
transparent: false,
|
||||
})
|
||||
|
||||
deleteAliyunFileApi(form.value.containerImageUrl).then((res) => {
|
||||
if (res.success) {
|
||||
resetForm()
|
||||
toast.success('删除成功')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onItemClick(fileItem: UploadFileItem) {
|
||||
console.log(fileItem)
|
||||
if (!isImageUrl(fileItem.mx_mapfilename) && !isVideoUrl(fileItem.mx_mapfilename)) {
|
||||
downloadFile(fileItem.mx_mapfilename, fileItem.name)
|
||||
}
|
||||
}
|
||||
|
||||
function beforeRead(file: UploadFile): boolean | Promise<UploadFile> {
|
||||
// 非图片直接允许上传
|
||||
if (!isImage(file.name))
|
||||
return true
|
||||
|
||||
// 图片异步压缩,返回修改后的 UploadFile 对象
|
||||
return imageCompress(file.path).then((res) => {
|
||||
file.path = res.path
|
||||
file.size = res.size
|
||||
return file
|
||||
}).catch((err) => {
|
||||
console.error('图片压缩失败:', err)
|
||||
return file
|
||||
})
|
||||
}
|
||||
|
||||
async function afterRead(fileItem: UploadFileItem) {
|
||||
// 设置上传中状态
|
||||
fileItem.status = 'uploading'
|
||||
fileItem.message = '正在上传'
|
||||
|
||||
fileItem.isUpload = false
|
||||
|
||||
try {
|
||||
// 上传到阿里云
|
||||
const res = await uploadToOss(
|
||||
fileItem.file.path,
|
||||
fileItem.file.name,
|
||||
fileItem.file.type,
|
||||
)
|
||||
|
||||
if (!res.url)
|
||||
throw new Error('上传失败:未获取到文件 URL')
|
||||
|
||||
// 上传完成
|
||||
fileItem.status = 'done'
|
||||
fileItem.message = '上传成功'
|
||||
fileItem.url = res.url
|
||||
|
||||
subFileList.value = [...subFileList.value]
|
||||
}
|
||||
catch (e) {
|
||||
// 上传完成
|
||||
fileItem.status = 'failed'
|
||||
fileItem.message = '上传失败'
|
||||
subFileList.value = [...subFileList.value]
|
||||
}
|
||||
}
|
||||
|
||||
function beforeRemove(index: number, fileItem: UploadFileItem): boolean | Promise<void> {
|
||||
console.log(fileItem)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
dialog.confirm({
|
||||
title: '提示',
|
||||
message: `确定删除该张图片吗?`,
|
||||
onConfirm: () => resolve(),
|
||||
onCancel: () => reject(),
|
||||
onClose: () => reject(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function onRemove(index: number, item: UploadFileItem) {
|
||||
if (item.status === 'done') {
|
||||
deleteAliyunFileApi(item.url).then((res) => {
|
||||
if (res.success) {
|
||||
toast.success('删除成功')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function handleConfirm() {
|
||||
if (form.value.containerImageUrl === '') {
|
||||
toast.fail('集装箱号图片不能为空')
|
||||
return
|
||||
}
|
||||
|
||||
if (form.value.containerNo === '') {
|
||||
toast.fail('集装箱号不能为空')
|
||||
return
|
||||
}
|
||||
|
||||
if (!validateContainerNo(form.value.containerNo)) {
|
||||
toast.fail('集装箱号不符合规则,请检查')
|
||||
return
|
||||
}
|
||||
|
||||
toast.loading('正在保存中 . . .', {
|
||||
overlay: true,
|
||||
transparent: false,
|
||||
})
|
||||
|
||||
// 图片已经上传成功,保存主表即可
|
||||
const mainTable = {
|
||||
b_id: form.value.b_id,
|
||||
b_container_no: form.value.containerNo,
|
||||
b_container_img: form.value.containerImageUrl,
|
||||
b_ocr_no: form.value.ocrNo,
|
||||
b_ocr_score: form.value.ocrScore || 0.00,
|
||||
}
|
||||
|
||||
const fileInserts = []
|
||||
|
||||
const containerNo = form.value.containerNo
|
||||
|
||||
subFileList.value.forEach(async (fileItem, index) => {
|
||||
const uniqueRes = await getUniqueIdApi()
|
||||
const indexNumber = index + 2
|
||||
|
||||
fileInserts.push({
|
||||
subid: uniqueRes.data,
|
||||
father: form.value.b_id,
|
||||
mx_xh: indexNumber,
|
||||
mx_filename: buildFileName(containerNo, indexNumber, fileItem.file.name),
|
||||
mx_filesize: fileItem.file.size,
|
||||
mx_fileext: getFileExtension(fileItem.file.name),
|
||||
mx_mapfilename: fileItem.url,
|
||||
mx_moduleid: 'b_container',
|
||||
mx_cate_id: '1',
|
||||
})
|
||||
})
|
||||
|
||||
const uniqueRes = await getUniqueIdApi()
|
||||
|
||||
fileInserts.push({
|
||||
subid: uniqueRes.data,
|
||||
father: form.value.b_id,
|
||||
mx_xh: 0,
|
||||
mx_filename: buildFileName(containerNo, 1, boxImage.value.name),
|
||||
mx_filesize: boxImage.value.size,
|
||||
mx_fileext: getFileExtension(boxImage.value.name),
|
||||
mx_mapfilename: form.value.containerImageUrl,
|
||||
mx_moduleid: 'b_container',
|
||||
mx_cate_id: '0',
|
||||
})
|
||||
|
||||
const reqData = [
|
||||
{
|
||||
tableName: 'b_container',
|
||||
keyField: 'b_id',
|
||||
inserts: [mainTable],
|
||||
updates: [],
|
||||
deletes: [],
|
||||
},
|
||||
{
|
||||
tableName: 'bf_file',
|
||||
keyField: 'subid',
|
||||
inserts: fileInserts,
|
||||
updates: [],
|
||||
deletes: [],
|
||||
},
|
||||
]
|
||||
|
||||
saveObjectApi(reqData).then((res) => {
|
||||
if (res.success) {
|
||||
toast.success('保存成功')
|
||||
tipContainerNo.value = form.value.containerNo
|
||||
showResult.value = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function buildFileName(containerNo, index, fileName) {
|
||||
const formattedIndex = String(index).padStart(2, '0')
|
||||
|
||||
return `${containerNo}_${formattedIndex}.${fileName.split('.').pop()}`
|
||||
}
|
||||
|
||||
// 集装箱号校验
|
||||
function validateContainerNo(containerNo) {
|
||||
// 正则表达式: 4个字母 + 7个数字
|
||||
const pattern = /^[A-Z]{4}\d{7}$/i
|
||||
|
||||
// 使用正则进行匹配
|
||||
if (pattern.test(containerNo)) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function continueAdd() {
|
||||
const idRes = await getUniqueIdApi()
|
||||
|
||||
if (idRes.success) {
|
||||
boxImage.value = null
|
||||
|
||||
ocrFinish.value = false
|
||||
isError.value = false
|
||||
|
||||
resetForm()
|
||||
form.value.b_id = idRes.data
|
||||
|
||||
subFileList.value = []
|
||||
showResult.value = false
|
||||
|
||||
tipContainerNo.value = ''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="g3-container">
|
||||
<template v-if="!showResult">
|
||||
<view class="g3-content">
|
||||
<wd-cell-group custom-class="group" title="集装箱号(OCR识别)" border use-slot>
|
||||
<template #title>
|
||||
<view style="display:flex;align-items: center;">
|
||||
<sar-icon family="iconfont" name="iconyuanbanben_OCR" size="38rpx" color="var(--sar-primary)" style="margin-right: 16rpx;" />
|
||||
<text>
|
||||
集装箱号(OCR识别)
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<view class="step-content box">
|
||||
<view v-if="ocrFinish" class="header">
|
||||
<sar-alert
|
||||
v-if="!isError"
|
||||
type="success"
|
||||
show-icon
|
||||
closable
|
||||
:root-style="{
|
||||
width: '100%',
|
||||
}"
|
||||
>
|
||||
识别成功,请检查箱号是否正确!
|
||||
<view>
|
||||
准确率:{{ computedOcrScore }}
|
||||
</view>
|
||||
</sar-alert>
|
||||
<sar-alert
|
||||
v-else
|
||||
type="danger"
|
||||
show-icon
|
||||
closable
|
||||
:root-style="{
|
||||
width: '100%',
|
||||
}"
|
||||
>
|
||||
识别失败,请检查手动填写集装箱号
|
||||
</sar-alert>
|
||||
</view>
|
||||
|
||||
<view class="box-main">
|
||||
<view v-if="!boxImage" class="box-placeholder" @click="handleChooseBox">
|
||||
<sar-icon name="plus" size="156rpx" color="#999" />
|
||||
</view>
|
||||
|
||||
<view v-else class="box-image">
|
||||
<wd-img
|
||||
:src="boxImage.path"
|
||||
width="100%"
|
||||
height="100%"
|
||||
:enable-preview="true"
|
||||
/>
|
||||
|
||||
<view class="delete-btn" @click="handleDeleteBoxImage()">
|
||||
<sar-icon name="close" size="20rpx" color="#fff" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="box-input">
|
||||
<view class="header">
|
||||
<view class="label-container">
|
||||
<view>集装箱号</view>
|
||||
<view class="required-asterisk">
|
||||
*
|
||||
</view>
|
||||
</view>
|
||||
<view class="format">
|
||||
格式: 4字母 + 7数字
|
||||
</view>
|
||||
</view>
|
||||
<sar-input
|
||||
v-model="form.containerNo"
|
||||
placeholder="请输入箱号"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
|
||||
<wd-cell-group custom-class="group" border use-slot style="margin-top: 32rpx;">
|
||||
<template #title>
|
||||
<view style="display:flex;align-items: center;">
|
||||
<sar-icon family="iconfont" name="tupian" size="38rpx" color="var(--sar-primary)" style="margin-right: 16rpx;" />
|
||||
<text>
|
||||
其他图片
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<view class="step-content">
|
||||
<sar-upload
|
||||
v-model="subFileList"
|
||||
multiple
|
||||
:after-read="afterRead"
|
||||
:before-read="beforeRead"
|
||||
:before-remove="beforeRemove"
|
||||
@item-click="onItemClick"
|
||||
@remove="onRemove"
|
||||
/>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
<view class="g3-footer">
|
||||
<view class="footer-main">
|
||||
<sar-button round root-style="width:100%" icon-family="iconfont" icon="fasongtijiao" @click="handleConfirm">
|
||||
上传
|
||||
</sar-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view v-else class="g3-result">
|
||||
<sar-result status="success" title="操作成功" description="已成功录入箱号 为 xxx 的记录">
|
||||
<template #description>
|
||||
<view class="result-tip">
|
||||
已成功录入箱号
|
||||
<text class="container-no">
|
||||
"{{ tipContainerNo }}"
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<sar-button long style="font-size: 38rpx;" @click="continueAdd">
|
||||
继续录入
|
||||
</sar-button>
|
||||
</sar-result>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.g3-result {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.result-tip {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.container-no {
|
||||
font-weight: 600;
|
||||
color: #4caf50;
|
||||
}
|
||||
}
|
||||
|
||||
.g3-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.g3-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16rpx 0rpx;
|
||||
}
|
||||
|
||||
.g3-footer {
|
||||
width: 100%;
|
||||
|
||||
.footer-main {
|
||||
padding: 16rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step {
|
||||
margin-bottom: 32rpx;
|
||||
|
||||
.step-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.step-content {
|
||||
padding: 32rpx;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.box-main {
|
||||
height: 326rpx;
|
||||
}
|
||||
|
||||
.box-placeholder {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
background: var(--sar-upload-select-bg);
|
||||
border-radius: var(--sar-upload-select-border-radius);
|
||||
|
||||
.placeholder-text {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.box-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.delete-btn {
|
||||
position: absolute;
|
||||
top: 12rpx;
|
||||
right: 12rpx;
|
||||
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
|
||||
border-radius: 50%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.box-input {
|
||||
margin-top: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 12rpx;
|
||||
width: 100%;
|
||||
.label-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.required-asterisk {
|
||||
position: absolute;
|
||||
top: -5rpx;
|
||||
right: -12rpx;
|
||||
color: red;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.format {
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.tip {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
border-radius: 999px;
|
||||
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #3a6ee8, #5c8df6);
|
||||
box-shadow: 0 6rpx 12rpx rgba(58, 110, 232, 0.18);
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.submit-btn:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 3rpx 6rpx rgba(58, 110, 232, 0.15);
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user