新增JeecgBoot BPM流程自动生成器,包含流程创建、修改及审批人配置功能,支持自然语言描述转化为BPMN XML,并通过API与JeecgBoot系统交互。
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
|
||||
<title><%= title %></title>
|
||||
<link rel="icon" href="<%= basePublicPath %>/logo.png" />
|
||||
<!-- Hiprint 打印样式(media=print,必须) -->
|
||||
<link rel="stylesheet" type="text/css" media="print" href="<%= basePublicPath %>/print-lock.css" />
|
||||
<!-- 全局配置 -->
|
||||
<script>
|
||||
window._CONFIG = {};
|
||||
|
||||
293
jeecgboot-vue3/package-lock.json
generated
293
jeecgboot-vue3/package-lock.json
generated
@@ -40,6 +40,7 @@
|
||||
"event-source-polyfill": "^1.0.31",
|
||||
"highlight.js": "^11.11.1",
|
||||
"intro.js": "^7.2.0",
|
||||
"jquery": "^3.7.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lodash.get": "^4.4.2",
|
||||
"markdown-it": "^14.1.0",
|
||||
@@ -65,6 +66,7 @@
|
||||
"vue-cropperjs": "^5.0.0",
|
||||
"vue-i18n": "^9.14.5",
|
||||
"vue-infinite-scroll": "^2.0.2",
|
||||
"vue-plugin-hiprint": "^0.0.60",
|
||||
"vue-print-nb-jeecg": "^1.0.13",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue-types": "^5.1.3",
|
||||
@@ -2040,6 +2042,14 @@
|
||||
"@keyv/serialize": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@claviska/jquery-minicolors": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@claviska/jquery-minicolors/-/jquery-minicolors-2.3.6.tgz",
|
||||
"integrity": "sha512-8Ro6D4GCrmOl41+6w4NFhEOpx8vjxwVRI69bulXsFDt49uVRKhLU5TnzEV7AmOJrylkVq+ugnYNMiGHBieeKUQ==",
|
||||
"peerDependencies": {
|
||||
"jquery": ">= 1.7.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@commitlint/cli": {
|
||||
"version": "18.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-18.6.1.tgz",
|
||||
@@ -4433,6 +4443,11 @@
|
||||
"@sinonjs/commons": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
||||
},
|
||||
"node_modules/@sphinxxxx/color-conversion": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz",
|
||||
@@ -4727,6 +4742,11 @@
|
||||
"integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/raf": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
|
||||
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw=="
|
||||
},
|
||||
"node_modules/@types/resolve": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
||||
@@ -5729,6 +5749,18 @@
|
||||
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz",
|
||||
"integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ=="
|
||||
},
|
||||
"node_modules/@wtto00/html2canvas": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@wtto00/html2canvas/-/html2canvas-1.4.3.tgz",
|
||||
"integrity": "sha512-jwsb+xL8N+gjrSNABSaFdxmWtE4c7RNFjP20lo1G7gs63Qqo1phhxVBTzxc/apDVh6LgXsU2l5bwKtXd9uz65w==",
|
||||
"dependencies": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@zxcvbn-ts/core": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@zxcvbn-ts/core/-/core-3.0.4.tgz",
|
||||
@@ -6101,7 +6133,6 @@
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"atob": "bin/atob.js"
|
||||
},
|
||||
@@ -6394,6 +6425,14 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-arraybuffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@@ -6561,6 +6600,17 @@
|
||||
"node-int64": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/btoa": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
|
||||
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
|
||||
"bin": {
|
||||
"btoa": "bin/btoa.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
@@ -6591,6 +6641,14 @@
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/bwip-js": {
|
||||
"version": "4.9.0",
|
||||
"resolved": "https://registry.npmjs.org/bwip-js/-/bwip-js-4.9.0.tgz",
|
||||
"integrity": "sha512-U3aWIxR/Px4m3GPd0opQ5GQJq/G8Cj0cr5z5hrcvy/SAApPnfkLqBqjRuB3GiEAasEQup3m7k/MDM/uiS9te8Q==",
|
||||
"bin": {
|
||||
"bwip-js": "bin/bwip-js.js"
|
||||
}
|
||||
},
|
||||
"node_modules/cac": {
|
||||
"version": "6.7.14",
|
||||
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
|
||||
@@ -6769,6 +6827,29 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/canvg": {
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
|
||||
"integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@types/raf": "^3.4.0",
|
||||
"core-js": "^3.8.3",
|
||||
"raf": "^3.4.1",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"rgbcolor": "^1.0.1",
|
||||
"stackblur-canvas": "^2.0.0",
|
||||
"svg-pathdata": "^6.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/canvg/node_modules/regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
@@ -7988,6 +8069,14 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/css-line-break": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
|
||||
@@ -8322,7 +8411,6 @@
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
@@ -8655,6 +8743,12 @@
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.9.tgz",
|
||||
"integrity": "sha512-i6mvVmWN4xo9LrhCOZrDgSs9noW6nOahbrmzjRbPF36YPyj5Ue5lgok0MHDWkG7xzpWFO2OYttXdzM7rJxHvNA==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||
@@ -8876,6 +8970,26 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.6.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz",
|
||||
"integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.4.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.18.3",
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/enquire.js": {
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz",
|
||||
@@ -11529,6 +11643,19 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/html2canvas": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||
@@ -13139,6 +13266,11 @@
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jquery": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
|
||||
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
|
||||
},
|
||||
"node_modules/js-base64": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
|
||||
@@ -13228,6 +13360,11 @@
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsbarcode": {
|
||||
"version": "3.12.3",
|
||||
"resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.12.3.tgz",
|
||||
"integrity": "sha512-CuHU9hC6dPsHF5oVFMo8NW76uQVjH4L22CsP4hW+dNnGywJHC/B0ThA1CTDVLnxKLrrpYdicBLnd2xsgTfRnvg=="
|
||||
},
|
||||
"node_modules/jsesc": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
|
||||
@@ -13334,6 +13471,23 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/jspdf": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/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/katex": {
|
||||
"version": "0.16.44",
|
||||
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.44.tgz",
|
||||
@@ -14703,8 +14857,7 @@
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/muggle-string": {
|
||||
"version": "0.3.1",
|
||||
@@ -15247,6 +15400,11 @@
|
||||
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/nzh": {
|
||||
"version": "1.0.14",
|
||||
"resolved": "https://registry.npmjs.org/nzh/-/nzh-1.0.14.tgz",
|
||||
"integrity": "sha512-wKgaqCSZdrySvB4RWop5g+v6IDv2IErsT6rjq06Bg0yiT9hiHYZO12GMGx/xweGVLcO2lDjX5RqWD0S/Jy9z5Q=="
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
@@ -15824,6 +15982,11 @@
|
||||
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -16690,6 +16853,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/raf": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||
"dependencies": {
|
||||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@@ -17317,6 +17488,14 @@
|
||||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/rgbcolor": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
|
||||
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
|
||||
"engines": {
|
||||
"node": ">= 0.8.15"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf": {
|
||||
"version": "5.0.10",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
||||
@@ -18060,6 +18239,32 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.8.3",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz",
|
||||
"integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.4.1",
|
||||
"engine.io-client": "~6.6.1",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz",
|
||||
"integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sortablejs": {
|
||||
"version": "1.15.7",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.7.tgz",
|
||||
@@ -18253,6 +18458,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/stackblur-canvas": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
|
||||
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
|
||||
"engines": {
|
||||
"node": ">=0.1.14"
|
||||
}
|
||||
},
|
||||
"node_modules/static-extend": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
|
||||
@@ -19258,6 +19471,14 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svg-pathdata": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
|
||||
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svg-tags": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
|
||||
@@ -19523,6 +19744,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/text-segmentation": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
@@ -20507,6 +20736,14 @@
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/utrie": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||
@@ -21569,6 +21806,26 @@
|
||||
"resolved": "https://registry.npmjs.org/vue-infinite-scroll/-/vue-infinite-scroll-2.0.2.tgz",
|
||||
"integrity": "sha512-n+YghR059YmciANGJh9SsNWRi1YZEBVlODtmnb/12zI+4R72QZSWd+EuZ5mW6auEo/yaJXgxzwsuhvALVnm73A=="
|
||||
},
|
||||
"node_modules/vue-plugin-hiprint": {
|
||||
"version": "0.0.60",
|
||||
"resolved": "https://registry.npmjs.org/vue-plugin-hiprint/-/vue-plugin-hiprint-0.0.60.tgz",
|
||||
"integrity": "sha512-a5uOMn6Nr4qlYYaVNbQKwRZJa8UcNMTflfi6J430/NDtySJB+5ArE8I8+NLjgVV56x3/qdUBs/GWuZCX5Umv1w==",
|
||||
"dependencies": {
|
||||
"@claviska/jquery-minicolors": "^2.3.6",
|
||||
"@wtto00/html2canvas": "^1.4.3",
|
||||
"bwip-js": "^4.0.0",
|
||||
"canvg": "^3.0.10",
|
||||
"jquery": "^3.6.0",
|
||||
"jsbarcode": "^3.11.5",
|
||||
"jspdf": "^2.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
"nzh": "^1.0.8",
|
||||
"socket.io-client": "^4.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-print-nb-jeecg": {
|
||||
"version": "1.0.13",
|
||||
"resolved": "https://registry.npmjs.org/vue-print-nb-jeecg/-/vue-print-nb-jeecg-1.0.13.tgz",
|
||||
@@ -22304,6 +22561,26 @@
|
||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.18.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xe-utils": {
|
||||
"version": "3.5.26",
|
||||
"resolved": "https://registry.npmjs.org/xe-utils/-/xe-utils-3.5.26.tgz",
|
||||
@@ -22318,6 +22595,14 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
||||
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xss": {
|
||||
"version": "1.0.15",
|
||||
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz",
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
"event-source-polyfill": "^1.0.31",
|
||||
"highlight.js": "^11.11.1",
|
||||
"intro.js": "^7.2.0",
|
||||
"jquery": "^3.7.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lodash.get": "^4.4.2",
|
||||
"markdown-it": "^14.1.0",
|
||||
@@ -79,6 +80,7 @@
|
||||
"vue-cropperjs": "^5.0.0",
|
||||
"vue-i18n": "^9.14.5",
|
||||
"vue-infinite-scroll": "^2.0.2",
|
||||
"vue-plugin-hiprint": "^0.0.60",
|
||||
"vue-print-nb-jeecg": "^1.0.13",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue-types": "^5.1.3",
|
||||
|
||||
352
jeecgboot-vue3/public/print-lock.css
Normal file
352
jeecgboot-vue3/public/print-lock.css
Normal file
@@ -0,0 +1,352 @@
|
||||
@media print {
|
||||
body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@page {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hiprint-printPaper * {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box; /* Firefox */
|
||||
-webkit-box-sizing: border-box; /* Safari */
|
||||
}
|
||||
|
||||
.hiprint-printPaper *:focus {
|
||||
outline: -webkit-focus-ring-color auto 0px;
|
||||
}
|
||||
|
||||
.hiprint-printPaper {
|
||||
position: relative;
|
||||
padding: 0 0 0 0;
|
||||
page-break-after: always;
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
user-select: none;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-printPaper-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 火狐浏览器打印 第一页过后 重叠问题 */
|
||||
@-moz-document url-prefix() {
|
||||
.hiprint-printPaper .hiprint-printPaper-content {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
top: -20px
|
||||
}
|
||||
}
|
||||
|
||||
.hiprint-printPaper.design {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
|
||||
.hiprint-printTemplate .hiprint-printPanel {
|
||||
page-break-after: always;
|
||||
}
|
||||
|
||||
.hiprint-printPaper, hiprint-printPanel {
|
||||
box-sizing: border-box;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.hiprint-printPanel .hiprint-printPaper:last-child {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
.hiprint-printTemplate .hiprint-printPanel:last-child {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hideheaderLinetarget {
|
||||
border-top: 0px dashed rgb(201, 190, 190) !important;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hidefooterLinetarget {
|
||||
border-top: 0px dashed rgb(201, 190, 190) !important;
|
||||
}
|
||||
|
||||
.hiprint-printPaper.design {
|
||||
border: 1px dashed rgba(170, 170, 170, 0.7);
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-table-content, .design .hiprint-printElement-longText-content {
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.design .resize-panel {
|
||||
box-sizing: border-box;
|
||||
border: 1px dotted;
|
||||
}
|
||||
|
||||
.hiprint-printElement-text {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
padding: 0 0 0 0;
|
||||
border: 0.75pt none rgb(0, 0, 0);
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
line-height: 9.75pt;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-text-content {
|
||||
border: 1px dashed rgb(206, 188, 188);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hiprint-printElement-longText {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
border: 0.75pt none rgb(0, 0, 0);
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
line-height: 9.75pt;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
/*white-space: pre-wrap*/
|
||||
}
|
||||
|
||||
|
||||
.hiprint-printElement-table {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
color: rgb(0, 0, 0);
|
||||
border-color: rgb(0, 0, 0);
|
||||
border-style: none;
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
padding: 0 0 0 0;
|
||||
box-sizing: border-box;
|
||||
line-height: 9.75pt;
|
||||
}
|
||||
|
||||
.hiprint-printElement-table thead {
|
||||
background: #e8e8e8;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
table.hiprint-printElement-tableTarget {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget, .hiprint-printElement-tableTarget tr, .hiprint-printElement-tableTarget td {
|
||||
border-color: rgb(0, 0, 0);
|
||||
/*border-style: none;*/
|
||||
/*border: 1px solid rgb(0, 0, 0);*/
|
||||
font-weight: normal;
|
||||
direction: ltr;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 4pt;
|
||||
padding-right: 4pt;
|
||||
padding-top: 0pt;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
/*line-height: 9.75pt;
|
||||
font-size: 9pt;*/
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget-border-all {
|
||||
border: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-none {
|
||||
border: 0px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-lr {
|
||||
border-left: 1px solid;
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-left {
|
||||
border-left: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-right {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-tb {
|
||||
border-top: 1px solid;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-top {
|
||||
border-top: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-bottom {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget-border-td-none td {
|
||||
border: 0px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:not(:nth-last-child(-n+2)) {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:not(last-child) {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:last-child {
|
||||
border-left: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:last-child:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
/*.hiprint-printElement-tableTarget tr,*/
|
||||
.hiprint-printElement-tableTarget td {
|
||||
height: 18pt;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-paperNumber {
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-table-handle {
|
||||
position: absolute;
|
||||
height: 21pt;
|
||||
width: 21pt;
|
||||
background: red;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-paperNumber-disabled {
|
||||
float: right !important;
|
||||
right: 0 !important;
|
||||
color: gainsboro !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-vline, .hiprint-printElement-hline {
|
||||
border: 0px none rgb(0, 0, 0);
|
||||
|
||||
}
|
||||
|
||||
.hiprint-printElement-vline {
|
||||
border-left: 0.75pt solid #000;
|
||||
border-right: 0px none rgb(0, 0, 0) !important;
|
||||
border-bottom: 0px none rgb(0, 0, 0) !important;
|
||||
border-top: 0px none rgb(0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-hline {
|
||||
border-top: 0.75pt solid #000;
|
||||
border-right: 0px none rgb(0, 0, 0) !important;
|
||||
border-bottom: 0px none rgb(0, 0, 0) !important;
|
||||
border-left: 0px none rgb(0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-oval, .hiprint-printElement-rect {
|
||||
border: 0.75pt solid #000;
|
||||
}
|
||||
|
||||
.hiprint-text-content-middle {
|
||||
}
|
||||
|
||||
.hiprint-text-content-middle > div {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hiprint-text-content-bottom {
|
||||
}
|
||||
|
||||
.hiprint-text-content-bottom > div {
|
||||
display: grid;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap {
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-clip {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/*hi-grid-row */
|
||||
.hi-grid-row {
|
||||
position: relative;
|
||||
height: auto;
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
zoom: 1;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hi-grid-row::after, .hi-grid-row::before {
|
||||
display: table;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hi-grid-col {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
float: left;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.table-grid-row {
|
||||
margin-left: -0pt;
|
||||
margin-right: -0pt;
|
||||
}
|
||||
|
||||
.tableGridColumnsGutterRow {
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
}
|
||||
|
||||
.hiprint-gridColumnsFooter {
|
||||
text-align: left;
|
||||
clear: both;
|
||||
}
|
||||
867
jeecgboot-vue3/src/views/print/template/PrintDesigner.vue
Normal file
867
jeecgboot-vue3/src/views/print/template/PrintDesigner.vue
Normal file
@@ -0,0 +1,867 @@
|
||||
<template>
|
||||
<PageWrapper :title="pageTitle" contentBackground dense contentFullHeight>
|
||||
<template #extra>
|
||||
<a-space>
|
||||
<a-button @click="goBack">返回列表</a-button>
|
||||
<a-button type="primary" v-auth="'print:template:edit'" @click="handleSave" :loading="saving">保存模板</a-button>
|
||||
<a-button v-auth="'print:template:edit'" @click="handlePreview">浏览器预览打印</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-card :bordered="false" class="hiprint-card">
|
||||
<a-alert
|
||||
type="info"
|
||||
show-icon
|
||||
message="从左侧拖拽组件到画布;选中控件后在右侧设置属性。文本中可使用变量占位(与业务传入的 JSON 字段对应)。"
|
||||
class="mb-2"
|
||||
/>
|
||||
<a-row :gutter="8" class="designer-row">
|
||||
<a-col :span="4" class="left-col">
|
||||
<div class="col-title">组件库</div>
|
||||
<a-collapse :bordered="false" defaultActiveKey="basic">
|
||||
<a-collapse-panel key="basic" header="常用组件">
|
||||
<div class="ep-draggable-item" tid="defaultModule.text">文本</div>
|
||||
<div class="ep-draggable-item" tid="defaultModule.longText">长文本</div>
|
||||
<div class="ep-draggable-item" tid="defaultModule.html">富文本(HTML)</div>
|
||||
<div class="ep-draggable-item" tid="defaultModule.image">图片</div>
|
||||
<div class="ep-draggable-item" tid="defaultModule.qrcode">二维码</div>
|
||||
<div class="ep-draggable-item" tid="defaultModule.barcode">条形码</div>
|
||||
<div class="ep-draggable-item" tid="defaultModule.hline">横线</div>
|
||||
<div class="ep-draggable-item" tid="defaultModule.vline">竖线</div>
|
||||
<div class="ep-draggable-item" tid="defaultModule.rect">矩形</div>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel key="detail" header="明细表" forceRender>
|
||||
<div class="ep-draggable-item" tid="qhmesModule.tableSimple">普通明细表(默认列)</div>
|
||||
<div class="help-tip">默认普通表头;字段/绑定在右侧属性里修改。</div>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel key="section" header="报表区块(布局)" forceRender>
|
||||
<div class="section-tip">这些是“更像 HttpPrinter”的常用组件预设(本质仍是 Hiprint 元素)。</div>
|
||||
<div class="ep-draggable-item" tid="qhmesModule.reportTitle">报表标题</div>
|
||||
<div class="ep-draggable-item" tid="qhmesModule.subTitle">副标题</div>
|
||||
<div class="ep-draggable-item" tid="qhmesModule.labelValue">标签:值</div>
|
||||
<div class="ep-draggable-item" tid="qhmesModule.pageNo">页码</div>
|
||||
<div class="ep-draggable-item" tid="qhmesModule.qrcode">二维码(预设)</div>
|
||||
<div class="ep-draggable-item" tid="qhmesModule.barcode">条形码(预设)</div>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</a-col>
|
||||
<a-col :span="13" class="center-col">
|
||||
<div class="col-title">画布</div>
|
||||
<div id="hiprint-printTemplate" class="hiprint-printTemplate"></div>
|
||||
<div class="hiprint-printPagination"></div>
|
||||
</a-col>
|
||||
<a-col :span="7" class="right-col">
|
||||
<div class="col-title">属性</div>
|
||||
<div id="PrintElementOptionSetting"></div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider>预览数据(JSON,供「预览打印」合并变量)</a-divider>
|
||||
<a-textarea v-model:value="printDataJson" :rows="6" placeholder='例如:{"title":"标题","orderNo":"001"}' />
|
||||
<a-divider>普通明细表列配置(用于 qhmesModule.tableSimple)</a-divider>
|
||||
<a-space direction="vertical" style="width: 100%">
|
||||
<a-textarea
|
||||
v-model:value="tableColumnsJson"
|
||||
:rows="6"
|
||||
placeholder='例如:[{"title":"物料","field":"name","width":90},{"title":"数量","field":"qty","width":45}]'
|
||||
/>
|
||||
<a-space>
|
||||
<a-button @click="buildColumnsFromSampleData">从预览数据推导列</a-button>
|
||||
<a-button type="primary" @click="applyTableColumnsConfig">应用到“普通明细表”组件</a-button>
|
||||
</a-space>
|
||||
</a-space>
|
||||
<a-divider>明细分组配置(可视化,多级)</a-divider>
|
||||
<a-space direction="vertical" style="width: 100%">
|
||||
<a-space>
|
||||
<span>启用分组</span>
|
||||
<a-switch v-model:checked="groupEnabled" />
|
||||
</a-space>
|
||||
<a-space>
|
||||
<span>保真预览(样式优先)</span>
|
||||
<a-switch v-model:checked="preserveDesignStyle" />
|
||||
</a-space>
|
||||
<a-select
|
||||
v-model:value="groupFields"
|
||||
mode="multiple"
|
||||
style="width: 100%"
|
||||
:options="tableFieldOptions"
|
||||
placeholder="选择分组字段(按选择顺序分层:一级→二级→三级)"
|
||||
/>
|
||||
<div class="help-tip">
|
||||
规则:按所选字段顺序做层级分组,相同值将隐藏重复内容并居中展示(视觉合并效果),无需写代码。
|
||||
</div>
|
||||
</a-space>
|
||||
</a-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick, onUnmounted, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import $ from 'jquery';
|
||||
import { hiprint, defaultElementTypeProvider, disAutoConnect } from 'vue-plugin-hiprint';
|
||||
import 'vue-plugin-hiprint/dist/print-lock.css';
|
||||
import { queryById, saveJson } from './printTemplate.api';
|
||||
import { createQhmesProvider } from './hiprint/qhmesProvider';
|
||||
|
||||
defineOptions({ name: 'PrintDesigner' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { createMessage } = useMessage();
|
||||
|
||||
const tplName = ref('');
|
||||
const saving = ref(false);
|
||||
const printDataJson = ref(
|
||||
'{\n "title": "演示标题",\n "orderNo": "SO20260101001",\n "table": [\n { "name": "物料A", "qty": 1, "amount": 100 }\n ]\n}'
|
||||
);
|
||||
const tableColumnsJson = ref(
|
||||
'[\n { "title": "物料", "field": "name", "width": 90 },\n { "title": "数量", "field": "qty", "width": 45 },\n { "title": "金额", "field": "amount", "width": 45 }\n]'
|
||||
);
|
||||
const groupEnabled = ref(false);
|
||||
const groupFields = ref<string[]>([]);
|
||||
const preserveDesignStyle = ref(true);
|
||||
|
||||
const pageTitle = computed(() => (tplName.value ? `打印设计 - ${tplName.value}` : '打印设计器'));
|
||||
|
||||
let hiprintTemplate: any = null;
|
||||
let hiprintInited = false;
|
||||
let fieldsTimer: any = null;
|
||||
|
||||
function ensureJqueryGlobal() {
|
||||
(window as any).$ = $;
|
||||
(window as any).jQuery = $;
|
||||
}
|
||||
|
||||
function destroyDesigner() {
|
||||
try {
|
||||
hiprintTemplate = null;
|
||||
$('#hiprint-printTemplate').empty();
|
||||
$('#PrintElementOptionSetting').empty();
|
||||
$('.hiprint-printPagination').empty();
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
function initHiprintRuntime() {
|
||||
if (hiprintInited) {
|
||||
return;
|
||||
}
|
||||
ensureJqueryGlobal();
|
||||
disAutoConnect();
|
||||
hiprint.init({
|
||||
providers: [new defaultElementTypeProvider(), createQhmesProvider()],
|
||||
lang: 'cn',
|
||||
});
|
||||
hiprintInited = true;
|
||||
}
|
||||
|
||||
function parseTemplateJson(str: string | undefined) {
|
||||
if (!str || str === '{}') {
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
} catch {
|
||||
createMessage.warning('模板 JSON 解析失败,已使用空白模板');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function parsePrintData(): Record<string, any> {
|
||||
try {
|
||||
return JSON.parse(printDataJson.value || '{}');
|
||||
} catch {
|
||||
createMessage.error('预览数据不是合法 JSON');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const tableFieldOptions = computed(() => {
|
||||
const data = parsePrintData();
|
||||
const firstRow = Array.isArray(data?.table) && data.table.length > 0 ? data.table[0] : null;
|
||||
if (!firstRow || Object.prototype.toString.call(firstRow) !== '[object Object]') {
|
||||
return [];
|
||||
}
|
||||
return Object.keys(firstRow).map((k) => ({ label: k, value: k }));
|
||||
});
|
||||
|
||||
function buildFieldsFromJson(value: any, prefix = ''): Array<{ field: string; text: string }> {
|
||||
const res: Array<{ field: string; text: string }> = [];
|
||||
if (value == null) {
|
||||
return res;
|
||||
}
|
||||
const isObj = Object.prototype.toString.call(value) === '[object Object]';
|
||||
const isArr = Array.isArray(value);
|
||||
if (!isObj && !isArr) {
|
||||
if (prefix) {
|
||||
res.push({ field: prefix, text: prefix });
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
if (isArr) {
|
||||
// 数组字段:允许绑定数组本身,也允许绑定数组元素的字段(table[0].xx 推导为 table.xx)
|
||||
if (prefix) {
|
||||
res.push({ field: prefix, text: prefix });
|
||||
}
|
||||
const first = value.length > 0 ? value[0] : null;
|
||||
if (first && Object.prototype.toString.call(first) === '[object Object]') {
|
||||
Object.keys(first).forEach((k) => {
|
||||
const f = prefix ? `${prefix}.${k}` : k;
|
||||
res.push({ field: f, text: f });
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Object.keys(value).forEach((k) => {
|
||||
const f = prefix ? `${prefix}.${k}` : k;
|
||||
const v = value[k];
|
||||
// 先把自己加进去(让属性面板可直接选择)
|
||||
res.push({ field: f, text: f });
|
||||
// 再递归对象/数组
|
||||
res.push(...buildFieldsFromJson(v, f));
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
function applyFieldsToTemplate() {
|
||||
if (!hiprintTemplate) {
|
||||
return;
|
||||
}
|
||||
const data = parsePrintData();
|
||||
const fields = buildFieldsFromJson(data);
|
||||
// 去重
|
||||
const uniq = new Map<string, { field: string; text: string }>();
|
||||
fields.forEach((it) => {
|
||||
if (it?.field && !uniq.has(it.field)) {
|
||||
uniq.set(it.field, it);
|
||||
}
|
||||
});
|
||||
try {
|
||||
hiprintTemplate.setFields(Array.from(uniq.values()));
|
||||
} catch (e) {
|
||||
// setFields 非强依赖,失败不影响设计器
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
type SimpleColumn = {
|
||||
title: string;
|
||||
field: string;
|
||||
width?: number;
|
||||
align?: 'left' | 'center' | 'right';
|
||||
};
|
||||
|
||||
function normalizeColumns(cols: any[]): any[] {
|
||||
return cols.map((c) => ({
|
||||
title: c.title || c.field || '列',
|
||||
field: c.field || '',
|
||||
width: Number(c.width || 60),
|
||||
align: c.align || 'left',
|
||||
colspan: 1,
|
||||
rowspan: 1,
|
||||
}));
|
||||
}
|
||||
|
||||
function getTableSimpleFormatter() {
|
||||
// 与 qhmesProvider.ts 保持一致:多级分组按 groupFields 顺序计算 rowspan
|
||||
return `
|
||||
function(t,e,printData){
|
||||
var opts = (t && t.options) ? t.options : {};
|
||||
var list = printData && Array.isArray(printData[opts.field || 'table']) ? printData[opts.field || 'table'] : [];
|
||||
var globalCols = printData && Array.isArray(printData.__qhmesTableColumns) ? printData.__qhmesTableColumns : [];
|
||||
var columns = Array.isArray(opts.columns) && opts.columns.length ? opts.columns : (globalCols.length ? globalCols : [
|
||||
{ title: '物料', field: 'name', width: 90, align: 'left' },
|
||||
{ title: '数量', field: 'qty', width: 45, align: 'right' },
|
||||
{ title: '金额', field: 'amount', width: 45, align: 'right' }
|
||||
]);
|
||||
var globalGroups = printData && Array.isArray(printData.__qhmesGroupFields) ? printData.__qhmesGroupFields : [];
|
||||
var groupFields = Array.isArray(opts.groupFields) && opts.groupFields.length ? opts.groupFields : globalGroups;
|
||||
var style = opts.__qhmesStyle || {};
|
||||
var fontSize = style.fontSize || 10;
|
||||
var borderColor = style.borderColor || '#000';
|
||||
var borderWidth = style.borderWidth || 1;
|
||||
var cellPadding = style.cellPadding || '2pt 4pt';
|
||||
var headerBg = style.headerBg || '';
|
||||
var tableWidth = style.tableWidth || '100%';
|
||||
function esc(v){
|
||||
if (v === null || v === undefined) return '';
|
||||
return String(v).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
function isGroupCol(field){ return groupFields.indexOf(field) > -1; }
|
||||
var rowspanMap = {};
|
||||
for (var c=0;c<columns.length;c++){ var f = columns[c].field; rowspanMap[f] = new Array(list.length).fill(1); }
|
||||
for (var g=0; g<groupFields.length; g++){
|
||||
var gf = groupFields[g];
|
||||
// 分组字段可能不在 columns 中,需先兜底初始化,避免 rowspanMap[gf] 未定义报错
|
||||
if (!rowspanMap[gf]) rowspanMap[gf] = new Array(list.length).fill(1);
|
||||
var i = 0;
|
||||
while(i < list.length){
|
||||
var j = i + 1;
|
||||
while(j < list.length){
|
||||
var upperOk = true;
|
||||
for (var up=0; up<g; up++){
|
||||
var uf = groupFields[up];
|
||||
if ((list[j][uf] ?? '') !== (list[i][uf] ?? '')) { upperOk = false; break; }
|
||||
}
|
||||
if (!upperOk) break;
|
||||
if ((list[j][gf] ?? '') === (list[i][gf] ?? '')) j++; else break;
|
||||
}
|
||||
var span = j - i;
|
||||
if (!rowspanMap[gf]) rowspanMap[gf] = new Array(list.length).fill(1);
|
||||
rowspanMap[gf][i] = span;
|
||||
for (var k=i+1;k<j;k++) rowspanMap[gf][k] = 0;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
var html = '<table style="width:'+tableWidth+';border-collapse:collapse;table-layout:fixed;font-size:'+fontSize+'pt;">';
|
||||
html += '<thead><tr>';
|
||||
for (var h=0;h<columns.length;h++){
|
||||
var hc = columns[h];
|
||||
var hw = hc.width ? ('width:'+hc.width+'pt;') : '';
|
||||
var hbg = headerBg ? ('background:'+headerBg+';') : '';
|
||||
html += '<th style="border:'+borderWidth+'px solid '+borderColor+';padding:'+cellPadding+';text-align:center;'+hbg+hw+'">'+esc(hc.title || hc.field || '')+'</th>';
|
||||
}
|
||||
html += '</tr></thead><tbody>';
|
||||
for (var r=0;r<list.length;r++){
|
||||
html += '<tr>';
|
||||
for (var cc=0;cc<columns.length;cc++){
|
||||
var col = columns[cc];
|
||||
var field = col.field;
|
||||
var align = col.align || 'left';
|
||||
if (isGroupCol(field)){
|
||||
var rs = rowspanMap[field][r];
|
||||
if (rs > 0){
|
||||
html += '<td rowspan="'+rs+'" style="border:'+borderWidth+'px solid '+borderColor+';padding:'+cellPadding+';text-align:center;vertical-align:middle;">'+esc(list[r][field])+'</td>';
|
||||
}
|
||||
} else {
|
||||
html += '<td style="border:'+borderWidth+'px solid '+borderColor+';padding:'+cellPadding+';text-align:'+align+';">'+esc(list[r][field])+'</td>';
|
||||
}
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
return html;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
function parseTemplateObjectFromInstance(): any {
|
||||
if (!hiprintTemplate) return null;
|
||||
const json = hiprintTemplate.getJson();
|
||||
if (typeof json === 'string') {
|
||||
try {
|
||||
return JSON.parse(json);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return json || null;
|
||||
}
|
||||
|
||||
function patchTableSimpleElements(templateObj: any): number {
|
||||
if (!templateObj) return 0;
|
||||
|
||||
let parsedCols: any[] = [];
|
||||
try {
|
||||
parsedCols = JSON.parse(tableColumnsJson.value || '[]');
|
||||
} catch {
|
||||
parsedCols = [];
|
||||
}
|
||||
const mergedCols = normalizeColumns(parsedCols).map((c) => ({
|
||||
title: c.title,
|
||||
field: c.field,
|
||||
width: c.width,
|
||||
align: c.align,
|
||||
}));
|
||||
const mergedGroups = groupEnabled.value ? [...groupFields.value] : [];
|
||||
let changedCount = 0;
|
||||
let candidateCount = 0;
|
||||
|
||||
const visited = new Set<any>();
|
||||
const walk = (node: any) => {
|
||||
if (!node || typeof node !== 'object' || visited.has(node)) return;
|
||||
visited.add(node);
|
||||
|
||||
const hasOptionsObj = node.options && typeof node.options === 'object';
|
||||
// 安全策略:只处理系统托管组件,避免覆盖用户已有明细组件
|
||||
const isManagedTableElement =
|
||||
node?.tid === 'qhmesModule.tableSimple' || (hasOptionsObj && node.options.__qhmesManaged === true);
|
||||
|
||||
if (isManagedTableElement) {
|
||||
candidateCount++;
|
||||
node.type = 'html';
|
||||
node.tid = 'qhmesModule.tableSimple';
|
||||
node.options = node.options || {};
|
||||
node.options.__qhmesManaged = true;
|
||||
node.options.field = node.options.field || 'table';
|
||||
node.options.columns = mergedCols;
|
||||
node.options.groupFields = mergedGroups;
|
||||
node.options.formatter = getTableSimpleFormatter();
|
||||
changedCount++;
|
||||
}
|
||||
|
||||
// 递归所有子属性(兼容 printPanels/panels/printElements 等不同结构)
|
||||
Object.keys(node).forEach((k) => {
|
||||
const v = node[k];
|
||||
if (Array.isArray(v)) {
|
||||
v.forEach((item) => walk(item));
|
||||
} else if (v && typeof v === 'object') {
|
||||
walk(v);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
walk(templateObj);
|
||||
(templateObj as any).__qhmesPatchStat = { changedCount, candidateCount };
|
||||
return changedCount;
|
||||
}
|
||||
|
||||
function syncExistingTableSimpleElements(showTip = false) {
|
||||
if (!hiprintTemplate) return;
|
||||
const templateObj = parseTemplateObjectFromInstance();
|
||||
if (!templateObj) return;
|
||||
const changedCount = patchTableSimpleElements(templateObj);
|
||||
const stat = (templateObj as any).__qhmesPatchStat || { changedCount, candidateCount: 0 };
|
||||
if (changedCount > 0) {
|
||||
try {
|
||||
hiprintTemplate.update(templateObj);
|
||||
if (showTip) {
|
||||
createMessage.success(`已同步 ${changedCount} 个明细组件分组配置(识别候选 ${stat.candidateCount})`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
} else if (showTip) {
|
||||
createMessage.warning('未识别到系统托管的分组明细组件,请先拖入“普通明细表(默认列)”后再应用');
|
||||
}
|
||||
}
|
||||
|
||||
function buildPreviewTemplateWithGrouping() {
|
||||
const templateObj = parseTemplateObjectFromInstance();
|
||||
if (!templateObj) return null;
|
||||
// 仅用于预览的临时模板,避免污染设计器当前画布
|
||||
const previewTemplate = JSON.parse(JSON.stringify(templateObj));
|
||||
|
||||
let parsedCols: any[] = [];
|
||||
try {
|
||||
parsedCols = JSON.parse(tableColumnsJson.value || '[]');
|
||||
} catch {
|
||||
parsedCols = [];
|
||||
}
|
||||
const mergedCols = normalizeColumns(parsedCols).map((c) => ({
|
||||
title: c.title,
|
||||
field: c.field,
|
||||
width: c.width,
|
||||
align: c.align,
|
||||
}));
|
||||
const mergedGroups = groupEnabled.value ? [...groupFields.value] : [];
|
||||
|
||||
const extractColumnsFromElement = (el: any) => {
|
||||
// 1) 新结构:options.columns
|
||||
if (Array.isArray(el?.options?.columns) && el.options.columns.length) {
|
||||
return el.options.columns.map((c: any) => ({
|
||||
title: c.title || c.field || '列',
|
||||
field: c.field || '',
|
||||
width: Number(c.width || 60),
|
||||
align: c.align || 'left',
|
||||
}));
|
||||
}
|
||||
// 2) 旧 table 结构:element.columns(二维表头)
|
||||
if (Array.isArray(el?.columns) && el.columns.length) {
|
||||
const headerRow = Array.isArray(el.columns[0]) ? el.columns[0] : [];
|
||||
if (headerRow.length) {
|
||||
return headerRow.map((c: any) => ({
|
||||
title: c.title || c.field || '列',
|
||||
field: c.field || '',
|
||||
width: Number(c.width || 60),
|
||||
align: c.align || 'left',
|
||||
}));
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
const visited = new Set<any>();
|
||||
const walk = (node: any) => {
|
||||
if (!node || typeof node !== 'object' || visited.has(node)) return;
|
||||
visited.add(node);
|
||||
|
||||
// 预览阶段宽松匹配:尽可能覆盖用户已有明细表组件
|
||||
const hasOptionsObj = node.options && typeof node.options === 'object';
|
||||
const maybeTableElement =
|
||||
node?.tid === 'qhmesModule.tableSimple' ||
|
||||
node?.tid === 'defaultModule.table' ||
|
||||
node?.type === 'table' ||
|
||||
(hasOptionsObj && Array.isArray(node.options.columns) && (node.options.field === 'table' || !node.options.field));
|
||||
|
||||
if (maybeTableElement) {
|
||||
const originOptions = node.options || {};
|
||||
const originColumns = extractColumnsFromElement(node);
|
||||
node.type = 'html';
|
||||
node.tid = 'qhmesModule.tableSimple';
|
||||
node.options = node.options || {};
|
||||
node.options.__qhmesManaged = true;
|
||||
node.options.field = node.options.field || 'table';
|
||||
// 优先保留用户已有列定义(包括旧 table 的 element.columns),其次才用可视化配置列
|
||||
if (originColumns.length > 0) {
|
||||
node.options.columns = originColumns;
|
||||
} else if (!Array.isArray(node.options.columns) || node.options.columns.length === 0) {
|
||||
node.options.columns = mergedCols;
|
||||
}
|
||||
node.options.groupFields = mergedGroups;
|
||||
node.options.__qhmesStyle = {
|
||||
fontSize: originOptions.fontSize,
|
||||
borderColor: originOptions.borderColor,
|
||||
borderWidth: originOptions.borderWidth,
|
||||
cellPadding: originOptions.cellPadding,
|
||||
headerBg: originOptions.headerBg,
|
||||
tableWidth: originOptions.tableWidth,
|
||||
};
|
||||
node.options.formatter = getTableSimpleFormatter();
|
||||
}
|
||||
|
||||
Object.keys(node).forEach((k) => {
|
||||
const v = node[k];
|
||||
if (Array.isArray(v)) v.forEach((it) => walk(it));
|
||||
else if (v && typeof v === 'object') walk(v);
|
||||
});
|
||||
};
|
||||
|
||||
walk(previewTemplate);
|
||||
return previewTemplate;
|
||||
}
|
||||
|
||||
function applyTableColumnsConfig(silent = false) {
|
||||
let cols: SimpleColumn[] = [];
|
||||
try {
|
||||
const parsed = JSON.parse(tableColumnsJson.value || '[]');
|
||||
if (!Array.isArray(parsed) || parsed.length === 0) {
|
||||
createMessage.warning('列配置必须是非空数组');
|
||||
return;
|
||||
}
|
||||
cols = parsed;
|
||||
} catch {
|
||||
createMessage.error('明细列配置 JSON 格式错误');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 动态更新 provider 元素定义:后续拖入的“普通明细表”会使用新列配置
|
||||
hiprint.updateElementType('qhmesModule.tableSimple', (type: any) => {
|
||||
const mergedCols = normalizeColumns(cols).map((col) => {
|
||||
if (groupEnabled.value && groupFields.value.includes(col.field)) {
|
||||
return { ...col, align: 'center' };
|
||||
}
|
||||
return col;
|
||||
});
|
||||
type.options = type.options || {};
|
||||
type.options.columns = mergedCols.map((c) => ({
|
||||
title: c.title,
|
||||
field: c.field,
|
||||
width: c.width,
|
||||
align: c.align,
|
||||
}));
|
||||
type.options.groupFields = groupEnabled.value ? [...groupFields.value] : [];
|
||||
return type;
|
||||
});
|
||||
// 同步到当前画布上已存在的“普通明细表”组件,避免只影响新拖拽组件
|
||||
syncExistingTableSimpleElements(!silent);
|
||||
if (!silent) {
|
||||
createMessage.success('已更新普通明细表列与分组配置');
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
createMessage.error('更新组件列配置失败');
|
||||
}
|
||||
}
|
||||
|
||||
function buildColumnsFromSampleData() {
|
||||
const data = parsePrintData();
|
||||
const firstRow = Array.isArray(data?.table) && data.table.length > 0 ? data.table[0] : null;
|
||||
if (!firstRow || Object.prototype.toString.call(firstRow) !== '[object Object]') {
|
||||
createMessage.warning('预览数据中未找到 table[0] 对象,无法推导');
|
||||
return;
|
||||
}
|
||||
const cols = Object.keys(firstRow).map((k) => ({
|
||||
title: k,
|
||||
field: k,
|
||||
width: 60,
|
||||
align: typeof firstRow[k] === 'number' ? 'right' : 'left',
|
||||
}));
|
||||
tableColumnsJson.value = JSON.stringify(cols, null, 2);
|
||||
createMessage.success('已根据 table[0] 推导列配置');
|
||||
}
|
||||
|
||||
function buildGroupedRowsVisualMerge(rows: any[], groups: string[]) {
|
||||
if (!Array.isArray(rows) || rows.length === 0 || !Array.isArray(groups) || groups.length === 0) {
|
||||
return rows;
|
||||
}
|
||||
const out = rows.map((r) => ({ ...r }));
|
||||
for (let i = 1; i < out.length; i++) {
|
||||
for (let level = 0; level < groups.length; level++) {
|
||||
const field = groups[level];
|
||||
// 上层一致才比较当前层
|
||||
let upperSame = true;
|
||||
for (let up = 0; up < level; up++) {
|
||||
const upField = groups[up];
|
||||
if ((out[i][upField] ?? '') !== (out[i - 1][upField] ?? '')) {
|
||||
upperSame = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!upperSame) break;
|
||||
if ((out[i][field] ?? '') === (out[i - 1][field] ?? '')) {
|
||||
// 保真模式下只清空重复值,保持原组件样式不变
|
||||
out[i][field] = '';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function parseTemplatePayload(str: string | undefined) {
|
||||
if (!str || str === '{}') {
|
||||
return { template: {}, ext: null as any };
|
||||
}
|
||||
try {
|
||||
const obj = JSON.parse(str);
|
||||
// 兼容历史格式:直接存 template json
|
||||
if (obj?.printPanels || obj?.panels) {
|
||||
return { template: obj, ext: null as any };
|
||||
}
|
||||
// 新格式:{ template, ext }
|
||||
if (obj?.template && (obj.template.printPanels || obj.template.panels || Object.keys(obj.template).length >= 0)) {
|
||||
return { template: obj.template, ext: obj.ext || null };
|
||||
}
|
||||
return { template: obj, ext: null as any };
|
||||
} catch {
|
||||
createMessage.warning('模板 JSON 解析失败,已使用空白模板');
|
||||
return { template: {}, ext: null as any };
|
||||
}
|
||||
}
|
||||
|
||||
async function bootDesigner() {
|
||||
const id = route.query.id as string;
|
||||
if (!id) {
|
||||
createMessage.error('缺少模板 id');
|
||||
goBack();
|
||||
return;
|
||||
}
|
||||
const record = await queryById(id);
|
||||
if (!record?.id) {
|
||||
createMessage.error('模板不存在');
|
||||
goBack();
|
||||
return;
|
||||
}
|
||||
tplName.value = record.templateName || record.templateCode || '';
|
||||
|
||||
initHiprintRuntime();
|
||||
destroyDesigner();
|
||||
await nextTick();
|
||||
|
||||
hiprint.PrintElementTypeManager.buildByHtml($('.ep-draggable-item'));
|
||||
// 兼容 a-collapse-panel 延迟渲染:初始化后再补一次,确保所有拖拽项都绑定到拖拽事件上
|
||||
setTimeout(() => {
|
||||
hiprint.PrintElementTypeManager.buildByHtml($('.ep-draggable-item'));
|
||||
}, 300);
|
||||
|
||||
const payload = parseTemplatePayload(record.templateJson);
|
||||
const template = payload.template;
|
||||
if (payload.ext) {
|
||||
if (typeof payload.ext.printDataJson === 'string' && payload.ext.printDataJson.trim()) {
|
||||
printDataJson.value = payload.ext.printDataJson;
|
||||
}
|
||||
if (typeof payload.ext.tableColumnsJson === 'string') {
|
||||
tableColumnsJson.value = payload.ext.tableColumnsJson;
|
||||
}
|
||||
groupEnabled.value = !!payload.ext.groupEnabled;
|
||||
if (Array.isArray(payload.ext.groupFields)) {
|
||||
groupFields.value = payload.ext.groupFields;
|
||||
}
|
||||
}
|
||||
hiprintTemplate = new hiprint.PrintTemplate({
|
||||
template,
|
||||
settingContainer: '#PrintElementOptionSetting',
|
||||
paginationContainer: '.hiprint-printPagination',
|
||||
history: true,
|
||||
});
|
||||
hiprintTemplate.design('#hiprint-printTemplate');
|
||||
applyFieldsToTemplate();
|
||||
applyTableColumnsConfig(true);
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
router.push('/print/template');
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
if (!hiprintTemplate || !route.query.id) {
|
||||
return;
|
||||
}
|
||||
const json = hiprintTemplate.getJson();
|
||||
let templateObj: any = {};
|
||||
if (typeof json === 'string') {
|
||||
try {
|
||||
templateObj = JSON.parse(json);
|
||||
} catch {
|
||||
templateObj = {};
|
||||
}
|
||||
} else {
|
||||
templateObj = json;
|
||||
}
|
||||
const payload = {
|
||||
template: templateObj,
|
||||
ext: {
|
||||
printDataJson: printDataJson.value,
|
||||
tableColumnsJson: tableColumnsJson.value,
|
||||
groupEnabled: groupEnabled.value,
|
||||
groupFields: groupFields.value,
|
||||
},
|
||||
};
|
||||
const templateJson = JSON.stringify(payload);
|
||||
saving.value = true;
|
||||
try {
|
||||
await saveJson({ id: route.query.id as string, templateJson });
|
||||
createMessage.success('模板已保存');
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handlePreview() {
|
||||
if (!hiprintTemplate) {
|
||||
return;
|
||||
}
|
||||
const data = parsePrintData();
|
||||
if (preserveDesignStyle.value) {
|
||||
// 样式优先:不改模板结构,只改分组字段的显示数据
|
||||
if (groupEnabled.value && Array.isArray(data.table) && groupFields.value.length > 0) {
|
||||
data.table = buildGroupedRowsVisualMerge(data.table, groupFields.value);
|
||||
}
|
||||
hiprintTemplate.print(data, {}, { callback: () => {} });
|
||||
return;
|
||||
}
|
||||
// 兜底:即使元素 options 未同步,预览时也从全局参数读取列和分组配置
|
||||
let parsedCols: any[] = [];
|
||||
try {
|
||||
parsedCols = JSON.parse(tableColumnsJson.value || '[]');
|
||||
} catch {
|
||||
parsedCols = [];
|
||||
}
|
||||
data.__qhmesTableColumns = normalizeColumns(parsedCols).map((c) => ({
|
||||
title: c.title,
|
||||
field: c.field,
|
||||
width: c.width,
|
||||
align: c.align,
|
||||
}));
|
||||
data.__qhmesGroupFields = groupEnabled.value ? [...groupFields.value] : [];
|
||||
const previewTemplate = buildPreviewTemplateWithGrouping();
|
||||
if (previewTemplate) {
|
||||
const previewPrintTpl = new (hiprint as any).PrintTemplate({ template: previewTemplate });
|
||||
previewPrintTpl.print(data, {}, { callback: () => {} });
|
||||
return;
|
||||
}
|
||||
hiprintTemplate.print(data, {}, { callback: () => {} });
|
||||
}
|
||||
|
||||
watch(
|
||||
() => printDataJson.value,
|
||||
() => {
|
||||
// 输入过程中做一个简单防抖
|
||||
if (fieldsTimer) {
|
||||
clearTimeout(fieldsTimer);
|
||||
}
|
||||
fieldsTimer = setTimeout(() => {
|
||||
applyFieldsToTemplate();
|
||||
}, 400);
|
||||
}
|
||||
);
|
||||
|
||||
// 分组配置不再自动覆盖画布组件,避免误改用户自定义明细
|
||||
|
||||
// 首次进入与 query.id 变化时加载(避免 onMounted + watch 重复初始化)
|
||||
watch(
|
||||
() => route.query.id as string,
|
||||
(id) => {
|
||||
if (id) {
|
||||
bootDesigner();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
if (fieldsTimer) {
|
||||
clearTimeout(fieldsTimer);
|
||||
fieldsTimer = null;
|
||||
}
|
||||
destroyDesigner();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.hiprint-card {
|
||||
min-height: calc(100vh - 120px);
|
||||
}
|
||||
|
||||
.designer-row {
|
||||
min-height: 520px;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.left-col .ep-draggable-item {
|
||||
padding: 8px 10px;
|
||||
margin-bottom: 6px;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
cursor: move;
|
||||
background: #fafafa;
|
||||
font-size: 12px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.help-tip,
|
||||
.section-tip {
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
margin: 6px 0 0;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.center-col {
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
background: #fff;
|
||||
min-height: 520px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.right-col {
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
background: #fff;
|
||||
min-height: 520px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#hiprint-printTemplate {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.mb-2 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="register" :title="title" width="640px" @ok="handleSubmit" destroyOnClose>
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form';
|
||||
import { formSchema } from '../printTemplate.data';
|
||||
import { add, edit } from '../printTemplate.api';
|
||||
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
|
||||
const isUpdate = ref(false);
|
||||
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增打印模板' : '编辑打印模板'));
|
||||
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 110,
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
baseColProps: { span: 24 },
|
||||
});
|
||||
|
||||
const [register, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate) && data?.record) {
|
||||
setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
if (!unref(isUpdate)) {
|
||||
delete values.id;
|
||||
if (!values.templateJson) {
|
||||
values.templateJson = '{}';
|
||||
}
|
||||
}
|
||||
setModalProps({ confirmLoading: true });
|
||||
if (unref(isUpdate)) {
|
||||
await edit(values);
|
||||
} else {
|
||||
await add(values);
|
||||
}
|
||||
closeModal();
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
187
jeecgboot-vue3/src/views/print/template/hiprint/qhmesProvider.ts
Normal file
187
jeecgboot-vue3/src/views/print/template/hiprint/qhmesProvider.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import { hiprint } from 'vue-plugin-hiprint';
|
||||
|
||||
/**
|
||||
* QH-MES 自定义 provider(参考 vue-plugin-hiprint 动态 provider 机制)
|
||||
* - 新增一组“报表/套打”常用组件
|
||||
* - 提供一个默认的“普通明细表”(单行表头)
|
||||
*
|
||||
* 注意:此 provider 不替换 defaultElementTypeProvider,只做补充。
|
||||
*/
|
||||
export function createQhmesProvider() {
|
||||
const key = 'qhmesModule';
|
||||
|
||||
const addElementTypes = function (context: any) {
|
||||
// 避免重复注册
|
||||
context.removePrintElementTypes(key);
|
||||
|
||||
const commonText = (tid: string, title: string, extraOptions: Record<string, any> = {}) => {
|
||||
return {
|
||||
tid,
|
||||
title,
|
||||
type: 'text',
|
||||
options: {
|
||||
title,
|
||||
field: '',
|
||||
testData: title,
|
||||
...extraOptions,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const elements: any[] = [
|
||||
commonText(`${key}.reportTitle`, '报表标题', { fontSize: 18, fontWeight: 'bold', textAlign: 'center' }),
|
||||
commonText(`${key}.subTitle`, '副标题', { fontSize: 12, textAlign: 'center' }),
|
||||
commonText(`${key}.labelValue`, '标签:值', { fontSize: 10 }),
|
||||
commonText(`${key}.pageNo`, '页码', { field: 'pageNumber', testData: '1/1' }),
|
||||
|
||||
// 二维码/条码(用 text + textType)
|
||||
{
|
||||
tid: `${key}.qrcode`,
|
||||
title: '二维码',
|
||||
type: 'text',
|
||||
options: {
|
||||
title: '二维码',
|
||||
field: 'qrcode',
|
||||
testData: 'QRCODE_DEMO',
|
||||
textType: 'qrcode',
|
||||
width: 35,
|
||||
height: 35,
|
||||
},
|
||||
},
|
||||
{
|
||||
tid: `${key}.barcode`,
|
||||
title: '条形码',
|
||||
type: 'text',
|
||||
options: {
|
||||
title: '条形码',
|
||||
field: 'barcode',
|
||||
testData: '1234567890',
|
||||
textType: 'barcode',
|
||||
width: 80,
|
||||
height: 25,
|
||||
},
|
||||
},
|
||||
|
||||
// 普通明细表(单行表头,支持多级分组合并)
|
||||
{
|
||||
tid: `${key}.tableSimple`,
|
||||
title: '普通明细表',
|
||||
type: 'html',
|
||||
options: {
|
||||
title: '普通明细表',
|
||||
field: 'table',
|
||||
testData: '',
|
||||
width: 180,
|
||||
height: 60,
|
||||
__qhmesManaged: true,
|
||||
columns: [
|
||||
{ title: '物料', field: 'name', width: 90, align: 'left' },
|
||||
{ title: '数量', field: 'qty', width: 45, align: 'right' },
|
||||
{ title: '金额', field: 'amount', width: 45, align: 'right' },
|
||||
],
|
||||
groupFields: [],
|
||||
formatter: `
|
||||
function(t,e,printData){
|
||||
var opts = (t && t.options) ? t.options : {};
|
||||
var list = printData && Array.isArray(printData[opts.field || 'table']) ? printData[opts.field || 'table'] : [];
|
||||
var globalCols = printData && Array.isArray(printData.__qhmesTableColumns) ? printData.__qhmesTableColumns : [];
|
||||
var columns = Array.isArray(opts.columns) && opts.columns.length ? opts.columns : (globalCols.length ? globalCols : [
|
||||
{ title: '物料', field: 'name', width: 90, align: 'left' },
|
||||
{ title: '数量', field: 'qty', width: 45, align: 'right' },
|
||||
{ title: '金额', field: 'amount', width: 45, align: 'right' }
|
||||
]);
|
||||
var globalGroups = printData && Array.isArray(printData.__qhmesGroupFields) ? printData.__qhmesGroupFields : [];
|
||||
var groupFields = Array.isArray(opts.groupFields) && opts.groupFields.length ? opts.groupFields : globalGroups;
|
||||
var style = opts.__qhmesStyle || {};
|
||||
var fontSize = style.fontSize || 10;
|
||||
var borderColor = style.borderColor || '#000';
|
||||
var borderWidth = style.borderWidth || 1;
|
||||
var cellPadding = style.cellPadding || '2pt 4pt';
|
||||
var headerBg = style.headerBg || '';
|
||||
var tableWidth = style.tableWidth || '100%';
|
||||
|
||||
function esc(v){
|
||||
if (v === null || v === undefined) return '';
|
||||
return String(v).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
function isGroupCol(field){
|
||||
return groupFields.indexOf(field) > -1;
|
||||
}
|
||||
|
||||
// 计算每个分组列在每行的 rowspan(多级:上层一致前提下再判断下层)
|
||||
var rowspanMap = {};
|
||||
for (var c=0;c<columns.length;c++){
|
||||
var f = columns[c].field;
|
||||
rowspanMap[f] = new Array(list.length).fill(1);
|
||||
}
|
||||
for (var g=0; g<groupFields.length; g++){
|
||||
var gf = groupFields[g];
|
||||
// 分组字段可能不在 columns 中,需先兜底初始化,避免 rowspanMap[gf] 未定义报错
|
||||
if (!rowspanMap[gf]) rowspanMap[gf] = new Array(list.length).fill(1);
|
||||
var i = 0;
|
||||
while(i < list.length){
|
||||
var j = i + 1;
|
||||
while(j < list.length){
|
||||
var upperOk = true;
|
||||
for (var up=0; up<g; up++){
|
||||
var uf = groupFields[up];
|
||||
if ((list[j][uf] ?? '') !== (list[i][uf] ?? '')) { upperOk = false; break; }
|
||||
}
|
||||
if (!upperOk) break;
|
||||
if ((list[j][gf] ?? '') === (list[i][gf] ?? '')) j++;
|
||||
else break;
|
||||
}
|
||||
var span = j - i;
|
||||
if (!rowspanMap[gf]) rowspanMap[gf] = new Array(list.length).fill(1);
|
||||
rowspanMap[gf][i] = span;
|
||||
for (var k=i+1;k<j;k++) rowspanMap[gf][k] = 0;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
var html = '<table style="width:'+tableWidth+';border-collapse:collapse;table-layout:fixed;font-size:'+fontSize+'pt;">';
|
||||
html += '<thead><tr>';
|
||||
for (var h=0;h<columns.length;h++){
|
||||
var hc = columns[h];
|
||||
var hw = hc.width ? ('width:'+hc.width+'pt;') : '';
|
||||
var hbg = headerBg ? ('background:'+headerBg+';') : '';
|
||||
html += '<th style="border:'+borderWidth+'px solid '+borderColor+';padding:'+cellPadding+';text-align:center;'+hbg+hw+'">'+esc(hc.title || hc.field || '')+'</th>';
|
||||
}
|
||||
html += '</tr></thead><tbody>';
|
||||
|
||||
for (var r=0;r<list.length;r++){
|
||||
html += '<tr>';
|
||||
for (var cc=0;cc<columns.length;cc++){
|
||||
var col = columns[cc];
|
||||
var field = col.field;
|
||||
var align = col.align || 'left';
|
||||
if (isGroupCol(field)){
|
||||
var rs = rowspanMap[field][r];
|
||||
if (rs > 0){
|
||||
html += '<td rowspan="'+rs+'" style="border:'+borderWidth+'px solid '+borderColor+';padding:'+cellPadding+';text-align:center;vertical-align:middle;">'+esc(list[r][field])+'</td>';
|
||||
}
|
||||
}else{
|
||||
html += '<td style="border:'+borderWidth+'px solid '+borderColor+';padding:'+cellPadding+';text-align:'+align+';">'+esc(list[r][field])+'</td>';
|
||||
}
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
return html;
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// 分组(左侧面板展示更友好)
|
||||
const groups = [
|
||||
new (hiprint as any).PrintElementTypeGroup('HttpPrinter风格组件', elements),
|
||||
];
|
||||
|
||||
context.addPrintElementTypes(key, groups);
|
||||
};
|
||||
|
||||
return { addElementTypes };
|
||||
}
|
||||
|
||||
96
jeecgboot-vue3/src/views/print/template/index.vue
Normal file
96
jeecgboot-vue3/src/views/print/template/index.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate" v-auth="'print:template:add'"> 新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete" v-auth="'print:template:delete'">
|
||||
<Icon icon="ant-design:delete-outlined" />
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button>
|
||||
批量操作
|
||||
<Icon icon="mdi:chevron-down" />
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<PrintTemplateModal @register="registerModal" @success="handleSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="PrintTemplateList" setup>
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { columns, searchFormSchema } from './printTemplate.data';
|
||||
import { list, deleteOne, batchDelete } from './printTemplate.api';
|
||||
import PrintTemplateModal from './components/PrintTemplateModal.vue';
|
||||
|
||||
defineOptions({ name: 'PrintTemplateList' });
|
||||
|
||||
const router = useRouter();
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
|
||||
const { tableContext } = useListPage({
|
||||
tableProps: {
|
||||
title: '打印模板',
|
||||
api: list,
|
||||
columns,
|
||||
rowKey: 'id',
|
||||
formConfig: { schemas: searchFormSchema },
|
||||
actionColumn: { width: 220 },
|
||||
},
|
||||
});
|
||||
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
function handleCreate() {
|
||||
openModal(true, { isUpdate: false });
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
openModal(true, { isUpdate: true, record });
|
||||
}
|
||||
|
||||
function handleDesign(record: Recordable) {
|
||||
router.push({ path: '/print/designer', query: { id: record.id } });
|
||||
}
|
||||
|
||||
async function handleDelete(record: Recordable) {
|
||||
await deleteOne({ id: record.id }, reload);
|
||||
}
|
||||
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value.join(',') }, reload);
|
||||
}
|
||||
|
||||
function handleSuccess() {
|
||||
reload();
|
||||
}
|
||||
|
||||
function getTableAction(record: Recordable) {
|
||||
return [
|
||||
{ label: '设计', onClick: handleDesign.bind(null, record), auth: 'print:template:edit' },
|
||||
{ label: '编辑', onClick: handleEdit.bind(null, record), auth: 'print:template:edit' },
|
||||
{
|
||||
label: '删除',
|
||||
color: 'error',
|
||||
popConfirm: {
|
||||
title: '确认删除?',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
auth: 'print:template:delete',
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
34
jeecgboot-vue3/src/views/print/template/printTemplate.api.ts
Normal file
34
jeecgboot-vue3/src/views/print/template/printTemplate.api.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
list = '/print/template/list',
|
||||
add = '/print/template/add',
|
||||
edit = '/print/template/edit',
|
||||
deleteOne = '/print/template/delete',
|
||||
deleteBatch = '/print/template/deleteBatch',
|
||||
queryById = '/print/template/queryById',
|
||||
saveJson = '/print/template/saveJson',
|
||||
}
|
||||
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
export const add = (params) => defHttp.post({ url: Api.add, params });
|
||||
|
||||
export const edit = (params) => defHttp.put({ url: Api.edit, params });
|
||||
|
||||
export const deleteOne = (params, handleSuccess?) => {
|
||||
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess?.();
|
||||
});
|
||||
};
|
||||
|
||||
export const batchDelete = (params, handleSuccess?) => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess?.();
|
||||
});
|
||||
};
|
||||
|
||||
export const queryById = (id: string) => defHttp.get({ url: Api.queryById, params: { id } });
|
||||
|
||||
export const saveJson = (data: { id: string; templateJson: string }) =>
|
||||
defHttp.post({ url: Api.saveJson, data }, { successMessageMode: 'message' });
|
||||
110
jeecgboot-vue3/src/views/print/template/printTemplate.data.ts
Normal file
110
jeecgboot-vue3/src/views/print/template/printTemplate.data.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{ title: '模板编码', dataIndex: 'templateCode', width: 140 },
|
||||
{ title: '模板名称', dataIndex: 'templateName', width: 180 },
|
||||
{
|
||||
title: '分类',
|
||||
dataIndex: 'category',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
const m = { barcode: '条码', form: '表单套打', report: '报表' };
|
||||
return m[text] || text;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '纸张(mm)',
|
||||
dataIndex: 'paperWidthMm',
|
||||
width: 130,
|
||||
customRender: ({ record }) =>
|
||||
record?.paperWidthMm != null && record?.paperHeightMm != null
|
||||
? `${record.paperWidthMm}×${record.paperHeightMm}`
|
||||
: '-',
|
||||
},
|
||||
{ title: '备注', dataIndex: 'remark', ellipsis: true },
|
||||
{ title: '创建时间', dataIndex: 'createTime', width: 165 },
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{ label: '模板编码', field: 'templateCode', component: 'Input', colProps: { span: 6 } },
|
||||
{ label: '模板名称', field: 'templateName', component: 'Input', colProps: { span: 6 } },
|
||||
{
|
||||
label: '分类',
|
||||
field: 'category',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '条码', value: 'barcode' },
|
||||
{ label: '表单套打', value: 'form' },
|
||||
{ label: '报表', value: 'report' },
|
||||
],
|
||||
allowClear: true,
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
label: '模板编码',
|
||||
field: 'templateCode',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
componentProps: { maxlength: 64 },
|
||||
dynamicDisabled: ({ values }) => !!values?.id,
|
||||
},
|
||||
{
|
||||
label: '模板名称',
|
||||
field: 'templateName',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '分类',
|
||||
field: 'category',
|
||||
component: 'Select',
|
||||
defaultValue: 'form',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '条码', value: 'barcode' },
|
||||
{ label: '表单套打', value: 'form' },
|
||||
{ label: '报表', value: 'report' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '纸宽(mm)',
|
||||
field: 'paperWidthMm',
|
||||
component: 'InputNumber',
|
||||
defaultValue: 210,
|
||||
componentProps: { min: 10, max: 2000, style: { width: '100%' } },
|
||||
},
|
||||
{
|
||||
label: '纸高(mm)',
|
||||
field: 'paperHeightMm',
|
||||
component: 'InputNumber',
|
||||
defaultValue: 297,
|
||||
componentProps: { min: 10, max: 2000, style: { width: '100%' } },
|
||||
},
|
||||
{
|
||||
label: '方向',
|
||||
field: 'paperOrientation',
|
||||
component: 'Select',
|
||||
defaultValue: 'portrait',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '纵向', value: 'portrait' },
|
||||
{ label: '横向', value: 'landscape' },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
field: 'remark',
|
||||
component: 'InputTextArea',
|
||||
componentProps: { rows: 2 },
|
||||
},
|
||||
{ label: '', field: 'id', component: 'Input', show: false },
|
||||
{ label: '', field: 'templateJson', component: 'Input', show: false, defaultValue: '{}' },
|
||||
];
|
||||
@@ -145,8 +145,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||
'@jeecg/online',
|
||||
'@jeecg/aiflow',
|
||||
],
|
||||
// 强制预构建clipboard,解决Vite6对CommonJS模块的严格检查
|
||||
include: ['clipboard']
|
||||
// 强制预构建 clipboard / jquery / hiprint,减少开发态与打包解析问题
|
||||
include: ['clipboard', 'jquery', 'vue-plugin-hiprint']
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user