north-glass-erp/northglass-erp/public/config.js
@@ -1,4 +1,4 @@ const ip = 'localhost' const ip = '10.153.19.4' window.ipConfig = { serverUrl:`${ip}:8086`, north-glass-erp/northglass-erp/src/components/pp/PrintProcess.vue
@@ -76,7 +76,9 @@ let printNumberFc = props.printFc data.value.printList = JSON.parse(props.printList) let flowCardCount = '' const picture = ref([]) onMounted(() => { //判断是否是工程打印 if(props.printProject!=null){ request.post(`/processCard/getSelectPrintProject/${printProject}/${merges}/${props.flashback}/${props.landingSequence}`).then((res) => { if (res.code == 200) { @@ -87,6 +89,7 @@ } }) }else{ //流程卡 request.post(`/processCard/getSelectPrinting/${merge}/${like}/${merges}/${props.flashback}/${compound}/${props.landingSequence}`, data.value).then((res) => { if (res.code == 200) { load(res.data.data) @@ -94,6 +97,10 @@ ElMessage.warning(res.msg) router.push("/login") } }) //订单序号dwg图片查询 request.post("/orderFile/getOrderFilePicture", data.value.printList).then((res) => { picture.value = res.data }) } @@ -292,7 +299,7 @@ 打印人:{{user.user.userName}} 时间:{{formattedTime}} <span style="font-weight: bolder;" v-if="name=='金华福喜天成玻璃有限公司'"> <span style="font-weight: bolder;" > 打印总数量:{{totalQuantity}} 打印总面积:{{totalArea}} </span> @@ -453,7 +460,14 @@ </tr> </tfoot> </table> <el-image class="picture" v-for="(item,index) in picture" :src="item.imageBase64" :preview-src-list="[item.imageBase64]" fit="contain" style="max-height: 700px;" /> </div> </template> @@ -545,6 +559,8 @@ width: 100%; height: 100%; } .picture{ page-break-before: always; } </style> north-glass-erp/northglass-erp/src/components/sd/order/PrintSheet4.vue
@@ -38,7 +38,6 @@ }) const getData = () => { request.get(`/order/printOrderProductDetail/${props.orderId}/${selectedValues.value}`).then(res => { console.log(res.data) data.value= res.data productIdData.value=data.value.orderProductDetail data.value.orderProductDetail.forEach(item => { north-glass-erp/northglass-erp/src/components/sd/order/UpdateAlienEditor.vue
@@ -40,7 +40,7 @@ const emits = defineEmits(['getUploadPicture']) let fileName=ref(null) let fileDate=ref(null) let fileData=ref(null) let fileJson=ref({ quadrilateral:null, polygon:null @@ -638,7 +638,7 @@ const base64 = await fileToBase64(blob); if(value===1){ fileName.value="map.dxf" fileDate.value=base64.replace(/^data:.+;base64,/, "") fileData.value=base64.replace(/^data:.+;base64,/, "") } else if(value===2&&state.value){ saveAs(blob, 'map.dxf'); @@ -689,7 +689,7 @@ handleFileUpload() fileName.value=file.name fileDate.value=base64.replace(/^data:.+;base64,/, "") fileData.value=base64.replace(/^data:.+;base64,/, "") } catch (error) { console.error('解析DXF文件时出错:', error); } @@ -1025,13 +1025,13 @@ //保存方法 const save = () => { if(fileName.value!=null&&fileDate.value!=null){ if(fileName.value!=null&&fileData.value!=null){ fileJson.value.quadrilateral=[parseInt(data5.value),parseInt(data6.value),parseInt(data1.value),parseInt(data2.value), parseInt(data3.value),parseInt(data4.value),parseInt(data7.value),parseInt(data8.value)] if(fileJson.value.quadrilateral==null&&fileJson.value.polygon==null){ fileJson.value=null } emits('getUploadPicture', fileName.value,fileDate.value,fileJson.value) emits('getUploadPicture', fileName.value,fileData.value,fileJson.value) }else{ ElMessage.warning("未参与修改") north-glass-erp/northglass-erp/src/components/sd/order/UploadPicture.vue
@@ -1,46 +1,423 @@ <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 } from '@element-plus/icons-vue' import { ElMessage, ElMessageBox } from 'element-plus' import request from "@/utils/requestByFile" const emits = defineEmits(['getUploadPicture']) 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 props = defineProps({ rowIndex:null, orderId:null }) const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => { console.log(uploadFile, uploadFiles) const form = reactive({ format: 'png' }) onMounted(() => { //loadSupportedFormats() }) const loadSupportedFormats = async () => { try { if (fileList.value.length === 0) { ElMessage.warning('请先选择要上传的DWG文件') return } loadingFormats.value = true converting.value = true progressPercentage.value = 0 progressStatus.value = '' progressText.value = '准备上传...' // 模拟进度更新 const progressInterval = setInterval(() => { if (progressPercentage.value < 80) { progressPercentage.value += 10 progressText.value = `上传中... ${progressPercentage.value}%` } }, 500) const data ={ file:fileList.value[0].raw } request.post(`/orderFile/updateOrderFileByOrderNumber/${props.orderId}/${props.rowIndex.orderNumber}`,data).then(res=>{ if (res.code === '200') { conversionResult.value = res.data uploadRef.value.clearFiles() clearInterval(progressInterval) progressPercentage.value = 100 progressStatus.value = 'success' progressText.value = '上传完成!' uploadRef.value.clearFiles() fileList.value = [] setTimeout(() => { converting.value = false },2000) } }) } catch (error) { console.error('保存失败:', error) } finally { loadingFormats.value = false } } const handlePreview: UploadProps['onPreview'] = (file) => { console.log(file) } const handleChange = (uploadFile, uploadFiles) => { emits('getUploadPicture', uploadFile.name,uploadFile) upload.value.clearFiles() const handleFileChange = (file) => { if (!(file.raw.name.toLowerCase().endsWith('.dwg') || file.raw.name.toLowerCase().endsWith('.dxf'))) { ElMessage.error('请选择DWG或DXF格式的文件') uploadRef.value.clearFiles() return } if (file.raw.size > 50 * 1024 * 1024) { ElMessage.error('文件大小不能超过50MB') uploadRef.value.clearFiles() return } fileList.value = [file] ElMessage.success(`已选择文件: ${file.name}`) } const handleFileRemove = () => { conversionResult.value = null uploadRef.value.clearFiles() } /*const handleConvert = async () => { if (fileList.value.length === 0) { ElMessage.warning('请先选择要上传的DWG文件') return } if (!form.format) { ElMessage.warning('请选择输出格式') return } try { converting.value = true progressPercentage.value = 0 progressStatus.value = '' progressText.value = '准备转换...' // 模拟进度更新 const progressInterval = setInterval(() => { if (progressPercentage.value < 80) { progressPercentage.value += 10 progressText.value = `转换中... ${progressPercentage.value}%` } }, 500) const file = fileList.value[0].raw //const response = await cadApi.convertDwgToImage(file, form.format) const response = null clearInterval(progressInterval) progressPercentage.value = 100 progressStatus.value = 'success' progressText.value = '转换完成!' conversionResult.value = response.data ElMessage.success('文件转换成功!') } catch (error) { progressStatus.value = 'exception' progressText.value = '转换失败' console.error('转换失败:', error) } finally { converting.value = false } }*/ const handleDownload = () => { if (!conversionResult.value) return const link = document.createElement('a') link.href = conversionResult.value.imageData link.download = conversionResult.value.fileName document.body.appendChild(link) link.click() document.body.removeChild(link) ElMessage.success('文件下载开始') } const handleNewConversion = () => { ElMessageBox.confirm('是否开始新的文件上传?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }).then(() => { handleReset() ElMessage.success('已重置,可以开始新的上传') }) } const handleReset = () => { uploadRef.value.clearFiles() fileList.value = [] conversionResult.value = null progressPercentage.value = 0 progressStatus.value = '' progressText.value = '' form.format = 'png' } 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> DWG文件上传 </span> </div> </template> <!-- 文件上传区域 --> <el-upload ref="uploadRef" class="upload-demo" drag action="" :auto-upload="false" :on-change="handleFileChange" :on-remove="handleFileRemove" :file-list="fileList" :limit="1" :accept="'.dwg' || '.dxf' " :disabled="converting" > <el-icon class="el-icon--upload"><UploadFilled /></el-icon> <div class="el-upload__text"> 拖拽DWG文件到此处或 <em>点击选择文件</em> </div> <template #tip> <div class="el-upload__tip"> 仅支持 .dwg 格式文件,且文件大小不超过50MB </div> </template> </el-upload> <!-- 上传选项 --> <div class="conversion-options"> <div class="action-buttons"> <el-button type="primary" :loading="converting" @click="loadSupportedFormats" :disabled="!form.format" > <template #icon> <el-icon><MagicStick /></el-icon> </template> 保存 </el-button> <el-button @click="handleReset" :loading="converting"> <template #icon> <el-icon><RefreshLeft /></el-icon> </template> 重置 </el-button> </div> </div> </template> </el-upload> <!-- 转换进度 --> <div v-if="converting" class="conversion-progress"> <el-divider content-position="left">上传进度</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">上传结果</el-divider> <el-result icon="success" :sub-title="`文件已成功转格式`" > <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 type="primary" @click="handleDownload" :icon="Download" > 下载图片 </el-button> <el-button @click="handleNewConversion" :icon="Plus" > 新的上传 </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> north-glass-erp/northglass-erp/src/utils/requestByFile.js
New file @@ -0,0 +1,56 @@ import axios from 'axios' import useUserInfoStore from '@/stores/userInfo' const userStore=useUserInfoStore() const request = axios.create({ baseURL: `http://${window.ipConfig.serverUrl}`, // 注意!! 这里是全局统一加上了 后端接口前缀 前缀,后端必须进行跨域配置! timeout: 60000 }) // // request 拦截器 // 可以自请求发送前对请求做一些处理 // 比如统一加token,对请求参数统一加密 request.interceptors.request.use(config => { config.headers['Content-Type'] = 'multipart/form-data'; if(userStore.user){ config.headers['satoken'] = localStorage.getItem('saToken'); } // 设置请求头 return config }, error => { return Promise.reject(error) }); // response 拦截器 // 可以在接口响应后统一处理结果 request.interceptors.response.use( response => { let res = response.data //传递报错信息,把报错信息传递到pinia中 userStore.setResponseCode(parseInt(res.code),res.msg) if(res.code!=='200' ){ if(response.config.responseType !== 'blob'){ return Promise.reject(res.code) } } // 如果是返回的文件 if (response.config.responseType === 'blob') { return res } // 兼容服务端返回的字符串数据 if (typeof res === 'string') { res = res ? JSON.parse(res) : res } return res; }, error => { console.log('err' + error) // for debug return Promise.reject(error) } ) export default request north-glass-erp/northglass-erp/src/views/sd/order/CADDraw.vue
File was deleted north-glass-erp/northglass-erp/src/views/sd/order/CreateOrder.vue
@@ -1950,7 +1950,7 @@ style="width: 100%;height: 100%" /> </el-dialog> <!--异形导入--> <el-dialog v-model="alienEditorVisible" <!-- <el-dialog v-model="alienEditorVisible" :title="$t('')" :close-on-click-modal="false" :close-on-press-escape="false" @@ -1961,7 +1961,7 @@ :rowIndex="rowIndex" @getUploadPicture="getUploadPicture" style="width: 100%;height: 100%" /> </el-dialog> </el-dialog>--> <!-- 尺寸审核窗口--> <el-dialog @@ -1997,10 +1997,14 @@ <order-number-report-transfer :transferData="transferData" @orderNumberTransfer="orderNumberTransfer"/> </el-dialog> <el-dialog v-model="uploadPictureVisible" <el-dialog id="loadDWG" v-model="alienEditorVisible" :close-on-click-modal="false" destroy-on-close width="500"> <upload-picture /> destroy-on-close width="800px"> <upload-picture :rowIndex="rowIndex" :orderId="titleUploadData.orderId" /> </el-dialog> @@ -2051,4 +2055,9 @@ /*flex-direction : row; justify-content: space-between;*/ } :deep(#loadDWG .el-dialog__body){ height: 70vh; overflow-y: auto; } </style> north-glass-erp/pom.xml
@@ -161,7 +161,16 @@ <version>6.1.5.Final</version> </dependency> <dependency> <groupId>com.aspose</groupId> <artifactId>aspose-cad</artifactId> <version>23.9</version> </dependency> </dependencies> <build> <plugins> @@ -181,19 +190,15 @@ </build> <!-- <repositories>--> <!-- <repository>--> <!-- <id>nexus-aliyun</id>--> <!-- <name>nexus-aliyun</name>--> <!-- <url>http://maven.aliyun.com/nexus/content/groups/public/</url>--> <!-- <releases>--> <!-- <enabled>true</enabled>--> <!-- </releases>--> <!-- <snapshots>--> <!-- <enabled>false</enabled>--> <!-- </snapshots>--> <!-- </repository>--> <!-- </repositories>--> <repositories> <repository> <id>aspose-maven-repository</id> <url>https://releases.aspose.com/java/repo</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <!-- <pluginRepositories>--> <!-- <pluginRepository>--> @@ -208,4 +213,4 @@ <!-- </snapshots>--> <!-- </pluginRepository>--> <!-- </pluginRepositories>--> </project> </project> north-glass-erp/src/main/java/com/example/erp/ErpApplication.java
@@ -1,11 +1,9 @@ package com.example.erp; import com.example.erp.tools.netty.NettyServer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Transactional; //springboot 启动入口 @SpringBootApplication north-glass-erp/src/main/java/com/example/erp/controller/pp/ReportController.java
@@ -40,7 +40,6 @@ return Result.success(reportService.processCardProgressReportSv(orderId, columns)); } @ApiOperation("流程卡进度汇总") @SaCheckPermission("selectOrder.search") @PostMapping("/processCardProgressCollect/{orderId}") public Result processCardProgressCollect(@PathVariable String orderId, @RequestBody List<String> columns) { return Result.success(reportService.processCardProgressCollectSv(orderId, columns)); north-glass-erp/src/main/java/com/example/erp/controller/sd/OrderFileController.java
New file @@ -0,0 +1,32 @@ package com.example.erp.controller.sd; import com.aspose.cad.internal.V.S; import com.example.erp.common.Result; import com.example.erp.entity.sd.OrderDetail; import com.example.erp.service.sd.OrderFileService; import io.swagger.annotations.Api; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.List; import java.util.Map; @RestController @Api(value="订单文件controller",tags={"订单文件操作接口"}) @RequestMapping("/orderFile") @RequiredArgsConstructor public class OrderFileController { private final OrderFileService orderFileService; @PostMapping("/updateOrderFileByOrderNumber/{orderId}/{orderNumber}") public Result updateOrderFileByOrderNumber(@RequestParam("file") MultipartFile file, @PathVariable String orderId, @PathVariable String orderNumber) throws IOException { return Result.success(orderFileService.updateOrderFileByOrderNumber(file,orderId,orderNumber)); } @PostMapping("/getOrderFilePicture") public Result getOrderFilePicture(@RequestBody List<Map<String,Object>> orderDetails) throws NoSuchFieldException { return Result.success(orderFileService.getOrderFilePicture(orderDetails)); } } north-glass-erp/src/main/java/com/example/erp/entity/sd/OrderFile.java
New file @@ -0,0 +1,22 @@ package com.example.erp.entity.sd; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.time.LocalDateTime; @Data @TableName("sd.`order_file`") public class OrderFile { @TableId(type = IdType.AUTO) private Integer id; private String orderId; private String orderNumber; private String fileName; private String fileData; private String imageBase64; private LocalDateTime createTime; } north-glass-erp/src/main/java/com/example/erp/mapper/sd/OrderFileMapper.java
New file @@ -0,0 +1,9 @@ package com.example.erp.mapper.sd; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.erp.entity.sd.OrderFile; import org.apache.ibatis.annotations.Mapper; @Mapper public interface OrderFileMapper extends BaseMapper<OrderFile> { } north-glass-erp/src/main/java/com/example/erp/service/sd/OrderFileService.java
New file @@ -0,0 +1,101 @@ package com.example.erp.service.sd; import com.aspose.cad.Image; import com.aspose.cad.ImageOptionsBase; import com.aspose.cad.imageoptions.CadRasterizationOptions; import com.aspose.cad.imageoptions.PngOptions; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.example.erp.common.Result; import com.example.erp.entity.sd.OrderDetail; import com.example.erp.entity.sd.OrderFile; import com.example.erp.mapper.sd.OrderFileMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class OrderFileService { private final OrderFileMapper orderFileMapper; public List<OrderFile> getOrderFilePicture(List<Map<String,Object>> orderDetails) throws NoSuchFieldException { Set<String> seenKeys = new HashSet<>(); List<Map<String,Object>> result = new ArrayList<>(); // 遍历订单详情列表去重 result = orderDetails.stream() .collect(Collectors.collectingAndThen( Collectors.toMap( map -> map.get("order_id") + "_" + map.get("order_number"), map -> map, (existing, replacement) -> existing // 保留第一个出现的 ), map -> new ArrayList<>(map.values()) )); //循环获取图片 List<OrderFile> orderFiles = new ArrayList<>(); for (Map<String,Object> obj : result) { OrderFile orderFile = orderFileMapper.selectOne(new QueryWrapper<OrderFile>() .select("order_id, order_number, image_base64") .eq("order_id", obj.get("order_id")) .eq("order_number", obj.get("order_number")) ); if (orderFile != null){ orderFiles.add(orderFile); } } return orderFiles; } public Object updateOrderFileByOrderNumber(MultipartFile file,String orderId,String orderNumber) throws IOException { // 调用Image类的Load方法来加载输入的DWG文件。 Image image = Image.load(file.getInputStream()); // 创建CadRasterizationOptions实例以启用CAD栅格化选项。 CadRasterizationOptions rasterizationOptions = new CadRasterizationOptions(); // 设置宽度 rasterizationOptions.setPageWidth(1000); // 设置高度 rasterizationOptions.setPageHeight(1000); // 调用这个setEmbedBackground方法来设置背景色是否不等于输出格式的默认背景色 rasterizationOptions.setEmbedBackground(true); // 为生成的图像创建一个PngOptions的实例,并将其分配给ImageOptionsBase类的实例。 ImageOptionsBase options = new PngOptions(); // 调用 setVectorRasterizationOptions 方法来定义光栅化选项 options.setVectorRasterizationOptions(rasterizationOptions); // 保存到字节流 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); image.save(outputStream, options); byte[] imageBytes = outputStream.toByteArray(); String base64 = "data:image/png;base64," + Base64.getEncoder().encodeToString(imageBytes); OrderFile orderFile = new OrderFile(); orderFile.setImageBase64(base64); orderFile.setFileName(file.getName()); orderFile.setOrderId(orderId); orderFile.setOrderNumber(orderNumber); orderFile.setFileData(Arrays.toString(file.getBytes())); OrderFile orderFileExist = orderFileMapper .selectOne(new LambdaQueryWrapper<OrderFile>() .eq(OrderFile::getOrderId, orderId) .eq(OrderFile::getOrderNumber, orderNumber) ); if (orderFileExist == null) { orderFileMapper.insert(orderFile); }else { orderFileMapper.update(orderFile,new LambdaUpdateWrapper<OrderFile>() .eq(OrderFile::getOrderId, orderId) .eq(OrderFile::getOrderNumber, orderNumber) ); } return base64; } } north-glass-erp/src/main/resources/application.yml
@@ -14,6 +14,10 @@ spring: # profiles: # active: prod servlet: multipart: max-file-size: 50MB max-request-size: 50MB datasource: dynamic: primary: user_info #设置默认的数据源或者数据源组,默认值即为master