16个文件已修改
1 文件已重命名
8个文件已添加
| | |
| | | |
| | | /north-glass-erp/src/test/test.iml |
| | | |
| | | /north-glass-erp/.idea/libraries |
| | | /north-glass-erp/.idea |
| | | /north-glass-erp/src/.idea |
| | | /north-glass-erp/src/main/main.iml |
| | |
| | | } |
| | | }, |
| | | "node_modules/@babel/runtime": { |
| | | "version": "7.25.0", |
| | | "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.25.0.tgz", |
| | | "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", |
| | | "version": "7.26.10", |
| | | "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.10.tgz", |
| | | "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", |
| | | "dependencies": { |
| | | "regenerator-runtime": "^0.14.0" |
| | | }, |
| | |
| | | "integrity": "sha512-FKWIhiU96bi3xpP9ewRMgANsoVmMUBnMnmpCT6dPMZOunVYJQmJhSRruoI0XSPoHeIif3kyEuiHbFrOJwEJaEA==", |
| | | "license": "MIT" |
| | | }, |
| | | "node_modules/dompurify": { |
| | | "version": "2.5.6", |
| | | "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.5.6.tgz", |
| | | "integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==", |
| | | "optional": true |
| | | }, |
| | | "node_modules/element-plus": { |
| | | "version": "2.9.3", |
| | | "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.3.tgz", |
| | |
| | | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" |
| | | }, |
| | | "node_modules/fflate": { |
| | | "version": "0.4.8", |
| | | "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.4.8.tgz", |
| | | "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" |
| | | "version": "0.8.2", |
| | | "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz", |
| | | "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" |
| | | }, |
| | | "node_modules/file-saver": { |
| | | "version": "2.0.5", |
| | |
| | | "version": "3.11.6", |
| | | "resolved": "https://registry.npmmirror.com/jsbarcode/-/jsbarcode-3.11.6.tgz", |
| | | "integrity": "sha512-G5TKGyKY1zJo0ZQKFM1IIMfy0nF2rs92BLlCz+cU4/TazIc4ZH+X1GYeDRt7TKjrYqmPfTjwTBkU/QnQlsYiuA==" |
| | | }, |
| | | "node_modules/jspdf": { |
| | | "version": "2.5.1", |
| | | "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.1.tgz", |
| | | "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", |
| | | "dependencies": { |
| | | "@babel/runtime": "^7.14.0", |
| | | "atob": "^2.1.2", |
| | | "btoa": "^1.2.1", |
| | | "fflate": "^0.4.8" |
| | | }, |
| | | "optionalDependencies": { |
| | | "canvg": "^3.0.6", |
| | | "core-js": "^3.6.0", |
| | | "dompurify": "^2.2.0", |
| | | "html2canvas": "^1.0.0-rc.5" |
| | | } |
| | | }, |
| | | "node_modules/local-pkg": { |
| | | "version": "0.4.3", |
| | |
| | | "socket.io-client": "^4.5.1" |
| | | } |
| | | }, |
| | | "node_modules/vue-plugin-hiprint/node_modules/dompurify": { |
| | | "version": "2.5.8", |
| | | "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.5.8.tgz", |
| | | "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==", |
| | | "optional": true |
| | | }, |
| | | "node_modules/vue-plugin-hiprint/node_modules/jspdf": { |
| | | "version": "2.5.2", |
| | | "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.2.tgz", |
| | | "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==", |
| | | "dependencies": { |
| | | "@babel/runtime": "^7.23.2", |
| | | "atob": "^2.1.2", |
| | | "btoa": "^1.2.1", |
| | | "fflate": "^0.8.1" |
| | | }, |
| | | "optionalDependencies": { |
| | | "canvg": "^3.0.6", |
| | | "core-js": "^3.6.0", |
| | | "dompurify": "^2.5.4", |
| | | "html2canvas": "^1.0.0-rc.5" |
| | | } |
| | | }, |
| | | "node_modules/vue-router": { |
| | | "version": "4.2.5", |
| | | "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz", |
| | |
| | | "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" |
| | | }, |
| | | "@babel/runtime": { |
| | | "version": "7.25.0", |
| | | "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.25.0.tgz", |
| | | "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", |
| | | "version": "7.26.10", |
| | | "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.10.tgz", |
| | | "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", |
| | | "requires": { |
| | | "regenerator-runtime": "^0.14.0" |
| | | }, |
| | |
| | | "resolved": "https://registry.npmmirror.com/dom-zindex/-/dom-zindex-1.0.6.tgz", |
| | | "integrity": "sha512-FKWIhiU96bi3xpP9ewRMgANsoVmMUBnMnmpCT6dPMZOunVYJQmJhSRruoI0XSPoHeIif3kyEuiHbFrOJwEJaEA==" |
| | | }, |
| | | "dompurify": { |
| | | "version": "2.5.6", |
| | | "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.5.6.tgz", |
| | | "integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==", |
| | | "optional": true |
| | | }, |
| | | "element-plus": { |
| | | "version": "2.9.3", |
| | | "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.3.tgz", |
| | |
| | | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" |
| | | }, |
| | | "fflate": { |
| | | "version": "0.4.8", |
| | | "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.4.8.tgz", |
| | | "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" |
| | | "version": "0.8.2", |
| | | "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz", |
| | | "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" |
| | | }, |
| | | "file-saver": { |
| | | "version": "2.0.5", |
| | |
| | | "version": "3.11.6", |
| | | "resolved": "https://registry.npmmirror.com/jsbarcode/-/jsbarcode-3.11.6.tgz", |
| | | "integrity": "sha512-G5TKGyKY1zJo0ZQKFM1IIMfy0nF2rs92BLlCz+cU4/TazIc4ZH+X1GYeDRt7TKjrYqmPfTjwTBkU/QnQlsYiuA==" |
| | | }, |
| | | "jspdf": { |
| | | "version": "2.5.1", |
| | | "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.1.tgz", |
| | | "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", |
| | | "requires": { |
| | | "@babel/runtime": "^7.14.0", |
| | | "atob": "^2.1.2", |
| | | "btoa": "^1.2.1", |
| | | "canvg": "^3.0.6", |
| | | "core-js": "^3.6.0", |
| | | "dompurify": "^2.2.0", |
| | | "fflate": "^0.4.8", |
| | | "html2canvas": "^1.0.0-rc.5" |
| | | } |
| | | }, |
| | | "local-pkg": { |
| | | "version": "0.4.3", |
| | |
| | | "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" |
| | | }, |
| | | "@babel/runtime": { |
| | | "version": "7.25.0", |
| | | "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.25.0.tgz", |
| | | "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", |
| | | "version": "7.26.10", |
| | | "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.10.tgz", |
| | | "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", |
| | | "requires": { |
| | | "regenerator-runtime": "^0.14.0" |
| | | }, |
| | |
| | | "resolved": "https://registry.npmmirror.com/dom-zindex/-/dom-zindex-1.0.6.tgz", |
| | | "integrity": "sha512-FKWIhiU96bi3xpP9ewRMgANsoVmMUBnMnmpCT6dPMZOunVYJQmJhSRruoI0XSPoHeIif3kyEuiHbFrOJwEJaEA==" |
| | | }, |
| | | "dompurify": { |
| | | "version": "2.5.6", |
| | | "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.5.6.tgz", |
| | | "integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==", |
| | | "optional": true |
| | | }, |
| | | "element-plus": { |
| | | "version": "2.9.3", |
| | | "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.3.tgz", |
| | |
| | | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" |
| | | }, |
| | | "fflate": { |
| | | "version": "0.4.8", |
| | | "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.4.8.tgz", |
| | | "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" |
| | | "version": "0.8.2", |
| | | "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz", |
| | | "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" |
| | | }, |
| | | "file-saver": { |
| | | "version": "2.0.5", |
| | |
| | | "version": "3.11.6", |
| | | "resolved": "https://registry.npmmirror.com/jsbarcode/-/jsbarcode-3.11.6.tgz", |
| | | "integrity": "sha512-G5TKGyKY1zJo0ZQKFM1IIMfy0nF2rs92BLlCz+cU4/TazIc4ZH+X1GYeDRt7TKjrYqmPfTjwTBkU/QnQlsYiuA==" |
| | | }, |
| | | "jspdf": { |
| | | "version": "2.5.1", |
| | | "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.1.tgz", |
| | | "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", |
| | | "requires": { |
| | | "@babel/runtime": "^7.14.0", |
| | | "atob": "^2.1.2", |
| | | "btoa": "^1.2.1", |
| | | "canvg": "^3.0.6", |
| | | "core-js": "^3.6.0", |
| | | "dompurify": "^2.2.0", |
| | | "fflate": "^0.4.8", |
| | | "html2canvas": "^1.0.0-rc.5" |
| | | } |
| | | }, |
| | | "local-pkg": { |
| | | "version": "0.4.3", |
| | |
| | | "jspdf": "^2.5.1", |
| | | "nzh": "^1.0.8", |
| | | "socket.io-client": "^4.5.1" |
| | | }, |
| | | "dependencies": { |
| | | "dompurify": { |
| | | "version": "2.5.8", |
| | | "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.5.8.tgz", |
| | | "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==", |
| | | "optional": true |
| | | }, |
| | | "jspdf": { |
| | | "version": "2.5.2", |
| | | "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.2.tgz", |
| | | "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==", |
| | | "requires": { |
| | | "@babel/runtime": "^7.23.2", |
| | | "atob": "^2.1.2", |
| | | "btoa": "^1.2.1", |
| | | "canvg": "^3.0.6", |
| | | "core-js": "^3.6.0", |
| | | "dompurify": "^2.5.4", |
| | | "fflate": "^0.8.1", |
| | | "html2canvas": "^1.0.0-rc.5" |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | "vue-router": { |
| | |
| | | "jspdf": "^2.5.1", |
| | | "nzh": "^1.0.8", |
| | | "socket.io-client": "^4.5.1" |
| | | }, |
| | | "dependencies": { |
| | | "dompurify": { |
| | | "version": "2.5.8", |
| | | "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.5.8.tgz", |
| | | "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==", |
| | | "optional": true |
| | | }, |
| | | "jspdf": { |
| | | "version": "2.5.2", |
| | | "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.2.tgz", |
| | | "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==", |
| | | "requires": { |
| | | "@babel/runtime": "^7.23.2", |
| | | "atob": "^2.1.2", |
| | | "btoa": "^1.2.1", |
| | | "canvg": "^3.0.6", |
| | | "core-js": "^3.6.0", |
| | | "dompurify": "^2.5.4", |
| | | "fflate": "^0.8.1", |
| | | "html2canvas": "^1.0.0-rc.5" |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | "vue-router": { |
| | |
| | | // MockData.js
|
| | | const mockLayoutData = {
|
| | | result: "ok",
|
| | | data: {
|
| | | |
| | | Layouts: [
|
| | | {
|
| | | mnumber: 9,
|
| | |
| | | }
|
| | | ],
|
| | | method: "getResult"
|
| | | }
|
| | | |
| | | };
|
| | |
|
| | | export default mockLayoutData;
|
New file |
| | |
| | | {
|
| | | "optimization": {
|
| | | "yShapeJoinOptimization": "1",
|
| | | "autoMiddleEmptyPairing": "1",
|
| | | "smallPieceRotationProhibited": "1",
|
| | | "maxFramesOnSite": "10",
|
| | | "bendEdgeDistance": "5",
|
| | | "positiveTolerance": "0",
|
| | | "negativeTolerance": "0",
|
| | | "cutterOriginPosition": "topLeft",
|
| | | "uniformShapeEdgeTrimAmount": "5",
|
| | | "edgeTrimMode": "intelligent",
|
| | | "parallelOptimizationChannels": "2",
|
| | | "optimizationIterations": "1",
|
| | | "finishedProductGrindingAmount": "0",
|
| | | "rawPieceEdgeTrimAmount": "0",
|
| | | "finishedSinglePieceBelowGrindingAmount": "500"
|
| | | },
|
| | | "display": {
|
| | | "themeColor": "#ffffff",
|
| | | "includeProductEdge": true,
|
| | | "includeIrregularEdge": true,
|
| | | "mergeByFrameNumber": true,
|
| | | "frameNumber": true,
|
| | | "orderNumber": true,
|
| | | "productName": true,
|
| | | "processingInfo": true,
|
| | | "remarks": true,
|
| | | "floorNumber": true,
|
| | | "edgeLength": true,
|
| | | "manufacturingProcess": true,
|
| | | "identifier": true
|
| | | },
|
| | | "cutting": {
|
| | | "cutting_direction": true,
|
| | | "show_cutting_path": true,
|
| | | "force_continuous_cutting": true,
|
| | | "min_radius": 5,
|
| | | "min_parallel_offset": 0.1,
|
| | | "t_shaped_recess": 2,
|
| | | "down_cut_spacing": 0.5,
|
| | | "lift_retract": 1
|
| | | },
|
| | | "server": {
|
| | | "output_format": "json",
|
| | | "save_location": "local",
|
| | | "auto_save": true,
|
| | | "save_interval": 60,
|
| | | "engineering_file_save_path": "",
|
| | | "cutting_code_save_path": "",
|
| | | "open_folder_after_save": "",
|
| | | "g_code_file_format": "",
|
| | | "trf_file_save_path": "",
|
| | | "btl_file_save_path": "",
|
| | | "optima_file_save_path": "",
|
| | | "optimization_depth_limit_enable": "",
|
| | | "original_sheet_material_calculation": ""
|
| | | },
|
| | | "tempering": {
|
| | | "tempering_temp": 600,
|
| | | "cooling_rate": 50,
|
| | | "annealing_time": 3600,
|
| | | "furnaceLength": 0,
|
| | | "furnaceWidth": 0,
|
| | | "maxLoadingRate": 100,
|
| | | "chaosLevel": 0,
|
| | | "temperingTime": 1200,
|
| | | "defaultTemperingMode": "auto",
|
| | | "maxArea": 100,
|
| | | "maxPieceCount": 100,
|
| | | "xAxisInterval": 10,
|
| | | "yAxisInterval": 10
|
| | | }
|
| | | }
|
| | |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | path: '/main/glassOptimize/MoveManage', |
| | | component: () => import('@/views/pp/glassOptimize/MoveManage.vue') |
| | | }, |
| | | { |
| | | path:'userPassWord', |
| | | name: 'userPassWord', |
| | |
| | | component: () => import('../views/pp/glassOptimize/OptimizePrint.vue'), |
| | | }, |
| | | { |
| | | path: 'optimizeMove', |
| | | name: 'optimizeMove', |
| | | component: () => import('../views/pp/glassOptimize/OptimizeMove.vue'), |
| | | path: 'OptimizationRectPrint', |
| | | name: 'OptimizationRectPrint', |
| | | component: () => import('../views/pp/glassOptimize/OptimizationRectPrint.vue'), |
| | | }, |
| | | { |
| | | path: 'OptimizeControl', |
| | | name: 'OptimizeControl', |
| | | component: () => import('../views/pp/glassOptimize/OptimizeControl.vue'), |
| | | }, |
| | | { |
| | | path: 'Optimization', |
| | | name: 'Optimization', |
| | | component: () => import('../views/pp/glassOptimize/Optimization.vue'), |
| | | }, |
| | | { |
| | | path: 'optimizeparms', |
| | | name: 'optimizeparms', |
| | | component: () => import('../views/pp/glassOptimize/OptimizeParms.vue'), |
| | | }, |
| | | { |
| | | path: '/optimizeProject/:projectNo/:thickNess/:model', |
New file |
| | |
| | | <template>
|
| | | <div>
|
| | | <RectRenderer |
| | | :layoutData="layoutData" |
| | | :gw="1150" |
| | | :gh="850" |
| | | style="width: 1000px; height: 800px; position: relative;"
|
| | | />
|
| | | </div>
|
| | | </template>
|
| | |
|
| | | <script setup>
|
| | | import { ref,onMounted } from 'vue';
|
| | | import RectRenderer from './page/OptimizationRect.vue';
|
| | | import mockLayoutData from '../../../components/pp/MockData';
|
| | | import request from "@/utils/request";
|
| | | import { useI18n } from "vue-i18n";
|
| | | import { ElMessage } from "element-plus";
|
| | |
|
| | | const { t } = useI18n();
|
| | | //const layoutData = ref(mockLayoutData);
|
| | | // const processId = "P25030309";
|
| | | const savedProjectNo = localStorage.getItem('projectNo');
|
| | | const processId = savedProjectNo;
|
| | | console.log(processId)
|
| | | const layoutData = ref(null);
|
| | |
|
| | | const selectLayout = () => {
|
| | | request.post(`/glassOptimize/selectOptimizeResult/${processId}`)
|
| | | .then((res) => {
|
| | | if (res.code == 200) {
|
| | | try {
|
| | | // 将字符串数据转换为对象
|
| | | // console.log("原始数据:", res.data.data[0].Layouts);
|
| | |
|
| | | const parsedData = JSON.parse(res.data.data[0].Layouts);
|
| | | layoutData.value = parsedData;
|
| | | // console.log("解析后的数据:", layoutData.value);
|
| | | // console.log("数据类型:", typeof parsedData);
|
| | | ElMessage.success("打开版图成功")
|
| | | } catch (error) {
|
| | | ElMessage.error("解析数据时出错:", error);
|
| | | |
| | | }
|
| | | } else {
|
| | |
|
| | | }
|
| | | })
|
| | | .catch((error) => {
|
| | | console.error("请求失败:", error);
|
| | | ElMessage.error(t('basicData.msg.requestFailed'));
|
| | | });
|
| | | }
|
| | |
|
| | | onMounted(() => {
|
| | | selectLayout();
|
| | |
|
| | | });
|
| | | </script>
|
New file |
| | |
| | | <template> |
| | | <div> |
| | | <button @click="handlePrint" style="position: fixed; bottom: 20px; right: 20px; padding: 10px; background: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer;">打印版图</button> |
| | | <RectRenderer |
| | | ref="rectRenderer" |
| | | :layoutData="layoutData" |
| | | :gw="1400" |
| | | :gh="1100" |
| | | style="width: 100%; height: 800px; position: relative;" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue'; |
| | | import RectRenderer from './page/RectRenderer.vue'; |
| | | import mockLayoutData from '../../../components/pp/MockData'; |
| | | |
| | | const layoutData = ref(mockLayoutData); |
| | | const rectRenderer = ref(null); |
| | | |
| | | const handlePrint = () => { |
| | | // 创建一个隐藏的iframe |
| | | const iframe = document.createElement('iframe'); |
| | | iframe.style.position = 'fixed'; |
| | | iframe.style.top = '-100vh'; |
| | | iframe.style.left = '-100vw'; |
| | | iframe.style.width = '200%'; |
| | | iframe.style.height = '200%'; |
| | | document.body.appendChild(iframe); |
| | | |
| | | // 将RectRenderer的内容加载到iframe中 |
| | | const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; |
| | | iframeDoc.open(); |
| | | iframeDoc.write(` |
| | | <html> |
| | | <head> |
| | | <title>Print Layout</title> |
| | | <style> |
| | | @page { |
| | | size: A4 landscape; |
| | | margin: 20mm; |
| | | } |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | .layout-wrapper { |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .layout-container { |
| | | page-break-inside: avoid; |
| | | break-inside: avoid; |
| | | page-break-after: auto; |
| | | margin-bottom: 20mm; |
| | | } |
| | | .layout-item { |
| | | page-break-inside: avoid; |
| | | break-inside: avoid; |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | <div class="layout-wrapper"> |
| | | ${rectRenderer.value.$el.outerHTML} |
| | | </div> |
| | | </body> |
| | | </html> |
| | | `); |
| | | iframeDoc.close(); |
| | | |
| | | // 设置打印样式 |
| | | const printStyle = iframeDoc.createElement('style'); |
| | | printStyle.type = 'text/css'; |
| | | printStyle.innerHTML = ` |
| | | @page { |
| | | size: A4 landscape; |
| | | margin: 20mm; |
| | | } |
| | | body { |
| | | -webkit-print-color-adjust: exact; |
| | | } |
| | | .layout-wrapper { |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .layout-container { |
| | | page-break-inside: avoid; |
| | | break-inside: avoid; |
| | | page-break-after: auto; |
| | | margin-bottom: 20mm; |
| | | } |
| | | .layout-item { |
| | | page-break-inside: avoid; |
| | | break-inside: avoid; |
| | | } |
| | | `; |
| | | iframeDoc.head.appendChild(printStyle); |
| | | |
| | | // 调整iframe大小以适应内容 |
| | | const contentWidth = rectRenderer.value.$el.offsetWidth; |
| | | const contentHeight = rectRenderer.value.$el.offsetHeight; |
| | | iframe.width = contentWidth + 'px'; |
| | | iframe.height = contentHeight + 'px'; |
| | | |
| | | // 执行打印 |
| | | iframe.contentWindow.print(); |
| | | |
| | | // 清理 |
| | | setTimeout(() => { |
| | | document.body.removeChild(iframe); |
| | | }, 100); |
| | | }; |
| | | </script> |
| | |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item @click="changeRouter(1)" :class="indexFlag===1?'indexTag':''" :to="{ path: '/main/glassOptimize/optimizeProject' }">{{'工程信息'}}</el-breadcrumb-item> |
| | | <el-breadcrumb-item v-show="false" @click="changeRouter(2)" :class="indexFlag===2?'indexTag':''" :to="{ path: '/main/order/createOrder' }">{{$t('order.page.createOrder')}}</el-breadcrumb-item> |
| | | <el-breadcrumb-item @click="changeRouter(3)" :class="indexFlag===3?'indexTag':''" :to="{ path: '/main/glassOptimize/optimizePrint' }">打印 |
| | | <el-breadcrumb-item @click="changeRouter(3)" :class="indexFlag===3?'indexTag':''" :to="{ path: '/main/glassOptimize/OptimizationRectPrint' }">打印 |
| | | </el-breadcrumb-item> |
| | | <el-breadcrumb-item @click="changeRouter(4)" :class="indexFlag===4?'indexTag':''" :to="{ path: '/main/glassOptimize/optimizeMove' }">调整 |
| | | <el-breadcrumb-item @click="changeRouter(4)" :class="indexFlag===4?'indexTag':''" :to="{ path: '/main/glassOptimize/Optimization' }">调整 |
| | | </el-breadcrumb-item> |
| | | <el-breadcrumb-item @click="changeRouter(5)" :class="indexFlag===5?'indexTag':''" :to="{ path: '/main/glassOptimize/optimizeMove' }">数控 |
| | | <el-breadcrumb-item @click="changeRouter(5)" :class="indexFlag===5?'indexTag':''" :to="{ path: '/main/glassOptimize/OptimizeControl' }">数控 |
| | | </el-breadcrumb-item> |
| | | <el-breadcrumb-item @click="changeRouter(6)" :class="indexFlag===6?'indexTag':''" :to="{ path: '/main/glassOptimize/optimizeMove' }">设置 |
| | | <el-breadcrumb-item @click="changeRouter(6)" :class="indexFlag===6?'indexTag':''" :to="{ path: '/main/glassOptimize/optimizeparms' }">设置 |
| | | </el-breadcrumb-item> |
| | | <el-breadcrumb-item></el-breadcrumb-item> |
| | | </el-breadcrumb> |
New file |
| | |
| | | <template>
|
| | | <div >
|
| | | <RectRenderer |
| | | :layoutData="layoutData" |
| | | :gw="1400" |
| | | :gh="1100" |
| | | style="width: 1500px; height: 800px; position: relative;"
|
| | | />
|
| | | |
| | | |
| | | </div>
|
| | | <button @click="submitLayouts" style="position: fixed; bottom: 20px; right: 20px; padding: 10px; background: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer;">
|
| | | 保存OPT
|
| | | </button>
|
| | | </template>
|
| | | |
| | | <script setup>
|
| | | import { ref } from 'vue';
|
| | | import RectRenderer from './page/RectRenderer.vue';
|
| | | import mockLayoutData from '../../../components/pp/MockData';
|
| | | import request from "@/utils/request";
|
| | | import { useI18n } from "vue-i18n";
|
| | | import { ElMessage } from "element-plus";
|
| | |
|
| | | const { t } = useI18n();
|
| | | const layoutData = ref(mockLayoutData);
|
| | | |
| | | const submitLayouts = async () => {
|
| | | try {
|
| | | const response = await request.post('/glassOptimize/generateOpt', {
|
| | | Layouts: layoutData.value.Layouts |
| | | }, {
|
| | | headers: {
|
| | | 'Content-Type': 'application/json'
|
| | | },
|
| | | responseType: 'blob' // 以 blob 形式接收响应
|
| | | });
|
| | |
|
| | | // 处理下载
|
| | | const downloadUrl = window.URL.createObjectURL(response);
|
| | | const a = document.createElement('a');
|
| | | a.href = downloadUrl;
|
| | | a.download = 'output.opt';
|
| | | document.body.appendChild(a);
|
| | | a.click();
|
| | | document.body.removeChild(a);
|
| | | window.URL.revokeObjectURL(downloadUrl);
|
| | | ElMessage.success('OPT文件下载成功,请选择文件路径');
|
| | | } catch (error) {
|
| | | console.error('下载失败:', error);
|
| | | // 显示错误消息给用户
|
| | | ElMessage.error('下载失败,请稍后再试');
|
| | | }
|
| | | };
|
| | |
|
| | |
|
| | |
|
| | | </script>
|
| | | |
| | |
| | | <template>
|
| | | <div style="width:100%;height:2000px;">
|
| | | <div class="layoutJSON">
|
| | | Displayed as <code>[x, y, w, h]</code>:
|
| | | <div class="columns">
|
| | | <div v-for="item in layout" :key="item.i">
|
| | | <div >
|
| | | <RectRenderer |
| | | :layoutData="layoutData" |
| | | :gw="1400" |
| | | :gh="1100" |
| | | style="width: 1500px; height: 800px; position: relative;"
|
| | | />
|
| | |
|
| | | <b>{{item.i}}</b>: [{{item.x}}, {{item.y}}, {{item.w}}, {{item.h}}]
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | | <hr/>
|
| | | <input type="checkbox" v-model="draggable"/> Draggable
|
| | | <input type="checkbox" v-model="resizable"/> Resizable
|
| | | <input type="checkbox" v-model="responsive"/> Responsive
|
| | | <br/>
|
| | | <div style="width:100%;margin-top: 10px;height:100%;">
|
| | | <grid-layout v-model:layout="layout"
|
| | | :col-num="12"
|
| | | :row-height="30"
|
| | | :is-draggable="draggable"
|
| | | :is-resizable="resizable"
|
| | | :vertical-compact="true"
|
| | | :use-css-transforms="true"
|
| | | >
|
| | |
|
| | | <grid-item v-for="item in layout"
|
| | | :key="item.i" |
| | | :static="item.static"
|
| | | :x="item.x"
|
| | | :y="item.y"
|
| | | :w="item.w"
|
| | | :h="item.h"
|
| | | :i="item.i"
|
| | | >
|
| | | <span class="text">{{item.i}}</span>
|
| | | </grid-item>
|
| | | |
| | | </grid-layout>
|
| | | </div>
|
| | | </div>
|
| | | </template>
|
| | |
|
| | | <script>
|
| | | import { GridLayout, GridItem } from 'vue3-grid-layout';
|
| | | <script setup>
|
| | | import { ref } from 'vue';
|
| | | import RectRenderer from './page/RectRenderer.vue';
|
| | | import mockLayoutData from '../../../components/pp/MockData';
|
| | |
|
| | | export default {
|
| | | components: {
|
| | | GridLayout,
|
| | | GridItem,
|
| | | },
|
| | | data() {
|
| | | return {
|
| | | layout: [
|
| | | {"x":0,"y":0,"w":2,"h":2,"i":"0666*343"},
|
| | | {"x":2,"y":0,"w":2,"h":4,"i":"1"},
|
| | | {"x":4,"y":0,"w":2,"h":5,"i":"2"},
|
| | | {"x":6,"y":0,"w":2,"h":3,"i":"3"},
|
| | | {"x":8,"y":0,"w":2,"h":3,"i":"4"},
|
| | | {"x":10,"y":0,"w":2,"h":3,"i":"5"},
|
| | | {"x":0,"y":5,"w":2,"h":5,"i":"6"},
|
| | | {"x":2,"y":5,"w":2,"h":5,"i":"7"},
|
| | | {"x":4,"y":5,"w":2,"h":5,"i":"8"},
|
| | | {"x":6,"y":4,"w":2,"h":4,"i":"9"},
|
| | | {"x":8,"y":4,"w":2,"h":4,"i":"10"},
|
| | | {"x":10,"y":4,"w":2,"h":4,"i":"11"},
|
| | | {"x":0,"y":10,"w":2,"h":5,"i":"12"},
|
| | | {"x":2,"y":10,"w":2,"h":5,"i":"13"},
|
| | | {"x":4,"y":8,"w":2,"h":4,"i":"14"},
|
| | | {"x":6,"y":8,"w":2,"h":4,"i":"15"},
|
| | | {"x":8,"y":10,"w":2,"h":5,"i":"16"},
|
| | | {"x":10,"y":4,"w":2,"h":2,"i":"17"},
|
| | | {"x":0,"y":9,"w":2,"h":3,"i":"18"},
|
| | | {"x":2,"y":6,"w":2,"h":2,"i":"19"}
|
| | | ],
|
| | | draggable: true,
|
| | | resizable: true,
|
| | | responsive: true,
|
| | | index: 0
|
| | | }
|
| | | },
|
| | | methods: {
|
| | | }
|
| | | }
|
| | | const layoutData = ref(mockLayoutData);
|
| | | |
| | | |
| | | </script>
|
| | | |
| | | <style scoped>
|
| | | .vue-grid-layout {
|
| | | background: #eee;
|
| | | }
|
| | | |
| | | .vue-grid-item:not(.vue-grid-placeholder) {
|
| | | background: #ccc;
|
| | | border: 1px solid black;
|
| | | }
|
| | | |
| | | .vue-grid-item .resizing {
|
| | | opacity: 0.9;
|
| | | }
|
| | | |
| | | .vue-grid-item .static {
|
| | | background: #cce;
|
| | | }
|
| | | |
| | | .vue-grid-item .text {
|
| | | font-size: 24px;
|
| | | text-align: center;
|
| | | position: absolute;
|
| | | top: 0;
|
| | | bottom: 0;
|
| | | left: 0;
|
| | | right: 0;
|
| | | margin: auto;
|
| | | height: 100%;
|
| | | width: 100%;
|
| | | }
|
| | | |
| | | .vue-grid-item .no-drag {
|
| | | height: 100%;
|
| | | width: 100%;
|
| | | }
|
| | | |
| | | .vue-grid-item .minMax {
|
| | | font-size: 12px;
|
| | | }
|
| | | |
| | | .vue-grid-item .add {
|
| | | cursor: pointer;
|
| | | }
|
| | | |
| | | .vue-draggable-handle {
|
| | | position: absolute;
|
| | | width: 20px;
|
| | | height: 20px;
|
| | | top: 0;
|
| | | left: 0;
|
| | | background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><circle cx='5' cy='5' r='5' fill='#999999'/></svg>") no-repeat;
|
| | | background-position: bottom right;
|
| | | padding: 0 8px 8px 0;
|
| | | background-repeat: no-repeat;
|
| | | background-origin: content-box;
|
| | | box-sizing: border-box;
|
| | | cursor: pointer;
|
| | | }
|
| | | |
| | | .layoutJSON {
|
| | | background: #ddd;
|
| | | border: 1px solid black;
|
| | | margin-top: 10px;
|
| | | padding: 10px;
|
| | | }
|
| | | |
| | | .columns {
|
| | | -moz-columns: 120px;
|
| | | -webkit-columns: 120px;
|
| | | columns: 120px;
|
| | | }
|
| | | |
| | | </style> |
| | | |
New file |
| | |
| | | <script setup>
|
| | | import { ref, reactive, onMounted, watch } from 'vue';
|
| | | import { useI18n } from "vue-i18n";
|
| | | import { ElMessage } from "element-plus";
|
| | | import request from "@/utils/request";
|
| | | import useUserInfoStore from "@/stores/userInfo";
|
| | |
|
| | | const { t } = useI18n();
|
| | | const userStore = useUserInfoStore()
|
| | | const username = userStore.user.userName
|
| | |
|
| | | const currentComponent = ref('optimization');
|
| | |
|
| | | const settings = reactive({
|
| | | optimization: {},
|
| | | display: {},
|
| | | cutting: {},
|
| | | server: {},
|
| | | tempering: {}
|
| | | });
|
| | |
|
| | | const selectComponent = (component) => {
|
| | | currentComponent.value = component;
|
| | | };
|
| | |
|
| | | const saveToDatabase = () => {
|
| | | request.post(`/glassOptimize/optimizeParms`, settings).then((res) => {
|
| | | if (res.code == 200 && res.data === true) {
|
| | | ElMessage.success(t('basicData.msg.saveSuccess'))
|
| | | } else {
|
| | | ElMessage.warning(res.msg)
|
| | | }
|
| | | });
|
| | | };
|
| | |
|
| | | const fetchSettings = async (username) => {
|
| | | try {
|
| | | const response = await request.post(`/glassOptimize/selectOptimizeParms/${username}`);
|
| | | if (response.code == 200) {
|
| | | if (!response.data) {
|
| | | console.error('响应数据为空');
|
| | | return;
|
| | | }
|
| | | const parsedData = JSON.parse(response.data);
|
| | | Object.assign(settings, parsedData);
|
| | | console.log('设置已更新:', settings);
|
| | | } else {
|
| | | console.error('请求失败,状态码:', response.code);
|
| | | }
|
| | | } catch (error) {
|
| | | console.error('请求发生错误:', error);
|
| | | }
|
| | | };
|
| | |
|
| | | onMounted(() => {
|
| | | fetchSettings(username);
|
| | | });
|
| | |
|
| | | // 参数映射表,用于将英文参数名映射为中文名称和类型
|
| | | const paramMapping = {
|
| | | yShapeJoinOptimization: { name: '异形拼接优化', type: 'checkbox' },
|
| | | autoMiddleEmptyPairing: { name: '自动中空配对', type: 'checkbox' },
|
| | | smallPieceRotationProhibited: { name: '小片禁止旋转', type: 'checkbox' },
|
| | | maxFramesOnSite: { name: '现场最大可放架子数量', type: 'text' },
|
| | | bendEdgeDistance: { name: '掰边距(mm)', type: 'text' },
|
| | | positiveTolerance: { name: '正公差(mm)', type: 'text' },
|
| | | negativeTolerance: { name: '负公差(mm)', type: 'text' },
|
| | | cutterOriginPosition: { name: '切割机原点位置', type: 'select' },
|
| | | uniformShapeEdgeTrimAmount: { name: '统一设置异形修边量', type: 'text' },
|
| | | edgeTrimMode: { name: '修边模式', type: 'select' },
|
| | | parallelOptimizationChannels: { name: '并行优化的通道数量', type: 'text' },
|
| | | optimizationIterations: { name: '重复优化次数', type: 'text' },
|
| | | finishedProductGrindingAmount: { name: '成品默认磨量', type: 'text' },
|
| | | rawPieceEdgeTrimAmount: { name: '原片默认修边量', type: 'text' },
|
| | | finishedSinglePieceBelowGrindingAmount: { name: '成品单片小于多少时磨量为', type: 'text' }
|
| | | };
|
| | |
|
| | | // 动态生成参数列表
|
| | | const parameterList = ref(Object.keys(paramMapping).map(key => ({
|
| | | key,
|
| | | ...paramMapping[key]
|
| | | })));
|
| | | </script>
|
| | |
|
| | | <template>
|
| | | <div class="settings-container">
|
| | | <div class="sidebar">
|
| | | <div
|
| | | @click="selectComponent('optimization')"
|
| | | :class="{ active: currentComponent === 'optimization' }"
|
| | | class="sidebar-item"
|
| | | >
|
| | | <div class="sidebar-header">优化参数</div>
|
| | | <div class="sidebar-content">优化参数设置</div>
|
| | | </div>
|
| | |
|
| | | <div
|
| | | @click="selectComponent('display')"
|
| | | :class="{ active: currentComponent === 'display' }"
|
| | | class="sidebar-item"
|
| | | >
|
| | | <div class="sidebar-header">版图显示</div>
|
| | | <div class="sidebar-content">版图显示设置</div>
|
| | | </div>
|
| | |
|
| | | <div
|
| | | @click="selectComponent('cutting')"
|
| | | :class="{ active: currentComponent === 'cutting' }"
|
| | | class="sidebar-item"
|
| | | >
|
| | | <div class="sidebar-header">刀路</div>
|
| | | <div class="sidebar-content">刀路设置</div>
|
| | | </div>
|
| | |
|
| | | <div
|
| | | @click="selectComponent('server')"
|
| | | :class="{ active: currentComponent === 'server' }"
|
| | | class="sidebar-item"
|
| | | >
|
| | | <div class="sidebar-header">输出</div>
|
| | | <div class="sidebar-content">结果输出设置</div>
|
| | | </div>
|
| | |
|
| | | <div
|
| | | @click="selectComponent('tempering')"
|
| | | :class="{ active: currentComponent === 'tempering' }"
|
| | | class="sidebar-item"
|
| | | >
|
| | | <div class="sidebar-header">钢化</div>
|
| | | <div class="sidebar-content">钢化设置</div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <div class="main-content">
|
| | | <template v-if="currentComponent === 'display'">
|
| | | <div class="display-settings">
|
| | | <h2>版图显示设置</h2>
|
| | | <div class="form-group">
|
| | | <label>矩形成品显示颜色</label>
|
| | | <input type="color" v-model="settings.display.themeColor" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>成品尺寸包含磨边量</label>
|
| | | <input type="checkbox" v-model="settings.display.includeProductEdge" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>异形尺寸包含磨边量</label>
|
| | | <input type="checkbox" v-model="settings.display.includeIrregularEdge" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>按架号合并版图</label>
|
| | | <input type="checkbox" v-model="settings.display.mergeByFrameNumber" />
|
| | | </div>
|
| | | <div style="border: 1px solid #d2d0d0; margin-top: 20px;">
|
| | | <div style="background-color: #D5EAFF;">小片信息</div>
|
| | | <div class="form-group">
|
| | | <label>架号</label>
|
| | | <input type="checkbox" v-model="settings.display.frameNumber" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>订单编号</label>
|
| | | <input type="checkbox" v-model="settings.display.orderNumber" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>产品名称</label>
|
| | | <input type="checkbox" v-model="settings.display.productName" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>加工信息</label>
|
| | | <input type="checkbox" v-model="settings.display.processingInfo" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>备注</label>
|
| | | <input type="checkbox" v-model="settings.display.remarks" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>楼层编号</label>
|
| | | <input type="checkbox" v-model="settings.display.floorNumber" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>边长</label>
|
| | | <input type="checkbox" v-model="settings.display.edgeLength" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>工艺</label>
|
| | | <input type="checkbox" v-model="settings.display.manufacturingProcess" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>ID</label>
|
| | | <input type="checkbox" v-model="settings.display.identifier" />
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | | </template>
|
| | |
|
| | | <template v-else-if="currentComponent === 'cutting'">
|
| | | <div class="display-settings">
|
| | | <h2>刀路设置</h2>
|
| | | <div class="form-group">
|
| | | <label>正向切割</label>
|
| | | <input type="checkbox" v-model="settings.cutting.cutting_direction" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>显示切割方向</label>
|
| | | <input type="checkbox" v-model="settings.cutting.show_cutting_path" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>强制弧线和直线连续切割</label>
|
| | | <input type="checkbox" v-model="settings.cutting.force_continuous_cutting" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>孔洞最小切割半径</label>
|
| | | <input type="number" v-model="settings.cutting.min_radius" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>两条平行线最小间隔</label>
|
| | | <input type="number" v-model="settings.cutting.min_parallel_offset" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>T型退缩</label>
|
| | | <input type="number" v-model="settings.cutting.t_shaped_recess" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>下刀间距</label>
|
| | | <input type="number" v-model="settings.cutting.down_cut_spacing" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>抬刀退缩</label>
|
| | | <input type="number" v-model="settings.cutting.lift_retract" />
|
| | | </div>
|
| | | </div>
|
| | | </template>
|
| | |
|
| | | <template v-else-if="currentComponent === 'server'">
|
| | | <div class="display-settings">
|
| | | <h2>结果输出设置</h2>
|
| | | <div class="form-group">
|
| | | <label>工程文件保存路径</label>
|
| | | <input type="text" v-model="settings.server.output_format" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>切割代码保存路径</label>
|
| | | <input type="text" v-model="settings.server.cutting_code_save_path" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>保存文件后打开所在文件夹</label>
|
| | | <input type="text" v-model="settings.server.open_folder_after_save" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>G代码文件格式</label>
|
| | | <input type="text" v-model="settings.server.g_code_file_format" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>TRF文件保存路径</label>
|
| | | <input type="text" v-model="settings.server.trf_file_save_path" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>保特罗文件保存路径</label>
|
| | | <input type="text" v-model="settings.server.btl_file_save_path" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>OPTIMA文件保存路径</label>
|
| | | <input type="text" v-model="settings.server.optima_file_save_path" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>优化深度限制启用</label>
|
| | | <input type="text" v-model="settings.server.optimization_depth_limit_enable" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>原片切材率计算</label>
|
| | | <input type="text" v-model="settings.server.original_sheet_material_calculation" />
|
| | | </div>
|
| | | </div>
|
| | | </template>
|
| | |
|
| | | <template v-else-if="currentComponent === 'tempering'">
|
| | | <div class="display-settings">
|
| | | <h2>钢化设置</h2>
|
| | | <div class="form-group">
|
| | | <label>炉长(mm)</label>
|
| | | <input type="number" v-model="settings.tempering.furnaceLength" step="1" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>炉宽(mm)</label>
|
| | | <input type="number" v-model="settings.tempering.furnaceWidth" step="1" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>最大装载率(%)</label>
|
| | | <input type="number" v-model="settings.tempering.maxLoadingRate" step="1" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>混乱程度(%)</label>
|
| | | <input type="number" v-model="settings.tempering.chaosLevel" step="1" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>钢化加热时间(秒)</label>
|
| | | <input type="number" v-model="settings.tempering.temperingTime" step="1" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>默认钢化推荐模式</label>
|
| | | <select v-model="settings.tempering.defaultTemperingMode">
|
| | | <option value="auto">自动推荐</option>
|
| | | <option value="manual">手动选择</option>
|
| | | </select>
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>最大面积设置(㎡)</label>
|
| | | <input type="number" v-model="settings.tempering.maxArea" step="0.1" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>最大片数设置(片)</label>
|
| | | <input type="number" v-model="settings.tempering.maxPieceCount" step="1" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>X轴默认间隔(mm)</label>
|
| | | <input type="number" v-model="settings.tempering.xAxisInterval" step="1" />
|
| | | </div>
|
| | | <div class="form-group">
|
| | | <label>Y轴默认间隔(mm)</label>
|
| | | <input type="number" v-model="settings.tempering.yAxisInterval" step="1" />
|
| | | </div>
|
| | | </div>
|
| | | </template>
|
| | |
|
| | | <template v-else>
|
| | | <div class="display-settings">
|
| | | <h2>优化参数设置</h2>
|
| | | <div class="parameter-list">
|
| | | <div |
| | | class="form-group" |
| | | v-for="(param, index) in parameterList" |
| | | :key="index"
|
| | | >
|
| | | <label class="parameter-name">{{ param.name }}</label>
|
| | | <div class="parameter-control">
|
| | | <input |
| | | v-if="param.type === 'checkbox'" |
| | | type="checkbox" |
| | | :checked="settings.optimization[param.key] === '1'"
|
| | | @click="() => { settings.optimization[param.key] = settings.optimization[param.key] === '1' ? '0' : '1' }"
|
| | | >
|
| | | <select |
| | | v-else-if="param.type === 'select'" |
| | | :name="param.key" |
| | | class="cs"
|
| | | >
|
| | | <option |
| | | v-for="option in getOptions(param.key)" |
| | | :key="option.value" |
| | | :selected="option.value === settings.optimization[param.key]"
|
| | | >
|
| | | {{ option.label }}
|
| | | </option>
|
| | | </select>
|
| | | <input |
| | | v-else |
| | | :type="param.type || 'text'" |
| | | :name="param.key" |
| | | class="cs" |
| | | v-model="settings.optimization[param.key]"
|
| | | >
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | | </template>
|
| | | </div>
|
| | |
|
| | | <button class="button" @click="saveToDatabase">保存</button>
|
| | | </div>
|
| | | </template>
|
| | |
|
| | | <style>
|
| | | .settings-container {
|
| | | display: flex;
|
| | | gap: 20px;
|
| | | padding: 20px;
|
| | | background-color: #f0f2f5;
|
| | | }
|
| | |
|
| | | .sidebar {
|
| | | width: 300px;
|
| | | background-color: white;
|
| | | padding: 15px;
|
| | | border-radius: 8px;
|
| | | box-shadow: 0 2px 4 rgba(0, 0, 0, 0.1);
|
| | | }
|
| | |
|
| | | .sidebar-item {
|
| | | cursor: pointer;
|
| | | padding: 10px;
|
| | | margin-bottom: 5px;
|
| | | border-radius: 6px;
|
| | | transition: all 0.3s ease;
|
| | | }
|
| | |
|
| | | .sidebar-item.active {
|
| | | background-color: #f8f9fa;
|
| | | transform: translateX(5px);
|
| | | }
|
| | |
|
| | | .sidebar-header {
|
| | | font-size: 12px;
|
| | | color: #666;
|
| | | margin-bottom: 5px;
|
| | | }
|
| | |
|
| | | .sidebar-content {
|
| | | font-size: 14px;
|
| | | color:#333;
|
| | | }
|
| | |
|
| | | .main-content {
|
| | | flex-grow: 1;
|
| | | padding: 20px;
|
| | | }
|
| | |
|
| | | button {
|
| | | padding: 10px 20px;
|
| | | background-color: #5cadfe;
|
| | | color: white;
|
| | | border: none;
|
| | | border-radius: 4px;
|
| | | cursor: pointer;
|
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
| | | }
|
| | |
|
| | | @media (max-width: 768px) {
|
| | | .settings-container {
|
| | | flex-direction: column;
|
| | | }
|
| | |
|
| | | .sidebar {
|
| | | order: -1;
|
| | | }
|
| | |
|
| | | .main-content {
|
| | | margin-top: 20px;
|
| | | }
|
| | | }
|
| | |
|
| | | .form-group {
|
| | | margin-bottom: 15px;
|
| | | display: flex;
|
| | | align-items: center;
|
| | | gap: 10px;
|
| | | }
|
| | |
|
| | | .form-group label {
|
| | | font-weight: normal;
|
| | | min-width: 120px;
|
| | | }
|
| | |
|
| | | .form-group input,
|
| | | .form-group select {
|
| | | flex: 1;
|
| | | padding: 5px;
|
| | | border: 1px solid #ddd;
|
| | | border-radius: 4px;
|
| | | }
|
| | |
|
| | | .form-group select {
|
| | | cursor: pointer;
|
| | | }
|
| | |
|
| | | .display-settings {
|
| | | background-color: white;
|
| | | padding: 20px;
|
| | | border-radius: 8px;
|
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
| | | }
|
| | |
|
| | | .parameter-list {
|
| | | display: flex;
|
| | | flex-direction: column;
|
| | | gap: 0px;
|
| | | }
|
| | |
|
| | | .parameter-item {
|
| | | display: flex;
|
| | | align-items: center;
|
| | | gap: 0px;
|
| | | }
|
| | |
|
| | | .parameter-name {
|
| | | font-weight: normal;
|
| | | min-width: 120px;
|
| | | }
|
| | |
|
| | | .parameter-control {
|
| | | flex: 1;
|
| | | }
|
| | |
|
| | | .button {
|
| | | text-align: center;
|
| | | width: 70px;
|
| | | height: 28px;
|
| | | border: none;
|
| | | background-color: #5CADFE;
|
| | | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0), 0 6px 5px 0 rgba(0, 0, 0, 0.19);
|
| | | margin-left: 500px;
|
| | | }
|
| | | </style>
|
| | |
|
| | | <script>
|
| | | // 辅助函数,根据参数键获取选项
|
| | | function getOptions(key) {
|
| | | const optionsMapping = {
|
| | | cutterOriginPosition: [
|
| | | { value: 'topLeft', label: '左上角' },
|
| | | { value: 'bottomLeft', label: '左下角' },
|
| | | { value: 'topRight', label: '右上角' },
|
| | | { value: 'bottomRight', label: '右下角' }
|
| | | ],
|
| | | edgeTrimMode: [
|
| | | { value: 'intelligent', label: '智能修边' },
|
| | | { value: 'complete', label: '完全修边' }
|
| | | ]
|
| | | };
|
| | | return optionsMapping[key] || [];
|
| | | }
|
| | | </script>
|
New file |
| | |
| | | <template>
|
| | | <div style="display: flex; height: 100vh;">
|
| | | <!-- Sidebar -->
|
| | | <div class="sidebar" style="width: 200px; background: #f4f4f4; padding: 10px;">
|
| | | <div
|
| | | v-for="(layout, layoutIndex) in layouts"
|
| | | :key="layoutIndex"
|
| | | class="sidebar-item"
|
| | | @click="selectLayout(layoutIndex)"
|
| | | :class="{ 'selected': selectedLayoutIndex === layoutIndex }"
|
| | | >
|
| | | {{ layout.width }} × {{ layout.height }} × {{ layout.SameCount }}
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <!-- Main Layout Panel -->
|
| | | <div ref="layoutPanel" :class="panelClass" :style="panelStyle">
|
| | | <div
|
| | | v-for="(layout, layoutIndex) in layouts"
|
| | | :key="layoutIndex"
|
| | | class="layout-wrapper"
|
| | | :style="{ display: selectedLayoutIndex === layoutIndex ? 'block' : 'none', top: '-150px' }"
|
| | | >
|
| | | <!-- Layout Info Label -->
|
| | | <div class="layout-info" :style="layoutInfoStyle(layoutIndex)">
|
| | | {{ getCurrentRectInfo(layoutIndex) }}
|
| | | </div>
|
| | |
|
| | | <!-- Layout Container -->
|
| | | <div class="layout-container" :style="layoutContainerStyle(layoutIndex)">
|
| | | <!-- 灰色矩形 -->
|
| | | <div
|
| | | v-for="(rect, rectIndex) in layout.rects.filter(r => r.isRemain)"
|
| | | :key="`gray-${rectIndex}`"
|
| | | :ref="(el) => { if (el) rectsElements[layoutIndex + '-' + rectIndex] = el }"
|
| | | class="layout-rect"
|
| | | :style="rectStyle(rect, layoutIndex)"
|
| | | @contextmenu.prevent="handleGrayRectRightClick(layoutIndex, rectIndex)"
|
| | | />
|
| | |
|
| | | <!-- 蓝色矩形 -->
|
| | | <div
|
| | | v-for="(rect, rectIndex) in layout.rects.filter(r => !r.isRemain)"
|
| | | :key="`blue-${rectIndex}`"
|
| | | :ref="(el) => { if (el) rectsElements[layoutIndex + '-' + rectIndex] = el }"
|
| | | class="layout-rect"
|
| | | :style="rectStyle(rect, layoutIndex)"
|
| | | @contextmenu.prevent="handleRectRightClick(layoutIndex, rectIndex)"
|
| | | @mousedown="handleRectDragStart(layoutIndex, rectIndex)"
|
| | | @mousemove="handleRectDragging"
|
| | | @mouseup="handleRectDragEnd"
|
| | | @mouseleave="handleRectDragEnd"
|
| | | >
|
| | | <div class="rect-content">
|
| | | <div class="size">{{ rect.w }}×{{ rect.h }}</div>
|
| | | <div class="jia-hao">{{ rect.JiaHao }}</div>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <!-- 提交按钮 -->
|
| | | <button @click="submitLayouts" style="position: fixed; bottom: 20px; right: 20px; padding: 10px; background: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer;">
|
| | | 保存调整
|
| | | </button>
|
| | | </div>
|
| | | </template>
|
| | |
|
| | | <script setup>
|
| | | import { ref, reactive, onMounted, onUnmounted } from 'vue';
|
| | | import request from "@/utils/request";
|
| | | import { useI18n } from "vue-i18n";
|
| | | import { ElMessage, ElMessageBox } from "element-plus";
|
| | | const { t } = useI18n();
|
| | | const props = defineProps({
|
| | | layoutData: { type: Object, required: true },
|
| | | gw: { type: Number, default: 1000 },
|
| | | gh: { type: Number, default: 1000 },
|
| | | style: { type: String, default: 'width:1000px;height:600px;display:block;background:gray' }
|
| | | });
|
| | |
|
| | | const emit = defineEmits(['rectClicked']);
|
| | | const layoutPanel = ref(null);
|
| | | const rectsElements = ref({});
|
| | | const focusIndex = ref(null);
|
| | | const layouts = ref([]);
|
| | | const panelClass = ref('');
|
| | | const panelStyle = ref(props.style);
|
| | | const rectClass = ref('layout-rect');
|
| | | const selectedLayoutIndex = ref(0);
|
| | | const currentRect = ref(null);
|
| | | const dragging = ref(false);
|
| | | const dragStartPos = ref({ x: 0, y: 0 });
|
| | | const dragRect = ref(null);
|
| | |
|
| | | // 提交布局数据到后端
|
| | | const submitLayouts = async () => {
|
| | | layouts.value.forEach(layout => {
|
| | | layout.rects.forEach(rect => {
|
| | | rect.x = Math.round(rect.x);
|
| | | rect.y = Math.round(rect.y);
|
| | | rect.w = Math.round(rect.w);
|
| | | rect.h = Math.round(rect.h);
|
| | | });
|
| | | });
|
| | | const savedProjectNo = localStorage.getItem('projectNo');
|
| | | const processId = savedProjectNo;
|
| | | const Layouts = layouts.value;
|
| | | request.post(`/glassOptimize/updateOptimizeResult/${processId}`, JSON.stringify({ Layouts }), {
|
| | | headers: {
|
| | | 'Content-Type': 'application/json'
|
| | | }
|
| | | }).then((res) => {
|
| | | if (res.code == 200 && res.data === true) {
|
| | | ElMessage.success(t('basicData.msg.saveSuccess'));
|
| | | } else {
|
| | | ElMessage.warning(res.msg);
|
| | | }
|
| | | });
|
| | | };
|
| | |
|
| | | const showAddDialog = (layoutIndex, rectIndex) => {
|
| | | ElMessageBox.prompt('请输入成品的宽度和高度', '添加成品', {
|
| | | inputType: 'text',
|
| | | inputValidator: (value) => {
|
| | | const values = value.split(',').map(v => v.trim());
|
| | | if (values.length !== 2) {
|
| | | return '请输入两个数字,用逗号分隔';
|
| | | }
|
| | | const [width, height] = values;
|
| | | if (isNaN(width) || isNaN(height)) {
|
| | | return '请输入有效的数字';
|
| | | }
|
| | | if (width <= 0 || height <= 0) {
|
| | | return '宽度和高度必须大于0';
|
| | | }
|
| | | return true;
|
| | | },
|
| | | inputErrorMessage: '输入格式不正确'
|
| | | })
|
| | | .then(({ value }) => {
|
| | | const values = value.split(',').map(v => parseFloat(v.trim()));
|
| | | const newRect = {
|
| | | x: 0,
|
| | | y: 0,
|
| | | w: values[0],
|
| | | h: values[1],
|
| | | isRemain: false,
|
| | | JiaHao: `新成品`
|
| | | };
|
| | | addNewRect(layoutIndex, newRect);
|
| | | })
|
| | | .catch(() => {
|
| | | // 用户取消
|
| | | });
|
| | | };
|
| | |
|
| | | const addNewRect = (layoutIndex, newRect) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | layout.rects.push(newRect);
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | };
|
| | |
|
| | | const layoutContainerStyle = (layoutIndex) => {
|
| | | const containerWidth = (props.gw - 210) / 2;
|
| | | const containerHeight = (props.gh - 100) / 3;
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const scale = Math.min(
|
| | | (props.gw - 100) / layout.width,
|
| | | (props.gh - 100) / layout.height
|
| | | );
|
| | | return {
|
| | | position: 'absolute',
|
| | | left: `${(props.gw - layout.width * scale) / 2}px`,
|
| | | top: `${(props.gh - layout.height * scale) / 2}px`,
|
| | | width: `${layout.width * scale}px`,
|
| | | height: `${layout.height * scale}px`,
|
| | | overflow: 'visible',
|
| | | border: '1px solid #ccc',
|
| | | background: '#fff'
|
| | | };
|
| | | };
|
| | |
|
| | | const layoutInfoStyle = (layoutIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const scale = Math.min(
|
| | | (props.gw - 100) / layout.width,
|
| | | (props.gh - 100) / layout.height
|
| | | );
|
| | | return {
|
| | | position: 'absolute',
|
| | | left: `${(props.gw - layout.width * scale) / 2}px`,
|
| | | top: `${(props.gh - layout.height * scale) / 2 - 45}px`,
|
| | | background: 'none',
|
| | | textAlign: 'center',
|
| | | zIndex: 1000
|
| | | };
|
| | | };
|
| | |
|
| | | const rectStyle = (rect, layoutIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const scale = Math.min(
|
| | | (props.gw - 100) / layout.width,
|
| | | (props.gh - 100) / layout.height
|
| | | );
|
| | | return {
|
| | | position: 'absolute',
|
| | | left: `${rect.x * scale}px`,
|
| | | top: `${rect.y * scale}px`,
|
| | | width: `${rect.w * scale}px`,
|
| | | height: `${rect.h * scale}px`,
|
| | | backgroundColor: rect.isRemain ? '#f0f0f0' : '#a0d8ef',
|
| | | border: '1px solid #000',
|
| | | cursor: 'pointer',
|
| | | draggable: !rect.isRemain,
|
| | | zIndex: rect.isRemain ? 1 : 2
|
| | | };
|
| | | };
|
| | |
|
| | | const handleRectClick = (layoutIndex, rectIndex) => {
|
| | | focusIndex.value = { layoutIndex, rectIndex };
|
| | | emit('rectClicked', layoutIndex, rectIndex);
|
| | | };
|
| | |
|
| | | const handleRectRightClick = (layoutIndex, rectIndex) => {
|
| | | const rect = layouts.value[layoutIndex].rects[rectIndex];
|
| | | if (rect.isRemain) return;
|
| | |
|
| | | const contextMenu = document.createElement('div');
|
| | | contextMenu.className = 'context-menu';
|
| | | contextMenu.style.position = 'absolute';
|
| | | contextMenu.style.left = `${event.clientX}px`;
|
| | | contextMenu.style.top = `${event.clientY}px`;
|
| | | contextMenu.style.backgroundColor = '#fff';
|
| | | contextMenu.style.border = '1px solid #ccc';
|
| | | contextMenu.style.padding = '5px';
|
| | | contextMenu.style.zIndex = 1001;
|
| | |
|
| | | const rotateItem = document.createElement('div');
|
| | | rotateItem.textContent = '旋转';
|
| | | rotateItem.style.cursor = 'pointer';
|
| | | rotateItem.addEventListener('click', () => {
|
| | | rotateRect(layoutIndex, rectIndex);
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const moveUpAndRotateItem = document.createElement('div');
|
| | | moveUpAndRotateItem.textContent = '向上移动并旋转';
|
| | | moveUpAndRotateItem.style.cursor = 'pointer';
|
| | | moveUpAndRotateItem.addEventListener('click', () => {
|
| | | moveRectAndRotate(layoutIndex, rectIndex, 'up');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const moveDownAndRotateItem = document.createElement('div');
|
| | | moveDownAndRotateItem.textContent = '向下移动并旋转';
|
| | | moveDownAndRotateItem.style.cursor = 'pointer';
|
| | | moveDownAndRotateItem.addEventListener('click', () => {
|
| | | moveRectAndRotate(layoutIndex, rectIndex, 'down');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const moveLeftAndRotateItem = document.createElement('div');
|
| | | moveLeftAndRotateItem.textContent = '向左移动并旋转';
|
| | | moveLeftAndRotateItem.style.cursor = 'pointer';
|
| | | moveLeftAndRotateItem.addEventListener('click', () => {
|
| | | moveRectAndRotate(layoutIndex, rectIndex, 'left');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const moveRightAndRotateItem = document.createElement('div');
|
| | | moveRightAndRotateItem.textContent = '向右移动并旋转';
|
| | | moveRightAndRotateItem.style.cursor = 'pointer';
|
| | | moveRightAndRotateItem.addEventListener('click', () => {
|
| | | moveRectAndRotate(layoutIndex, rectIndex, 'right');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const moveUpItem = document.createElement('div');
|
| | | moveUpItem.textContent = '向上移动';
|
| | | moveUpItem.style.cursor = 'pointer';
|
| | | moveUpItem.addEventListener('click', () => {
|
| | | moveRect(layoutIndex, rectIndex, 'up');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const moveDownItem = document.createElement('div');
|
| | | moveDownItem.textContent = '向下移动';
|
| | | moveDownItem.style.cursor = 'pointer';
|
| | | moveDownItem.addEventListener('click', () => {
|
| | | moveRect(layoutIndex, rectIndex, 'down');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const moveLeftItem = document.createElement('div');
|
| | | moveLeftItem.textContent = '向左移动';
|
| | | moveLeftItem.style.cursor = 'pointer';
|
| | | moveLeftItem.addEventListener('click', () => {
|
| | | moveRect(layoutIndex, rectIndex, 'left');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const moveRightItem = document.createElement('div');
|
| | | moveRightItem.textContent = '向右移动';
|
| | | moveRightItem.style.cursor = 'pointer';
|
| | | moveRightItem.addEventListener('click', () => {
|
| | | moveRect(layoutIndex, rectIndex, 'right');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const deleteItem = document.createElement('div');
|
| | | deleteItem.textContent = '删除';
|
| | | deleteItem.style.cursor = 'pointer';
|
| | | deleteItem.addEventListener('click', () => {
|
| | | deleteRect(layoutIndex, rectIndex);
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const addItem = document.createElement('div');
|
| | | addItem.textContent = '添加成品';
|
| | | addItem.style.cursor = 'pointer';
|
| | | addItem.addEventListener('click', () => {
|
| | | showAddDialog(layoutIndex, rectIndex);
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | contextMenu.appendChild(rotateItem);
|
| | | contextMenu.appendChild(moveUpAndRotateItem);
|
| | | contextMenu.appendChild(moveDownAndRotateItem);
|
| | | contextMenu.appendChild(moveLeftAndRotateItem);
|
| | | contextMenu.appendChild(moveRightAndRotateItem);
|
| | | contextMenu.appendChild(moveUpItem);
|
| | | contextMenu.appendChild(moveDownItem);
|
| | | contextMenu.appendChild(moveLeftItem);
|
| | | contextMenu.appendChild(moveRightItem);
|
| | | contextMenu.appendChild(deleteItem);
|
| | | contextMenu.appendChild(addItem);
|
| | |
|
| | | document.body.appendChild(contextMenu);
|
| | | };
|
| | |
|
| | | const handleGrayRectRightClick = (layoutIndex, rectIndex) => {
|
| | | const rect = layouts.value[layoutIndex].rects[rectIndex];
|
| | | if (!rect.isRemain) return;
|
| | |
|
| | | const contextMenu = document.createElement('div');
|
| | | contextMenu.className = 'context-menu';
|
| | | contextMenu.style.position = 'absolute';
|
| | | contextMenu.style.left = `${event.clientX}px`;
|
| | | contextMenu.style.top = `${event.clientY}px`;
|
| | | contextMenu.style.backgroundColor = '#fff';
|
| | | contextMenu.style.border = '1px solid #ccc';
|
| | | contextMenu.style.padding = '5px';
|
| | | contextMenu.style.zIndex = 1001;
|
| | |
|
| | | const mergeLeftItem = document.createElement('div');
|
| | | mergeLeftItem.textContent = '向左合并';
|
| | | mergeLeftItem.style.cursor = 'pointer';
|
| | | mergeLeftItem.addEventListener('click', () => {
|
| | | mergeGrayRects(layoutIndex, rectIndex, 'left');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const mergeRightItem = document.createElement('div');
|
| | | mergeRightItem.textContent = '向右合并';
|
| | | mergeRightItem.style.cursor = 'pointer';
|
| | | mergeRightItem.addEventListener('click', () => {
|
| | | mergeGrayRects(layoutIndex, rectIndex, 'right');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const mergeUpItem = document.createElement('div');
|
| | | mergeUpItem.textContent = '向上合并';
|
| | | mergeUpItem.style.cursor = 'pointer';
|
| | | mergeUpItem.addEventListener('click', () => {
|
| | | mergeGrayRects(layoutIndex, rectIndex, 'up');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const mergeDownItem = document.createElement('div');
|
| | | mergeDownItem.textContent = '向下合并';
|
| | | mergeDownItem.style.cursor = 'pointer';
|
| | | mergeDownItem.addEventListener('click', () => {
|
| | | mergeGrayRects(layoutIndex, rectIndex, 'down');
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | const addItem = document.createElement('div');
|
| | | addItem.textContent = '添加成品';
|
| | | addItem.style.cursor = 'pointer';
|
| | | addItem.addEventListener('click', () => {
|
| | | showAddDialog(layoutIndex, rectIndex);
|
| | | document.body.removeChild(contextMenu);
|
| | | });
|
| | |
|
| | | contextMenu.appendChild(mergeLeftItem);
|
| | | contextMenu.appendChild(mergeRightItem);
|
| | | contextMenu.appendChild(mergeUpItem);
|
| | | contextMenu.appendChild(mergeDownItem);
|
| | | contextMenu.appendChild(addItem);
|
| | |
|
| | | document.body.appendChild(contextMenu);
|
| | | };
|
| | |
|
| | | const handleRectDragStart = (layoutIndex, rectIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[rectIndex];
|
| | | if (rect.isRemain) return;
|
| | |
|
| | | dragging.value = true;
|
| | | dragRect.value = { layoutIndex, rectIndex };
|
| | | dragStartPos.value = {
|
| | | x: event.clientX,
|
| | | y: event.clientY
|
| | | };
|
| | | };
|
| | |
|
| | | const handleRectDragging = (event) => {
|
| | | if (!dragging.value || !dragRect.value) return;
|
| | |
|
| | | const layoutIndex = dragRect.value.layoutIndex;
|
| | | const rectIndex = dragRect.value.rectIndex;
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[rectIndex];
|
| | | const scale = Math.min(
|
| | | (props.gw - 100) / layout.width,
|
| | | (props.gh - 100) / layout.height
|
| | | );
|
| | |
|
| | | const deltaX = event.clientX - dragStartPos.value.x;
|
| | | const deltaY = event.clientY - dragStartPos.value.y;
|
| | |
|
| | | // 只调整位置,不调整大小
|
| | | const newRect = { ...rect };
|
| | | newRect.x += deltaX / scale;
|
| | | newRect.y += deltaY / scale;
|
| | |
|
| | | // 检查是否与其他蓝色矩形重叠
|
| | | const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
|
| | | let isValidMove = true;
|
| | | |
| | | otherRects.forEach(otherRect => {
|
| | | if (checkOverlap(newRect, otherRect)) {
|
| | | isValidMove = false;
|
| | | }
|
| | | });
|
| | |
|
| | | // 检查是否超出布局边界
|
| | | if (newRect.x < 0 || newRect.y < 0 ||
|
| | | newRect.x + newRect.w > layout.width ||
|
| | | newRect.y + newRect.h > layout.height) {
|
| | | isValidMove = false;
|
| | | }
|
| | |
|
| | | if (isValidMove) {
|
| | | rect.x = newRect.x;
|
| | | rect.y = newRect.y;
|
| | | dragStartPos.value = {
|
| | | x: event.clientX,
|
| | | y: event.clientY
|
| | | };
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | }
|
| | | };
|
| | |
|
| | | const handleRectDragEnd = () => {
|
| | | if (dragRect.value) {
|
| | | const layoutIndex = dragRect.value.layoutIndex;
|
| | | const rectIndex = dragRect.value.rectIndex;
|
| | | const rect = layouts.value[layoutIndex].rects[rectIndex];
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const scale = Math.min(
|
| | | (props.gw - 100) / layout.width,
|
| | | (props.gh - 100) / layout.height
|
| | | );
|
| | |
|
| | | // 拖动结束后自动对齐到最近的整数位置
|
| | | rect.x = Math.round(rect.x);
|
| | | rect.y = Math.round(rect.y);
|
| | |
|
| | | // 只调整位置对齐,不调整大小
|
| | | //adjustAlignmentPosition(layoutIndex, rectIndex);
|
| | |
|
| | | // 调整灰色矩形
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | }
|
| | |
|
| | | dragging.value = false;
|
| | | dragRect.value = null;
|
| | | };
|
| | |
|
| | | const adjustAlignmentPosition = (layoutIndex, rectIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[rectIndex];
|
| | | const otherRects = layout.rects.filter((r, i) => i !== rectIndex);
|
| | |
|
| | | const threshold = Math.max(rect.w, rect.h) * 0.1;
|
| | |
|
| | | otherRects.forEach(otherRect => {
|
| | | if (Math.abs(rect.x - otherRect.x) < threshold) {
|
| | | rect.x = Math.round((rect.x + otherRect.x) / 2);
|
| | | }
|
| | | if (Math.abs((rect.x + rect.w) - (otherRect.x + otherRect.w)) < threshold) {
|
| | | // 不调整宽度
|
| | | }
|
| | | if (Math.abs(rect.y - otherRect.y) < threshold) {
|
| | | rect.y = Math.round((rect.y + otherRect.y) / 2);
|
| | | }
|
| | | if (Math.abs((rect.y + rect.h) - (otherRect.y + otherRect.h)) < threshold) {
|
| | | // 不调整高度
|
| | | }
|
| | | });
|
| | | };
|
| | |
|
| | | const mergeGrayRects = (layoutIndex, rectIndex, direction) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[rectIndex];
|
| | | const grayRects = layout.rects.filter(r => r.isRemain);
|
| | |
|
| | | let targetRect = null;
|
| | |
|
| | | switch (direction) {
|
| | | case 'left':
|
| | | targetRect = grayRects.find(r => r.x + r.w === rect.x && r.y === rect.y && r.h === rect.h);
|
| | | break;
|
| | | case 'right':
|
| | | targetRect = grayRects.find(r => r.x === rect.x + rect.w && r.y === rect.y && r.h === rect.h);
|
| | | break;
|
| | | case 'up':
|
| | | targetRect = grayRects.find(r => r.y + r.h === rect.y && r.x === rect.x && r.w === rect.w);
|
| | | break;
|
| | | case 'down':
|
| | | targetRect = grayRects.find(r => r.y === rect.y + rect.h && r.x === rect.x && r.w === rect.w);
|
| | | break;
|
| | | }
|
| | |
|
| | | if (targetRect) {
|
| | | const mergedRect = {
|
| | | x: Math.min(rect.x, targetRect.x),
|
| | | y: Math.min(rect.y, targetRect.y),
|
| | | w: Math.max(rect.x + rect.w, targetRect.x + targetRect.w) - Math.min(rect.x, targetRect.x),
|
| | | h: Math.max(rect.y + rect.h, targetRect.y + targetRect.h) - Math.min(rect.y, targetRect.y),
|
| | | isRemain: true
|
| | | };
|
| | |
|
| | | const index = layout.rects.indexOf(rect);
|
| | | layout.rects.splice(index, 1);
|
| | | const targetIndex = layout.rects.indexOf(targetRect);
|
| | | layout.rects.splice(targetIndex, 1);
|
| | | layout.rects.push(mergedRect);
|
| | |
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | } else {
|
| | | ElMessage.warning('无法合并,没有相邻的灰色矩形');
|
| | | }
|
| | | };
|
| | |
|
| | | const mergeAdjacentGrayRects = (rects) => {
|
| | | const grayRects = rects.filter(r => r.isRemain);
|
| | | let merged = [];
|
| | | |
| | | grayRects.sort((a, b) => {
|
| | | if (a.x !== b.x) return a.x - b.x;
|
| | | return a.y - b.y;
|
| | | });
|
| | |
|
| | | if (grayRects.length === 0) return;
|
| | |
|
| | | merged.push({ ...grayRects[0] });
|
| | |
|
| | | for (let i = 1; i < grayRects.length; i++) {
|
| | | const last = merged[merged.length - 1];
|
| | | const current = grayRects[i];
|
| | |
|
| | | if (current.x === last.x + last.w && |
| | | current.y === last.y && |
| | | current.h === last.h) {
|
| | | last.w += current.w;
|
| | | last.x = Math.round(last.x);
|
| | | last.y = Math.round(last.y);
|
| | | last.w = Math.round(last.w);
|
| | | last.h = Math.round(last.h);
|
| | | } else if (current.y === last.y + last.h && |
| | | current.x === last.x && |
| | | current.w === last.w) {
|
| | | last.h += current.h;
|
| | | last.x = Math.round(last);
|
| | | last.y = Math.round(last.y);
|
| | | last.w = Math.round(last.w);
|
| | | last.h = Math.round(last.h);
|
| | | } else {
|
| | | merged.push({ |
| | | x: Math.round(current.x),
|
| | | y: Math.round(current.y),
|
| | | w: Math.round(current.w),
|
| | | h: Math.round(current.h),
|
| | | isRemain: true
|
| | | });
|
| | | }
|
| | | }
|
| | |
|
| | | const nonGray = rects.filter(r => !r.isRemain);
|
| | | rects.splice(0, rects.length, ...nonGray, ...merged);
|
| | | };
|
| | |
|
| | | const adjustGrayRectangles = (layoutIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rects = layout.rects;
|
| | | const nonGrayRects = rects.filter(rect => !rect.isRemain);
|
| | |
|
| | | const remainingAreas = calculateRemainingAreas(layout.width, layout.height, nonGrayRects);
|
| | |
|
| | | const currentGrayRects = rects.filter(r => r.isRemain);
|
| | | currentGrayRects.forEach((_, index) => {
|
| | | if (index >= remainingAreas.length) {
|
| | | rects.splice(index, 1);
|
| | | }
|
| | | });
|
| | |
|
| | | remainingAreas.forEach((area, index) => {
|
| | | if (index < currentGrayRects.length) {
|
| | | currentGrayRects[index].x = Math.round(area.x);
|
| | | currentGrayRects[index].y = Math.round(area.y);
|
| | | currentGrayRects[index].w = Math.round(area.w);
|
| | | currentGrayRects[index].h = Math.round(area.h);
|
| | | } else {
|
| | | rects.push({
|
| | | x: Math.round(area.x),
|
| | | y: Math.round(area.y),
|
| | | w: Math.round(area.w),
|
| | | h: Math.round(area.h),
|
| | | isRemain: true
|
| | | });
|
| | | }
|
| | | });
|
| | |
|
| | | mergeAdjacentGrayRects(rects);
|
| | | };
|
| | |
|
| | | const rotateRect = (layoutIndex, rectIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[rectIndex];
|
| | | const originalState = { ...rect };
|
| | |
|
| | | // 旋转矩形
|
| | | const temp = rect.w;
|
| | | rect.w = rect.h;
|
| | | rect.h = temp;
|
| | |
|
| | | // 检查旋转后是否与其他蓝色矩形重叠
|
| | | const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
|
| | | let isValidRotation = true;
|
| | |
|
| | | otherRects.forEach(otherRect => {
|
| | | if (checkOverlap(rect, otherRect)) {
|
| | | isValidRotation = false;
|
| | | }
|
| | | });
|
| | |
|
| | | // 检查是否超出布局边界
|
| | | if (rect.x + rect.w > layout.width || rect.y + rect.h > layout.height) {
|
| | | isValidRotation = false;
|
| | | }
|
| | |
|
| | | if (isValidRotation) {
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | } else {
|
| | | // 恢复原状
|
| | | rect.w = originalState.w;
|
| | | rect.h = originalState.h;
|
| | | ElMessage.warning('无法旋转,存在重叠或超出边界');
|
| | | }
|
| | | };
|
| | |
|
| | | const moveRectAndRotate = (layoutIndex, rectIndex, direction) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[rectIndex];
|
| | | const grayRects = layout.rects.filter(r => r.isRemain);
|
| | |
|
| | | // 旋转矩形
|
| | | const temp = rect.w;
|
| | | rect.w = rect.h;
|
| | | rect.h = temp;
|
| | |
|
| | | // 检查旋转后的矩形是否可以放置在某个灰色矩形的位置
|
| | | const canPlace = grayRects.some(grayRect => {
|
| | | return grayRect.w >= rect.w && grayRect.h >= rect.h;
|
| | | });
|
| | |
|
| | | if (!canPlace) {
|
| | | // 如果不能放置,恢复原状
|
| | | const temp = rect.w;
|
| | | rect.w = rect.h;
|
| | | rect.h = temp;
|
| | | ElMessage.warning('无法旋转,没有足够的空间');
|
| | | return;
|
| | | }
|
| | |
|
| | | // 调整灰色矩形
|
| | | adjustGrayRectangles(layoutIndex);
|
| | |
|
| | | // 移动矩形
|
| | | moveRect(layoutIndex, rectIndex, direction);
|
| | | };
|
| | |
|
| | | const moveRect = (layoutIndex, rectIndex, direction) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[rectIndex];
|
| | | const originalState = { ...rect };
|
| | |
|
| | | // 计算剩余空间
|
| | | const remainingAreas = calculateRemainingAreas(layout.width, layout.height, layout.rects.filter(r => !r.isRemain));
|
| | | |
| | | // 根据方向计算可移动的最大步长
|
| | | let maxStep = 0;
|
| | | switch (direction) {
|
| | | case 'up':
|
| | | maxStep = rect.y;
|
| | | break;
|
| | | case 'down':
|
| | | maxStep = layout.height - (rect.y + rect.h);
|
| | | break;
|
| | | case 'left':
|
| | | maxStep = rect.x;
|
| | | break;
|
| | | case 'right':
|
| | | maxStep = layout.width - (rect.x + rect.w);
|
| | | break;
|
| | | }
|
| | |
|
| | | // 移动步长,根据剩余空间动态调整
|
| | | const stepSize = maxStep;
|
| | | const actualStep = Math.min(maxStep, stepSize);
|
| | |
|
| | | // 移动矩形
|
| | | switch (direction) {
|
| | | case 'up':
|
| | | rect.y -= actualStep;
|
| | | break;
|
| | | case 'down':
|
| | | rect.y += actualStep;
|
| | | break;
|
| | | case 'left':
|
| | | rect.x -= actualStep;
|
| | | break;
|
| | | case 'right':
|
| | | rect.x += actualStep;
|
| | | break;
|
| | | }
|
| | |
|
| | | // 检查是否与其他蓝色矩形重叠
|
| | | const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
|
| | | let isValidMove = true;
|
| | |
|
| | | otherRects.forEach(otherRect => {
|
| | | if (checkOverlap(rect, otherRect)) {
|
| | | isValidMove = false;
|
| | | }
|
| | | });
|
| | |
|
| | | // 检查是否超出布局边界
|
| | | if (rect.x < 0 || rect.y < 0 ||
|
| | | rect.x + rect.w > layout.width ||
|
| | | rect.y + rect.h > layout.height) {
|
| | | isValidMove = false;
|
| | | }
|
| | |
|
| | | if (isValidMove) {
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | } else {
|
| | | // 恢复原状
|
| | | rect.x = originalState.x;
|
| | | rect.y = originalState.y;
|
| | | ElMessage.warning('无法移动,存在重叠或超出边界');
|
| | | }
|
| | | };
|
| | |
|
| | | const deleteRect = (layoutIndex, rectIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | layout.rects.splice(rectIndex, 1);
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | };
|
| | |
|
| | | const checkOverlap = (rect1, rect2) => {
|
| | | return !(rect1.x + rect1.w <= rect2.x ||
|
| | | rect1.x >= rect2.x + rect2.w ||
|
| | | rect1.y + rect1.h <= rect2.y ||
|
| | | rect1.y >= rect2.y + rect2.h);
|
| | | };
|
| | |
|
| | | const calculateRemainingAreas = (totalWidth, totalHeight, obstacles) => {
|
| | | let remaining = [{ x: 0, y: 0, w: totalWidth, h: totalHeight }];
|
| | | obstacles.forEach(rect => {
|
| | | remaining = cutRemainingAreas(remaining, rect);
|
| | | });
|
| | | return remaining;
|
| | | };
|
| | |
|
| | | const cutRemainingAreas = (remainingAreas, obstacle) => {
|
| | | const newRemaining = [];
|
| | | remainingAreas.forEach(area => {
|
| | | if (checkOverlap(area, obstacle)) {
|
| | | if (obstacle.x > area.x) {
|
| | | newRemaining.push({
|
| | | x: area.x,
|
| | | y: area.y,
|
| | | w: obstacle.x - area.x,
|
| | | h: area.h
|
| | | });
|
| | | }
|
| | | if (obstacle.x + obstacle.w < area.x + area.w) {
|
| | | newRemaining.push({
|
| | | x: obstacle.x + obstacle.w,
|
| | | y: area.y,
|
| | | w: area.w - (obstacle.x + obstacle.w - area.x),
|
| | | h: area.h
|
| | | });
|
| | | }
|
| | | if (obstacle.y > area.y) {
|
| | | newRemaining.push({
|
| | | x: area.x,
|
| | | y: area.y,
|
| | | w: area.w,
|
| | | h: obstacle.y - area.y
|
| | | });
|
| | | }
|
| | | if (obstacle.y + obstacle.h < area.y + area.h) {
|
| | | newRemaining.push({
|
| | | x: area.x,
|
| | | y: obstacle.y + obstacle.h,
|
| | | w: area.w,
|
| | | h: area.h - (obstacle.y + obstacle.h - area.y)
|
| | | });
|
| | | }
|
| | | } else {
|
| | | newRemaining.push(area);
|
| | | }
|
| | | });
|
| | | return newRemaining;
|
| | | };
|
| | |
|
| | | const getCurrentRectInfo = (layoutIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[focusIndex.value?.rectIndex || 0];
|
| | | if (!rect) return '';
|
| | | const totalRects = layouts.value.length;
|
| | | const currentRectIndex = layoutIndex + 1;
|
| | | const width = layout.width;
|
| | | const height = layout.height;
|
| | | const percentage = ((rect.w / layout.width) * 100).toFixed(1) + '%';
|
| | | return `${currentRectIndex}/${totalRects} ${width}×${height} ×1 ${percentage}`;
|
| | | };
|
| | |
|
| | | const selectLayout = (layoutIndex) => {
|
| | | selectedLayoutIndex.value = layoutIndex;
|
| | | };
|
| | |
|
| | | const updateLayout = () => {
|
| | | if (!layoutPanel.value) return;
|
| | | layouts.value = props.layoutData.Layouts;
|
| | | };
|
| | |
|
| | | onMounted(() => {
|
| | | setTimeout(updateLayout, 1000);
|
| | |
|
| | | selectedLayoutIndex.value = 0;
|
| | | });
|
| | |
|
| | | onUnmounted(() => {
|
| | | rectsElements.value = {};
|
| | | });
|
| | | </script>
|
| | |
|
| | | <style scoped>
|
| | | .layout-wrapper {
|
| | | position: relative;
|
| | | margin-top: 50px;
|
| | | }
|
| | |
|
| | | .layout-container {
|
| | | position: relative;
|
| | | overflow: visible;
|
| | | }
|
| | |
|
| | | .layout-info {
|
| | | color: #444;
|
| | | font-size: 12px;
|
| | | background-color: #ffffff;
|
| | | padding: 5px 10px;
|
| | | border-radius: 3px;
|
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
| | | font-weight: bold;
|
| | | }
|
| | |
|
| | | .rect-content {
|
| | | display: grid;
|
| | | grid-template-columns: 1fr;
|
| | | grid-template-rows: 1fr;
|
| | | padding: 5px;
|
| | | }
|
| | |
|
| | | .size {
|
| | | grid-row: 1;
|
| | | grid-column: 1;
|
| | | color: #444;
|
| | | font-size: 12px;
|
| | | }
|
| | |
|
| | | .jia-hao {
|
| | | grid-row: 2;
|
| | | grid-column: 1;
|
| | | margin: auto;
|
| | | font-size: 14px;
|
| | | font-weight: bold;
|
| | | }
|
| | |
|
| | | .sidebar-item {
|
| | | padding: 10px;
|
| | | cursor: pointer;
|
| | | }
|
| | |
|
| | | .sidebar-item.selected {
|
| | | background: #ddd;
|
| | | }
|
| | |
|
| | | .context-menu {
|
| | | position: absolute;
|
| | | background-color: #fff;
|
| | | border: 1px solid #ccc;
|
| | | padding: 5px;
|
| | | z-index: 1001;
|
| | | }
|
| | |
|
| | | .context-menu div {
|
| | | padding: 5px;
|
| | | cursor: pointer;
|
| | | }
|
| | |
|
| | | .context-menu div:hover {
|
| | | background-color: #f0f0f0;
|
| | | }
|
| | | </style>
|
| | |
| | | <script setup> |
| | | import {nextTick, onMounted, reactive, ref, watch} from "vue"; |
| | | import {nextTick, onMounted, reactive, ref, watch,onBeforeUnmount } from "vue"; |
| | | import {useI18n} from "vue-i18n"; |
| | | import {Folder, Plus, Setting, Operation,} from "@element-plus/icons-vue"; |
| | | import OptimizeCompute from "@/views/pp/glassOptimize/page/OptimizeCompute.vue"; |
| | |
| | | //工程号 |
| | | const projectNo = ref(route.params.projectNo); |
| | | const projectName = ref(''); |
| | | onBeforeUnmount(() => { |
| | | localStorage.setItem('projectNo', projectNo.value); |
| | | }); |
| | | |
| | | const fetchData = () => { |
| | | request.post(`/glassOptimize/projectInfo/${projectNo.value}`).then((res) => { |
File was renamed from north-glass-erp/northglass-erp/src/views/pp/glassOptimize/RectRenderer.vue |
| | |
| | | <template>
|
| | | <div ref="layoutPanel" :class="panelClass" :style="panelStyle">
|
| | | <div v-for="(layout, layoutIndex) in layouts" :key="layoutIndex" |
| | | class="layout-wrapper">
|
| | | |
| | | <div v-for="(layout, layoutIndex) in layouts" :key="layoutIndex" class="layout-wrapper">
|
| | | <!-- 布局信息标签 -->
|
| | | <div class="layout-info" :style="layoutInfoStyle(layoutIndex)">
|
| | | 布局{{ layoutIndex + 1 }}
|
| | | {{ getCurrentRectInfo(layoutIndex) }}
|
| | | </div>
|
| | |
|
| | | <!-- 布局容器 -->
|
| | | <div class="layout-container"
|
| | | :style="layoutContainerStyle(layoutIndex)">
|
| | | |
| | | <div v-for="(rect, rectIndex) in layout.rects" :key="rectIndex" |
| | | <div class="layout-container" :style="layoutContainerStyle(layoutIndex)">
|
| | | <div v-for="(rect, rectIndex) in layout.rects" :key="rectIndex"
|
| | | :ref="(el) => { if (el) rectsElements[layoutIndex + '-' + rectIndex] = el }"
|
| | | :class="rectClass"
|
| | | :style="rectStyle(rect, layoutIndex)"
|
| | |
| | | import { ref, reactive, onMounted, onUnmounted } from 'vue';
|
| | |
|
| | | const props = defineProps({
|
| | | layoutData: {
|
| | | type: Object,
|
| | | required: true
|
| | | },
|
| | | gw: {
|
| | | type: Number,
|
| | | default: 1000
|
| | | },
|
| | | gh: {
|
| | | type: Number,
|
| | | default: 1000
|
| | | },
|
| | | style: {
|
| | | type: String,
|
| | | default: 'width:1000px;height:600px;display:block;background:gray'
|
| | | }
|
| | | layoutData: { type: Object, required: true },
|
| | | gw: { type: Number, default: 1000 },
|
| | | gh: { type: Number, default: 1000 },
|
| | | style: { type: String, default: 'width:1000px;height:600px;display:block;background:gray' }
|
| | | });
|
| | |
|
| | | const emit = defineEmits(['rectClicked']);
|
| | |
|
| | | const layoutPanel = ref(null);
|
| | | const rectsElements = ref({});
|
| | | const focusIndex = ref(null);
|
| | | const layouts = ref([]);
|
| | |
|
| | | const panelClass = ref('');
|
| | | const panelStyle = ref(props.style);
|
| | |
|
| | | const rectClass = ref('layout-rect');
|
| | |
|
| | | const layoutContainerStyle = (layoutIndex) => {
|
| | | const containerWidth = (props.gw - 210) / 2; // 两列,每列宽度为gw的一半,减去右边距
|
| | | const containerHeight = (props.gh - 100) / 3; // 三行,每行高度为gh的三分之一,减去下边距
|
| | | const x = (layoutIndex % 2) * (containerWidth + 50); // 横向排列,加上50px间距
|
| | | const y = Math.floor(layoutIndex / 2) * (containerHeight + 50); // 纵向排列,加上50px间距
|
| | | const containerWidth = (props.gw - 210) / 2;
|
| | | const containerHeight = (props.gh - 100) / 3;
|
| | | const x = (layoutIndex % 2) * (containerWidth + 50);
|
| | | const y = Math.floor(layoutIndex / 2) * (containerHeight + 50);
|
| | | return {
|
| | | position: 'absolute',
|
| | | left: `${x}px`,
|
| | |
| | | return {
|
| | | position: 'absolute',
|
| | | left: `${x}px`,
|
| | | top: `${y - 45}px`, // 将标签放在版图容器的上方
|
| | | top: `${y - 45}px`,
|
| | | background: 'none',
|
| | | textAlign: 'center',
|
| | | zIndex: 1000
|
| | |
| | | containerWidth / layout.width,
|
| | | containerHeight / layout.height
|
| | | );
|
| | | |
| | | return {
|
| | | position: 'absolute',
|
| | | left: `${rect.x * scale}px`,
|
| | |
| | | emit('rectClicked', layoutIndex, rectIndex);
|
| | | };
|
| | |
|
| | | const getCurrentRectInfo = (layoutIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[focusIndex.value?.rectIndex || 0];
|
| | | if (!rect) return '';
|
| | | const totalRects = layouts.value.length;
|
| | | const currentRectIndex = layoutIndex+1;
|
| | | const width = layout.width;
|
| | | const height = layout.height;
|
| | | const percentage = ((rect.w / layout.width) * 100).toFixed(1) + '%';
|
| | | return `${currentRectIndex}/${totalRects} ${width}×${height} ×1 ${percentage}`;
|
| | | };
|
| | |
|
| | | const updateLayout = () => {
|
| | | if (!layoutPanel.value) return;
|
| | |
|
| | | layouts.value = props.layoutData.data.Layouts;
|
| | | layouts.value = props.layoutData.Layouts;
|
| | | };
|
| | |
|
| | | onMounted(() => {
|
| | |
| | | onUnmounted(() => {
|
| | | rectsElements.value = {};
|
| | | });
|
| | |
|
| | |
|
| | | </script>
|
| | |
|
| | | <style scoped>
|
| | | .layout-wrapper {
|
| | | position: relative;
|
| | | margin-top:50px;
|
| | | margin-top: 50px;
|
| | | }
|
| | |
|
| | | .layout-container {
|
| | |
| | | border-radius: 3px;
|
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
| | | font-weight: bold;
|
| | |
|
| | | }
|
| | |
|
| | | .rect-content {
|
| | |
| | | import cn.dev33.satoken.annotation.SaCheckPermission; |
| | | import com.example.erp.common.Constants; |
| | | import com.example.erp.common.Result; |
| | | import com.example.erp.entity.pp.LayoutsData; |
| | | import com.example.erp.entity.pp.OptimizeProjectMange; |
| | | import com.example.erp.exception.ServiceException; |
| | | import com.example.erp.service.pp.GlassOptimizeService; |
| | | import com.example.erp.service.pp.JsonToOptConverter; |
| | | import com.example.erp.service.userInfo.UserService; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.io.IOException; |
| | | import java.sql.Date; |
| | | import java.util.Map; |
| | | |
| | |
| | | public class GlassOptimizeController { |
| | | @Autowired |
| | | GlassOptimizeService glassOptimizeService; |
| | | |
| | | @Autowired |
| | | private UserService userService; |
| | | //工程信息 |
| | | @ApiOperation("工程信息接口") |
| | | @PostMapping ("/projectInfo/{projectNo}") |
| | |
| | | } |
| | | } |
| | | |
| | | @ApiOperation("优化设置保存") |
| | | @PostMapping("/optimizeParms") |
| | | public Result optimizeParmsSave(@RequestBody Map<String, Object> object) { |
| | | try { |
| | | return Result.seccess(glassOptimizeService.optimizeParmsSave(object)); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return Result.error(); |
| | | } |
| | | } |
| | | |
| | | |
| | | @PostMapping("/selectOptimizeParms/{username}") |
| | | public Result getOptimizeParms(@PathVariable String username) { |
| | | return Result.seccess(userService.getOptimizeParms(username)); |
| | | } |
| | | |
| | | |
| | | |
| | |
| | | return Result.error(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | |
| | | @RequestBody Map<String,Object> object){ |
| | | return Result.seccess(glassOptimizeService.addProjectSv(optionVal,projectId,projectNmae,object)); |
| | | } |
| | | |
| | | |
| | | @ApiOperation("保存优化结果接口") |
| | | @PostMapping("/saveOptimizeResult") |
| | | public Result saveOptimizeResult( |
| | | @RequestBody Map<String,Object> object){ |
| | | return Result.seccess(glassOptimizeService.saveOptimizeResult(object)); |
| | | } |
| | | |
| | | |
| | | @ApiOperation("查询优化结果接口") |
| | | @PostMapping("/selectOptimizeResult/{processId}") |
| | | public Result selectOptimizeResult( |
| | | @PathVariable String processId){ |
| | | return Result.seccess(glassOptimizeService.selectOptimizeResult(processId)); |
| | | } |
| | | |
| | | @ApiOperation("更新优化结果接口") |
| | | @PostMapping("/updateOptimizeResult/{processId}") |
| | | public Result updateOptimizeResult( |
| | | @PathVariable String processId,@RequestBody Map<String,Object> object){ |
| | | |
| | | return Result.seccess(glassOptimizeService.updateOptimizeResult(object,processId)); |
| | | } |
| | | @ApiOperation("OPT文件下载接口") |
| | | @PostMapping("/generateOpt") |
| | | public ResponseEntity<byte[]> generateOptFile(@RequestBody LayoutsData layoutsData) throws IOException { |
| | | // 确保 layoutsData 包含 Layouts 数组 |
| | | if (layoutsData == null || layoutsData.getLayouts() == null) { |
| | | throw new IllegalArgumentException("Layouts 数据不能为空"); |
| | | } |
| | | |
| | | // 生成 OPT 文件内容 |
| | | String optContent = JsonToOptConverter.generateOptContent(layoutsData); |
| | | |
| | | // 创建响应头 |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.setContentType(org.springframework.http.MediaType.TEXT_PLAIN); |
| | | headers.setContentDispositionFormData("attachment", "output.opt"); |
| | | |
| | | // 返回文件内容 |
| | | return new ResponseEntity<>(optContent.getBytes(), headers, HttpStatus.OK); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | public Result updateUserName(@RequestBody Map<String,Object> object){ |
| | | return Result.seccess( userService.updateUserName(object)); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.example.erp.entity.pp;
|
| | |
|
| | | import com.fasterxml.jackson.annotation.JsonProperty;
|
| | | import java.util.List;
|
| | |
|
| | | public class LayoutsData {
|
| | | @JsonProperty("Layouts")
|
| | | private List<Layout> layouts;
|
| | |
|
| | | public List<Layout> getLayouts() {
|
| | | return layouts;
|
| | | }
|
| | |
|
| | |
|
| | | public static class Layout {
|
| | | @JsonProperty("mnumber")
|
| | | private int mNumber;
|
| | | @JsonProperty("width")
|
| | | private int width;
|
| | | @JsonProperty("rects")
|
| | | private List<Rect> rects;
|
| | | @JsonProperty("wuliao")
|
| | | private String material;
|
| | | @JsonProperty("SameCount")
|
| | | private int sameCount;
|
| | | @JsonProperty("height")
|
| | | private int height;
|
| | |
|
| | | public int getWidth() {
|
| | | return width;
|
| | | }
|
| | |
|
| | | public int getHeight() {
|
| | | return height;
|
| | | }
|
| | |
|
| | | public List<Rect> getRects() {
|
| | | return rects;
|
| | | }
|
| | | }
|
| | |
|
| | | public static class Rect {
|
| | | @JsonProperty("isRemain")
|
| | | private boolean isRemain;
|
| | | @JsonProperty("h")
|
| | | private int height;
|
| | | @JsonProperty("DM2")
|
| | | private int dm2;
|
| | | @JsonProperty("xuhao")
|
| | | private String serialNumber;
|
| | | @JsonProperty("DM1")
|
| | | private int dm1;
|
| | | @JsonProperty("liuchengka")
|
| | | private String processCard;
|
| | | @JsonProperty("JiaHao")
|
| | | private String jiaHao;
|
| | | @JsonProperty("LM2")
|
| | | private int lm2;
|
| | | @JsonProperty("LM1")
|
| | | private int lm1;
|
| | | @JsonProperty("w")
|
| | | private int width;
|
| | | @JsonProperty("x")
|
| | | private int x;
|
| | | @JsonProperty("y")
|
| | | private int y;
|
| | | @JsonProperty("rownumber")
|
| | | private int rowNumber;
|
| | |
|
| | | public int getWidth() {
|
| | | return width;
|
| | | }
|
| | |
|
| | | public int getHeight() {
|
| | | return height;
|
| | | }
|
| | |
|
| | | public String getProcessCard() {
|
| | | return processCard;
|
| | | }
|
| | | }
|
| | | } |
| | |
| | | private String createTime; |
| | | private String updateTime; |
| | | private Integer state; |
| | | private String optimizeParms; |
| | | @TableField(select = false,exist = false) |
| | | private List<UserRole> userRoleList; |
| | | |
| | |
| | | void addratioResult(Map<String, Object> object); |
| | | //模拟计算保存 工程信息 |
| | | void addratioProjectResult(Map<String, Object> object); |
| | | //优化设置保存 |
| | | void optimizeParmsSave(String jsonString); |
| | | |
| | | //优化结果保存 |
| | | void optimizeResultSave(String jsonString); |
| | | //优化结果查询 |
| | | List<Map<String, Object>> selectOptimizeResult(String processId); |
| | | //优化结果调整 |
| | | void updateOptimizeResult(String jsonString,String processId); |
| | | |
| | | List<Map<String, Object>> getProcessCardDetailmMp(String processId, Integer technologyNumber); |
| | | |
| | |
| | | Boolean updateProcessMp(Integer id, String process); |
| | | |
| | | List<User> findByAddress(String userName); |
| | | |
| | | String selectOptimizeParmsById(@Param("username") String username); |
| | | } |
| | |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | //优化设置保存 |
| | | public Boolean optimizeParmsSave(Map<String, Object> object) { |
| | | try { |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | String jsonString = mapper.writeValueAsString(object); |
| | | |
| | | glassOptimizeMapper.optimizeParmsSave(jsonString); |
| | | return true; |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | //优化调整结果保存 |
| | | public Boolean saveOptimizeResult(Map<String, Object> object) { |
| | | try { |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | String jsonString = mapper.writeValueAsString(object); |
| | | glassOptimizeMapper.optimizeResultSave(jsonString); |
| | | return true; |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | public Boolean updateOptimizeResult(Map<String, Object> object,String processId){ |
| | | try { |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | String jsonString = mapper.writeValueAsString(object); |
| | | glassOptimizeMapper.updateOptimizeResult(jsonString,processId); |
| | | return true; |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | //优化调整结果查询 |
| | | public Map<String, Object> selectOptimizeResult(String processId) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("data", glassOptimizeMapper.selectOptimizeResult(processId)); |
| | | return map; |
| | | } |
| | | |
| | | //工程信息 |
| | | public Map<String, Object> projectInfoSv(String projectNo) { |
| | | Map<String, Object> map = new HashMap<>(); |
New file |
| | |
| | | package com.example.erp.service.pp;
|
| | |
|
| | | import com.example.erp.entity.pp.LayoutsData;
|
| | | import com.example.erp.entity.pp.LayoutsData.*;
|
| | | import com.fasterxml.jackson.databind.ObjectMapper;
|
| | | import java.io.IOException;
|
| | | import java.util.List;
|
| | |
|
| | | public class JsonToOptConverter {
|
| | |
|
| | | public static String convertToJson(LayoutsData layoutsData) throws IOException {
|
| | | ObjectMapper objectMapper = new ObjectMapper();
|
| | | return objectMapper.writeValueAsString(layoutsData);
|
| | | }
|
| | |
|
| | | public static String generateOptContent(LayoutsData layoutsData) {
|
| | | StringBuilder optContent = new StringBuilder();
|
| | | addHeader(optContent);
|
| | | addSignatures(optContent);
|
| | | addPatterns(optContent, layoutsData);
|
| | | addInfos(optContent, layoutsData);
|
| | | return optContent.toString();
|
| | | }
|
| | |
|
| | | private static void addHeader(StringBuilder optContent) {
|
| | | optContent.append("[OPT_Header]\n");
|
| | | optContent.append("OPTCutVersion=4.0\n");
|
| | | optContent.append("Dimension=mm\n");
|
| | | optContent.append("Date=2025/2/25\n\n");
|
| | | }
|
| | |
|
| | | private static void addSignatures(StringBuilder optContent) {
|
| | | optContent.append("[OPT_Signature]\n");
|
| | | optContent.append("Creator=OPTIMA S.r.l.\n\n");
|
| | | }
|
| | |
|
| | | private static void addPatterns(StringBuilder optContent, LayoutsData layoutsData) {
|
| | | optContent.append("[OPT_Pattern]\n");
|
| | | for (Layout layout : layoutsData.getLayouts()) {
|
| | | optContent.append("GlassID=32\n");
|
| | | optContent.append("GlassDescription=32\n");
|
| | | optContent.append("GlassType=0\n");
|
| | | optContent.append("GlassThickness=5\n");
|
| | | optContent.append("Pieces=100\n");
|
| | | optContent.append("Width=").append(layout.getWidth()).append("\n");
|
| | | optContent.append("Height=").append(layout.getHeight()).append("\n");
|
| | | optContent.append("TrimLeft=15\n");
|
| | | optContent.append("TrimBottom=0\n");
|
| | | optContent.append("TrimRight=0\n");
|
| | | optContent.append("TrimTop=0\n");
|
| | | optContent.append("MinCutDistance=10\n");
|
| | | optContent.append("Priority=0\n");
|
| | | optContent.append("TravType=XY\n\n");
|
| | | }
|
| | | }
|
| | |
|
| | | private static void addInfos(StringBuilder optContent, LayoutsData layoutsData) {
|
| | | int id = 1;
|
| | | for (Layout layout : layoutsData.getLayouts()) {
|
| | | for (Rect rect : layout.getRects()) {
|
| | | optContent.append("[Info]\n");
|
| | | optContent.append("Id=").append(id++).append("\n");
|
| | | optContent.append("SecondGlassReference=\n");
|
| | | optContent.append("RackNo=0\n");
|
| | | optContent.append("SheetWidth=").append(rect.getWidth()).append("\n");
|
| | | optContent.append("SheetHeight=").append(rect.getHeight()).append("\n");
|
| | | optContent.append("Customer=\n");
|
| | | optContent.append("PosNo=\n");
|
| | | optContent.append("OrderNo=").append(rect.getProcessCard()).append("-1-").append(id - 1).append("\n");
|
| | | optContent.append("RackCode=0\n");
|
| | | optContent.append("PieceStandardPz=\n");
|
| | | optContent.append("UMPz=\n");
|
| | | optContent.append("IDPz=\n");
|
| | | optContent.append("RealDimXPz=").append(rect.getWidth()).append(".00\n");
|
| | | optContent.append("RealDimYPz=").append(rect.getHeight()).append(".00\n");
|
| | | optContent.append("GrindingPz=\n");
|
| | | optContent.append("GrindingPzX1=0\n");
|
| | | optContent.append("GrindingPzY1=0\n");
|
| | | optContent.append("GrindingPzX2=0\n");
|
| | | optContent.append("GrindingPzY2=0\n");
|
| | | optContent.append("BendingPz=\n");
|
| | | optContent.append("QuantityPz=77\n");
|
| | | optContent.append("LabelsPz=\n");
|
| | | optContent.append("LabelsPzCounter=\n");
|
| | | optContent.append("RotationAllowed=1\n");
|
| | | optContent.append("PreferencePz=\n");
|
| | | optContent.append("DescMatCompPz=\n");
|
| | | optContent.append("DeliveryDatePz=\n");
|
| | | optContent.append("PzNOTE=3C.orzx\n");
|
| | | optContent.append("PzNOTE1=\n");
|
| | | optContent.append("PzNOTE2=").append(rect.getWidth()).append("\n");
|
| | | optContent.append("PzNOTE3=").append(rect.getHeight()).append("\n");
|
| | | optContent.append("PzNOTE4=右下-30-30\n");
|
| | | optContent.append("PzNOTE5=false-true-false\n");
|
| | | optContent.append("PzNOTE6=true-true\n");
|
| | | optContent.append("PzNOTE7=").append(rect.getProcessCard()).append("-1-").append(id - 1).append("\n");
|
| | | for (int i = 8; i <= 20; i++) {
|
| | | optContent.append("PzNOTE").append(i).append("=\n");
|
| | | }
|
| | | optContent.append("\n");
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | map.put("users", Collections.singletonList(userList)); |
| | | return map; |
| | | } |
| | | |
| | | |
| | | //查询用户优化参数 |
| | | public String getOptimizeParms(String username) { |
| | | // 获取当前登录用户 |
| | | |
| | | return userMapper.selectOptimizeParmsById(username); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | LEFT JOIN pp.damage_details dal ON dal.order_number = g.order_number AND dal.technology_number = g.technology_number and f.process_id=dal.process_id |
| | | LEFT JOIN pp.flow_card fl ON fl.order_id = g.order_id AND fl.order_number = g.order_number AND fl.technology_number = g.technology_number |
| | | WHERE |
| | | p.state IN (1, 2) and |
| | | f.process_id = #{processId} |
| | | </select> |
| | | |
| | |
| | | ); |
| | | </foreach> |
| | | </insert> |
| | | |
| | | <!--模拟计算结果保存--> |
| | | <insert id="addratioResult" parameterType="map"> |
| | | <foreach collection="projectdetail.data[0].ratioResult" item="glass"> |
| | | INSERT INTO pp.optimize_heat_layout ( |
| | |
| | | </foreach> |
| | | </insert> |
| | | |
| | | |
| | | <!--模拟计算工程更新--> |
| | | <update id="addratioProjectResult" parameterType="map"> |
| | | UPDATE pp.optimize_project |
| | | SET |
| | |
| | | project_no = #{inputValues.project_no} |
| | | |
| | | </update> |
| | | <!--优化设置保存--> |
| | | <update id="optimizeParmsSave"> |
| | | update erp_user_info.user as u |
| | | set u.optimize_parms = #{jsonString} |
| | | </update> |
| | | |
| | | <update id="updateOptimizeResult"> |
| | | update pp.optimize_project_file as u |
| | | set u.content = #{jsonString} |
| | | where u.project_no=#{processId} and type='优化结果' |
| | | </update> |
| | | |
| | | |
| | | |
| | | <select id="selectOptimizeResult"> |
| | | SELECT content as Layouts |
| | | FROM pp.optimize_project_file |
| | | WHERE project_no=#{processId} and type='优化结果'; |
| | | </select> |
| | | </mapper> |
| | |
| | | set address=#{process},update_time=now() |
| | | where id=#{id} |
| | | </update> |
| | | |
| | | |
| | | <select id="selectOptimizeParmsById" resultType="String"> |
| | | SELECT optimize_parms FROM erp_user_info.user WHERE user_name = #{username} |
| | | </select> |
| | | |
| | | |
| | | </mapper> |