| | |
| | | <script setup lang="ts"> |
| | | import { ref } from 'vue' |
| | | import type { UploadProps, UploadUserFile } from 'element-plus' |
| | | const fileList = ref<UploadUserFile[]>([]) |
| | | const upload = ref() |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import { |
| | | Document, UploadFilled, MagicStick, RefreshLeft, |
| | | Download, Plus, Picture, Refresh, Delete |
| | | } from '@element-plus/icons-vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import request from "@/utils/requestByFile" |
| | | import {useI18n} from "vue-i18n"; |
| | | |
| | | const emits = defineEmits(['getUploadPicture']) |
| | | const { t } = useI18n() |
| | | const uploadRef = ref() |
| | | const fileList = ref([]) |
| | | const converting = ref(false) |
| | | const progressPercentage = ref(0) |
| | | const progressStatus = ref('') |
| | | const progressText = ref('') |
| | | const conversionResult = ref(null) |
| | | const supportedFormats = ref(['png', 'jpg', 'jpeg', 'bmp']) |
| | | const loadingFormats = ref(false) |
| | | let result = ref(null) |
| | | let props = defineProps({ |
| | | rowIndex:null, |
| | | orderId:null, |
| | | state:null |
| | | }) |
| | | |
| | | const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => { |
| | | console.log(uploadFile, uploadFiles) |
| | | const form = reactive({ |
| | | format: 'png' |
| | | }) |
| | | |
| | | onMounted(() => { |
| | | getFileList() |
| | | }) |
| | | |
| | | const getFileList = async () => { |
| | | request.post(`/orderFile/getOrderNumberFile/${props.orderId}/${props.rowIndex.orderNumber}`).then(res=>{ |
| | | if(res.data===null){ |
| | | return |
| | | } |
| | | result.value = res.data |
| | | conversionResult.value = res.data.imageBase64 |
| | | }) |
| | | } |
| | | |
| | | const handlePreview: UploadProps['onPreview'] = (file) => { |
| | | console.log(file) |
| | | } |
| | | const handleChange = (uploadFile, uploadFiles) => { |
| | | emits('getUploadPicture', uploadFile.name,uploadFile) |
| | | upload.value.clearFiles() |
| | | const deleteFile = async () => { |
| | | request.post(`/orderFile/deleteOrderNumberFile/${props.orderId}/${props.rowIndex.orderNumber}`).then(res=>{ |
| | | result.value = null |
| | | conversionResult.value = null |
| | | ElMessage.success(t("basicData.msg.deleteSuccess")) |
| | | }) |
| | | } |
| | | |
| | | const downloadFile = () => { |
| | | try { |
| | | // 移除字符串中的方括号和空格 |
| | | const cleanString = result.value.fileData.replace(/[\[\]\s]/g, ''); |
| | | |
| | | // 如果字符串为空,返回空的Uint8Array |
| | | if (!cleanString) { |
| | | return new Uint8Array(); |
| | | } |
| | | |
| | | // 分割字符串并转换为数字数组 |
| | | const byteStrings = cleanString.split(','); |
| | | const bytes = byteStrings.map(byteStr => { |
| | | // 将字符串转换为数字(处理负数) |
| | | let value = parseInt(byteStr, 10); |
| | | |
| | | // Java字节是有符号的(-128到127),需要转换为无符号(0到255) |
| | | if (value < 0) { |
| | | value = 256 + value; |
| | | } |
| | | |
| | | return value; |
| | | }); |
| | | |
| | | const uint8Array = new Uint8Array(bytes); |
| | | const file = new File([uint8Array], `${props.orderId}-${props.rowIndex.orderNumber}.dwg`, { type:'application/x-dwg' }) |
| | | |
| | | const url = URL.createObjectURL(file); |
| | | // 创建下载链接 |
| | | const a = document.createElement('a'); |
| | | a.href = url; |
| | | a.download = file.name; |
| | | a.style.display = 'none'; |
| | | |
| | | // 添加到DOM并触发点击 |
| | | document.body.appendChild(a); |
| | | a.click(); |
| | | |
| | | // 清理资源 |
| | | setTimeout(() => { |
| | | document.body.removeChild(a); |
| | | URL.revokeObjectURL(url); |
| | | }, 100); |
| | | } catch (error) { |
| | | console.error('解析Java字节数组字符串时出错:', error); |
| | | throw new Error('无效的Java字节数组格式'); |
| | | } |
| | | } |
| | | |
| | | |
| | | const loadSupportedFormats = async () => { |
| | | try { |
| | | if (fileList.value.length === 0) { |
| | | ElMessage.warning(t("order.msg.pleaseUploadPicture1")) |
| | | return |
| | | } |
| | | loadingFormats.value = true |
| | | |
| | | converting.value = true |
| | | progressPercentage.value = 0 |
| | | progressStatus.value = '' |
| | | progressText.value = t("order.msg.pleaseUploadPicture2") |
| | | |
| | | // 模拟进度更新 |
| | | const progressInterval = setInterval(() => { |
| | | if (progressPercentage.value < 80) { |
| | | progressPercentage.value += 10 |
| | | progressText.value = t("order.msg.pleaseUploadPicture3")+progressPercentage.value+'%' |
| | | } |
| | | }, 500) |
| | | |
| | | const data ={ |
| | | file:fileList.value[0].raw, |
| | | name:fileList.value[0].raw.name |
| | | } |
| | | request.post(`/orderFile/updateOrderFileByOrderNumber/${props.orderId}/${props.rowIndex.orderNumber}`,data).then(res=>{ |
| | | if (res.code === '200') { |
| | | result.value = res.data |
| | | conversionResult.value = res.data.imageBase64 |
| | | uploadRef.value.clearFiles() |
| | | clearInterval(progressInterval) |
| | | progressPercentage.value = 100 |
| | | progressStatus.value = 'success' |
| | | progressText.value = t("order.msg.pleaseUploadPicture4") |
| | | uploadRef.value.clearFiles() |
| | | fileList.value = [] |
| | | setTimeout(() => { |
| | | |
| | | converting.value = false |
| | | },2000) |
| | | } |
| | | }) |
| | | } catch (error) { |
| | | ElMessage.error(t("order.msg.pleaseUploadPicture5")) |
| | | } finally { |
| | | loadingFormats.value = false |
| | | } |
| | | } |
| | | |
| | | const fileTypeCheck = (file) => { |
| | | const fileName = file.raw.name.toLowerCase(); |
| | | |
| | | switch (true) { |
| | | case /\.dwg$/.test(fileName): |
| | | case /\.png$/.test(fileName): |
| | | case /\.jpg$/.test(fileName): |
| | | return true; |
| | | default: |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | const handleFileChange = (file) => { |
| | | const fileTypeCheckBoole = fileTypeCheck(file) |
| | | if (!(fileTypeCheckBoole )) { |
| | | //ElMessage.error('请选择DWG或DXF格式的文件') |
| | | ElMessage.error(t("order.msg.pleaseUploadPicture6")) |
| | | uploadRef.value.clearFiles() |
| | | return |
| | | } |
| | | |
| | | if (file.raw.size > 50 * 1024 * 1024) { |
| | | ElMessage.error(t("order.msg.pleaseUploadPicture7")) |
| | | uploadRef.value.clearFiles() |
| | | return |
| | | } |
| | | fileList.value = [file] |
| | | ElMessage.success(t("order.msg.pleaseUploadPicture8")+file.name) |
| | | } |
| | | |
| | | const handleFileRemove = () => { |
| | | conversionResult.value = null |
| | | result.value = null |
| | | uploadRef.value.clearFiles() |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | const handleReset = () => { |
| | | uploadRef.value.clearFiles() |
| | | fileList.value = [] |
| | | conversionResult.value = null |
| | | progressPercentage.value = 0 |
| | | progressStatus.value = '' |
| | | progressText.value = '' |
| | | form.format = 'png' |
| | | result.value = null |
| | | } |
| | | |
| | | const formatFileSize = (bytes) => { |
| | | if (bytes === 0) return '0 Bytes' |
| | | const k = 1024 |
| | | const sizes = ['Bytes', 'KB', 'MB', 'GB'] |
| | | const i = Math.floor(Math.log(bytes) / Math.log(k)) |
| | | return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <el-upload |
| | | v-model:file-list="fileList" |
| | | ref="upload" |
| | | class="upload-demo" |
| | | action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15" |
| | | :on-preview="handlePreview" |
| | | :on-remove="handleRemove" |
| | | :on-change="handleChange" |
| | | list-type="picture" |
| | | :auto-upload="false" |
| | | > |
| | | <el-button type="primary">Click to upload</el-button> |
| | | <template #tip> |
| | | <div class="el-upload__tip"> |
| | | DWG files with a size less than 10M |
| | | <div class="file-upload-container"> |
| | | <el-card class="upload-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span class="header-title"> |
| | | <el-icon><Document /></el-icon> |
| | | {{$t("order.msg.pleaseUploadPicture9")}} |
| | | </span> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <!-- 文件上传区域 --> |
| | | <el-upload |
| | | v-if="!conversionResult" |
| | | ref="uploadRef" |
| | | class="upload-demo" |
| | | drag |
| | | action="" |
| | | :auto-upload="false" |
| | | :on-change="handleFileChange" |
| | | :on-remove="handleFileRemove" |
| | | :file-list="fileList" |
| | | :limit="1" |
| | | :disabled="converting" |
| | | > |
| | | <el-icon class="el-icon--upload"><UploadFilled /></el-icon> |
| | | <div class="el-upload__text"> |
| | | {{$t("order.msg.pleaseUploadPicture10")}} <em>{{$t("order.msg.pleaseUploadPicture11")}}</em> |
| | | </div> |
| | | <template #tip> |
| | | <div class="el-upload__tip"> |
| | | {{$t("order.msg.pleaseUploadPicture12")}} |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | |
| | | <!-- 上传选项 --> |
| | | <div v-if="!conversionResult" class="conversion-options"> |
| | | |
| | | <div class="action-buttons"> |
| | | <el-button |
| | | type="primary" |
| | | :loading="converting" |
| | | @click="loadSupportedFormats" |
| | | :disabled="!form.format || props.state !== 1 || converting" |
| | | > |
| | | <template #icon> |
| | | <el-icon><MagicStick /></el-icon> |
| | | </template> |
| | | {{$t("basicData.save")}} |
| | | </el-button> |
| | | |
| | | <el-button @click="handleReset" |
| | | :loading="converting" |
| | | :disabled="props.state !== 1 || converting"> |
| | | <template #icon> |
| | | <el-icon><RefreshLeft /></el-icon> |
| | | </template> |
| | | {{$t("craft.reset")}} |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | |
| | | <!-- 转换进度 --> |
| | | <div v-if="converting" class="conversion-progress"> |
| | | <el-divider content-position="left">{{$t("order.msg.pleaseUploadPicture13")}}</el-divider> |
| | | <el-progress |
| | | :percentage="progressPercentage" |
| | | :status="progressStatus" |
| | | :stroke-width="8" |
| | | /> |
| | | <div class="progress-text"> |
| | | {{ progressText }} |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 转换结果 --> |
| | | <div v-if="conversionResult" class="conversion-result"> |
| | | <el-divider content-position="left">{{$t("order.msg.pleaseUploadPicture14")}}</el-divider> |
| | | |
| | | <el-result |
| | | icon="success" |
| | | :sub-title='t("order.msg.pleaseUploadPicture15")' |
| | | > |
| | | <template #extra> |
| | | <div class="result-content"> |
| | | |
| | | <!-- 图片预览 --> |
| | | <div class="image-preview"> |
| | | <el-image |
| | | :src="conversionResult" |
| | | :preview-src-list="[conversionResult]" |
| | | fit="contain" |
| | | style="max-height: 600px;" |
| | | > |
| | | <!-- <template #error>--> |
| | | <!-- <div class="image-slot">--> |
| | | <!-- <el-icon><Picture /></el-icon>--> |
| | | <!-- <div>图片加载失败</div>--> |
| | | <!-- </div>--> |
| | | <!-- </template>--> |
| | | </el-image> |
| | | |
| | | </div> |
| | | |
| | | |
| | | |
| | | <!-- 操作按钮 --> |
| | | <div class="result-actions"> |
| | | <el-button |
| | | @click='downloadFile' |
| | | type="primary" |
| | | ><template #icon> |
| | | <el-icon><Download/></el-icon> |
| | | </template> |
| | | {{$t("order.msg.pleaseUploadPicture16")}} |
| | | </el-button> |
| | | <el-button |
| | | @click = 'deleteFile' |
| | | :disabled="props.state !== 1" |
| | | ><template #icon> |
| | | <el-icon><Delete /></el-icon> |
| | | </template> |
| | | {{$t("basicData.delete")}} |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-result> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | |
| | | <style scoped> |
| | | |
| | | |
| | | <style scoped> |
| | | .file-upload-container { |
| | | max-width: 800px; |
| | | margin: 0 auto; |
| | | padding: 20px; |
| | | } |
| | | |
| | | .upload-card { |
| | | min-height: 600px; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .header-title { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | :deep(.upload-demo) { |
| | | width: 100%; |
| | | } |
| | | |
| | | :deep(.el-upload-dragger) { |
| | | width: 100%; |
| | | padding: 40px; |
| | | } |
| | | |
| | | .conversion-options { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .action-buttons { |
| | | display: flex; |
| | | gap: 12px; |
| | | justify-content: center; |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .conversion-progress { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .progress-text { |
| | | text-align: center; |
| | | margin-top: 8px; |
| | | color: #666; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .conversion-result { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .result-content { |
| | | text-align: center; |
| | | } |
| | | |
| | | .image-preview { |
| | | margin: 20px 0; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .file-info { |
| | | margin: 20px 0; |
| | | max-width: 400px; |
| | | margin-left: auto; |
| | | margin-right: auto; |
| | | } |
| | | |
| | | .result-actions { |
| | | display: flex; |
| | | gap: 12px; |
| | | justify-content: center; |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .image-slot { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 200px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .image-slot .el-icon { |
| | | font-size: 48px; |
| | | margin-bottom: 16px; |
| | | } |
| | | </style> |