1. 变量占位符:{中文变量}
2. 变量占位符预设类型,可以是:输入框、下拉、富文本(允许插入表格作为合同正本的附件内容)
This commit is contained in:
@@ -10,6 +10,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons-vue": "^7.0.1",
|
"@ant-design/icons-vue": "^7.0.1",
|
||||||
|
"@wangeditor/editor": "^5.1.23",
|
||||||
|
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||||
|
"@xmldom/xmldom": "^0.8.10",
|
||||||
"ant-design-vue": "^4.2.6",
|
"ant-design-vue": "^4.2.6",
|
||||||
"axios": "^1.16.0",
|
"axios": "^1.16.0",
|
||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
|
|||||||
Generated
+488
@@ -11,6 +11,15 @@ importers:
|
|||||||
'@ant-design/icons-vue':
|
'@ant-design/icons-vue':
|
||||||
specifier: ^7.0.1
|
specifier: ^7.0.1
|
||||||
version: 7.0.1(vue@3.5.34)
|
version: 7.0.1(vue@3.5.34)
|
||||||
|
'@wangeditor/editor':
|
||||||
|
specifier: ^5.1.23
|
||||||
|
version: 5.1.23
|
||||||
|
'@wangeditor/editor-for-vue':
|
||||||
|
specifier: ^5.1.12
|
||||||
|
version: 5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.34)
|
||||||
|
'@xmldom/xmldom':
|
||||||
|
specifier: ^0.8.10
|
||||||
|
version: 0.8.13
|
||||||
ant-design-vue:
|
ant-design-vue:
|
||||||
specifier: ^4.2.6
|
specifier: ^4.2.6
|
||||||
version: 4.2.6(vue@3.5.34)
|
version: 4.2.6(vue@3.5.34)
|
||||||
@@ -402,12 +411,35 @@ packages:
|
|||||||
'@simonwep/pickr@1.8.2':
|
'@simonwep/pickr@1.8.2':
|
||||||
resolution: {integrity: sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==}
|
resolution: {integrity: sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==}
|
||||||
|
|
||||||
|
'@transloadit/prettier-bytes@0.0.7':
|
||||||
|
resolution: {integrity: sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==}
|
||||||
|
|
||||||
'@types/estree@1.0.8':
|
'@types/estree@1.0.8':
|
||||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
|
'@types/event-emitter@0.3.5':
|
||||||
|
resolution: {integrity: sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==}
|
||||||
|
|
||||||
'@types/node@25.9.1':
|
'@types/node@25.9.1':
|
||||||
resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==}
|
resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==}
|
||||||
|
|
||||||
|
'@uppy/companion-client@2.2.2':
|
||||||
|
resolution: {integrity: sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==}
|
||||||
|
|
||||||
|
'@uppy/core@2.3.4':
|
||||||
|
resolution: {integrity: sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==}
|
||||||
|
|
||||||
|
'@uppy/store-default@2.1.1':
|
||||||
|
resolution: {integrity: sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==}
|
||||||
|
|
||||||
|
'@uppy/utils@4.1.3':
|
||||||
|
resolution: {integrity: sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==}
|
||||||
|
|
||||||
|
'@uppy/xhr-upload@2.1.3':
|
||||||
|
resolution: {integrity: sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@uppy/core': ^2.3.3
|
||||||
|
|
||||||
'@vitejs/plugin-vue@5.2.4':
|
'@vitejs/plugin-vue@5.2.4':
|
||||||
resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==}
|
resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
@@ -452,6 +484,97 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.2.0
|
vue: ^3.2.0
|
||||||
|
|
||||||
|
'@wangeditor/basic-modules@1.1.7':
|
||||||
|
resolution: {integrity: sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@wangeditor/core': 1.x
|
||||||
|
dom7: ^3.0.0
|
||||||
|
lodash.throttle: ^4.1.1
|
||||||
|
nanoid: ^3.2.0
|
||||||
|
slate: ^0.72.0
|
||||||
|
snabbdom: ^3.1.0
|
||||||
|
|
||||||
|
'@wangeditor/code-highlight@1.0.3':
|
||||||
|
resolution: {integrity: sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@wangeditor/core': 1.x
|
||||||
|
dom7: ^3.0.0
|
||||||
|
slate: ^0.72.0
|
||||||
|
snabbdom: ^3.1.0
|
||||||
|
|
||||||
|
'@wangeditor/core@1.1.19':
|
||||||
|
resolution: {integrity: sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==}
|
||||||
|
peerDependencies:
|
||||||
|
'@uppy/core': ^2.1.1
|
||||||
|
'@uppy/xhr-upload': ^2.0.3
|
||||||
|
dom7: ^3.0.0
|
||||||
|
is-hotkey: ^0.2.0
|
||||||
|
lodash.camelcase: ^4.3.0
|
||||||
|
lodash.clonedeep: ^4.5.0
|
||||||
|
lodash.debounce: ^4.0.8
|
||||||
|
lodash.foreach: ^4.5.0
|
||||||
|
lodash.isequal: ^4.5.0
|
||||||
|
lodash.throttle: ^4.1.1
|
||||||
|
lodash.toarray: ^4.4.0
|
||||||
|
nanoid: ^3.2.0
|
||||||
|
slate: ^0.72.0
|
||||||
|
snabbdom: ^3.1.0
|
||||||
|
|
||||||
|
'@wangeditor/editor-for-vue@5.1.12':
|
||||||
|
resolution: {integrity: sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@wangeditor/editor': '>=5.1.0'
|
||||||
|
vue: ^3.0.5
|
||||||
|
|
||||||
|
'@wangeditor/editor@5.1.23':
|
||||||
|
resolution: {integrity: sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==}
|
||||||
|
|
||||||
|
'@wangeditor/list-module@1.0.5':
|
||||||
|
resolution: {integrity: sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@wangeditor/core': 1.x
|
||||||
|
dom7: ^3.0.0
|
||||||
|
slate: ^0.72.0
|
||||||
|
snabbdom: ^3.1.0
|
||||||
|
|
||||||
|
'@wangeditor/table-module@1.1.4':
|
||||||
|
resolution: {integrity: sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==}
|
||||||
|
peerDependencies:
|
||||||
|
'@wangeditor/core': 1.x
|
||||||
|
dom7: ^3.0.0
|
||||||
|
lodash.isequal: ^4.5.0
|
||||||
|
lodash.throttle: ^4.1.1
|
||||||
|
nanoid: ^3.2.0
|
||||||
|
slate: ^0.72.0
|
||||||
|
snabbdom: ^3.1.0
|
||||||
|
|
||||||
|
'@wangeditor/upload-image-module@1.0.2':
|
||||||
|
resolution: {integrity: sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@uppy/core': ^2.0.3
|
||||||
|
'@uppy/xhr-upload': ^2.0.3
|
||||||
|
'@wangeditor/basic-modules': 1.x
|
||||||
|
'@wangeditor/core': 1.x
|
||||||
|
dom7: ^3.0.0
|
||||||
|
lodash.foreach: ^4.5.0
|
||||||
|
slate: ^0.72.0
|
||||||
|
snabbdom: ^3.1.0
|
||||||
|
|
||||||
|
'@wangeditor/video-module@1.1.4':
|
||||||
|
resolution: {integrity: sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@uppy/core': ^2.1.4
|
||||||
|
'@uppy/xhr-upload': ^2.0.7
|
||||||
|
'@wangeditor/core': 1.x
|
||||||
|
dom7: ^3.0.0
|
||||||
|
nanoid: ^3.2.0
|
||||||
|
slate: ^0.72.0
|
||||||
|
snabbdom: ^3.1.0
|
||||||
|
|
||||||
|
'@xmldom/xmldom@0.8.13':
|
||||||
|
resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
'@xmldom/xmldom@0.9.10':
|
'@xmldom/xmldom@0.9.10':
|
||||||
resolution: {integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==}
|
resolution: {integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==}
|
||||||
engines: {node: '>=14.6'}
|
engines: {node: '>=14.6'}
|
||||||
@@ -498,6 +621,10 @@ packages:
|
|||||||
csstype@3.2.3:
|
csstype@3.2.3:
|
||||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||||
|
|
||||||
|
d@1.0.2:
|
||||||
|
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
|
||||||
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
dayjs@1.11.20:
|
dayjs@1.11.20:
|
||||||
resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
|
resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
|
||||||
|
|
||||||
@@ -534,6 +661,9 @@ packages:
|
|||||||
dom-zindex@1.0.6:
|
dom-zindex@1.0.6:
|
||||||
resolution: {integrity: sha512-FKWIhiU96bi3xpP9ewRMgANsoVmMUBnMnmpCT6dPMZOunVYJQmJhSRruoI0XSPoHeIif3kyEuiHbFrOJwEJaEA==}
|
resolution: {integrity: sha512-FKWIhiU96bi3xpP9ewRMgANsoVmMUBnMnmpCT6dPMZOunVYJQmJhSRruoI0XSPoHeIif3kyEuiHbFrOJwEJaEA==}
|
||||||
|
|
||||||
|
dom7@3.0.0:
|
||||||
|
resolution: {integrity: sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==}
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -558,14 +688,35 @@ packages:
|
|||||||
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
es5-ext@0.10.64:
|
||||||
|
resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
|
||||||
|
engines: {node: '>=0.10'}
|
||||||
|
|
||||||
|
es6-iterator@2.0.3:
|
||||||
|
resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
|
||||||
|
|
||||||
|
es6-symbol@3.1.4:
|
||||||
|
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
|
||||||
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
esbuild@0.25.12:
|
esbuild@0.25.12:
|
||||||
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
|
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
esniff@2.0.1:
|
||||||
|
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
|
||||||
|
engines: {node: '>=0.10'}
|
||||||
|
|
||||||
estree-walker@2.0.2:
|
estree-walker@2.0.2:
|
||||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||||
|
|
||||||
|
event-emitter@0.3.5:
|
||||||
|
resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
|
||||||
|
|
||||||
|
ext@1.7.0:
|
||||||
|
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
|
||||||
|
|
||||||
fdir@6.5.0:
|
fdir@6.5.0:
|
||||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
@@ -626,20 +777,39 @@ packages:
|
|||||||
resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
|
resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
html-void-elements@2.0.1:
|
||||||
|
resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
|
||||||
|
|
||||||
https-proxy-agent@5.0.1:
|
https-proxy-agent@5.0.1:
|
||||||
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
i18next@20.6.1:
|
||||||
|
resolution: {integrity: sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==}
|
||||||
|
|
||||||
immediate@3.0.6:
|
immediate@3.0.6:
|
||||||
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
|
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
|
||||||
|
|
||||||
|
immer@9.0.21:
|
||||||
|
resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
|
||||||
|
|
||||||
inherits@2.0.4:
|
inherits@2.0.4:
|
||||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
|
||||||
|
is-hotkey@0.2.0:
|
||||||
|
resolution: {integrity: sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==}
|
||||||
|
|
||||||
is-plain-object@3.0.1:
|
is-plain-object@3.0.1:
|
||||||
resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==}
|
resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
is-plain-object@5.0.0:
|
||||||
|
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
is-url@1.2.4:
|
||||||
|
resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
|
||||||
|
|
||||||
isarray@1.0.0:
|
isarray@1.0.0:
|
||||||
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
||||||
|
|
||||||
@@ -655,6 +825,28 @@ packages:
|
|||||||
lodash-es@4.18.1:
|
lodash-es@4.18.1:
|
||||||
resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==}
|
resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==}
|
||||||
|
|
||||||
|
lodash.camelcase@4.3.0:
|
||||||
|
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
|
||||||
|
|
||||||
|
lodash.clonedeep@4.5.0:
|
||||||
|
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
|
||||||
|
|
||||||
|
lodash.debounce@4.0.8:
|
||||||
|
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||||
|
|
||||||
|
lodash.foreach@4.5.0:
|
||||||
|
resolution: {integrity: sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==}
|
||||||
|
|
||||||
|
lodash.isequal@4.5.0:
|
||||||
|
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
|
||||||
|
deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
|
||||||
|
|
||||||
|
lodash.throttle@4.1.1:
|
||||||
|
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
|
||||||
|
|
||||||
|
lodash.toarray@4.4.0:
|
||||||
|
resolution: {integrity: sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==}
|
||||||
|
|
||||||
lodash@4.18.1:
|
lodash@4.18.1:
|
||||||
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
|
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
|
||||||
|
|
||||||
@@ -673,6 +865,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
mime-match@1.0.2:
|
||||||
|
resolution: {integrity: sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==}
|
||||||
|
|
||||||
mime-types@2.1.35:
|
mime-types@2.1.35:
|
||||||
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -683,6 +878,9 @@ packages:
|
|||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
|
namespace-emitter@2.0.1:
|
||||||
|
resolution: {integrity: sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==}
|
||||||
|
|
||||||
nanoid@3.3.12:
|
nanoid@3.3.12:
|
||||||
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
|
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
|
||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
@@ -696,6 +894,9 @@ packages:
|
|||||||
nanopop@2.4.2:
|
nanopop@2.4.2:
|
||||||
resolution: {integrity: sha512-NzOgmMQ+elxxHeIha+OG/Pv3Oc3p4RU2aBhwWwAqDpXrdTbtRylbRLQztLy8dMMwfl6pclznBdfUhccEn9ZIzw==}
|
resolution: {integrity: sha512-NzOgmMQ+elxxHeIha+OG/Pv3Oc3p4RU2aBhwWwAqDpXrdTbtRylbRLQztLy8dMMwfl6pclznBdfUhccEn9ZIzw==}
|
||||||
|
|
||||||
|
next-tick@1.1.0:
|
||||||
|
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
|
||||||
|
|
||||||
pako@1.0.11:
|
pako@1.0.11:
|
||||||
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
||||||
|
|
||||||
@@ -725,6 +926,18 @@ packages:
|
|||||||
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
preact@10.29.7:
|
||||||
|
resolution: {integrity: sha512-DCHYrK/B10yUD3ZjLfhZ3WIE/9Vf9VFUODcRE2dRomTYDpJk6z6L9wecSfhfE6M9ZTHUdyQkoC46arIDhEV84Q==}
|
||||||
|
peerDependencies:
|
||||||
|
preact-render-to-string: '>=5'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
preact-render-to-string:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
prismjs@1.30.0:
|
||||||
|
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
process-nextick-args@2.0.1:
|
process-nextick-args@2.0.1:
|
||||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||||
|
|
||||||
@@ -759,10 +972,25 @@ packages:
|
|||||||
shallow-equal@1.2.1:
|
shallow-equal@1.2.1:
|
||||||
resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==}
|
resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==}
|
||||||
|
|
||||||
|
slate-history@0.66.0:
|
||||||
|
resolution: {integrity: sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==}
|
||||||
|
peerDependencies:
|
||||||
|
slate: '>=0.65.3'
|
||||||
|
|
||||||
|
slate@0.72.8:
|
||||||
|
resolution: {integrity: sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==}
|
||||||
|
|
||||||
|
snabbdom@3.6.4:
|
||||||
|
resolution: {integrity: sha512-VmxEfuw1/Y/eFj5VtMhYnukExpYiPkNzoo3+N3qwAOUDMl8wXgbli5ebR+j0knE3lZ/0eYskLxNcX64uy10N9w==}
|
||||||
|
engines: {node: '>=12.17.0'}
|
||||||
|
|
||||||
source-map-js@1.2.1:
|
source-map-js@1.2.1:
|
||||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
ssr-window@3.0.0:
|
||||||
|
resolution: {integrity: sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==}
|
||||||
|
|
||||||
string_decoder@1.1.1:
|
string_decoder@1.1.1:
|
||||||
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
|
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
|
||||||
|
|
||||||
@@ -773,10 +1001,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==}
|
resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==}
|
||||||
engines: {node: '>=12.22'}
|
engines: {node: '>=12.22'}
|
||||||
|
|
||||||
|
tiny-warning@1.0.3:
|
||||||
|
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
||||||
|
|
||||||
tinyglobby@0.2.16:
|
tinyglobby@0.2.16:
|
||||||
resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
|
resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
|
type@2.7.3:
|
||||||
|
resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
|
||||||
|
|
||||||
undici-types@7.24.6:
|
undici-types@7.24.6:
|
||||||
resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
|
resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
|
||||||
|
|
||||||
@@ -862,6 +1096,9 @@ packages:
|
|||||||
warning@4.0.3:
|
warning@4.0.3:
|
||||||
resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
|
resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
|
||||||
|
|
||||||
|
wildcard@1.1.2:
|
||||||
|
resolution: {integrity: sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==}
|
||||||
|
|
||||||
xe-utils@4.0.8:
|
xe-utils@4.0.8:
|
||||||
resolution: {integrity: sha512-l+p++9iPtSxpf/5ZCzkPXsyV0avE34KzieAC9oAhi+3e98PLJaBQHNiY2V8Lnbiux4JFAbU10p8AT6oujXkP9A==}
|
resolution: {integrity: sha512-l+p++9iPtSxpf/5ZCzkPXsyV0avE34KzieAC9oAhi+3e98PLJaBQHNiY2V8Lnbiux4JFAbU10p8AT6oujXkP9A==}
|
||||||
|
|
||||||
@@ -1067,12 +1304,47 @@ snapshots:
|
|||||||
core-js: 3.49.0
|
core-js: 3.49.0
|
||||||
nanopop: 2.4.2
|
nanopop: 2.4.2
|
||||||
|
|
||||||
|
'@transloadit/prettier-bytes@0.0.7': {}
|
||||||
|
|
||||||
'@types/estree@1.0.8': {}
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
|
'@types/event-emitter@0.3.5': {}
|
||||||
|
|
||||||
'@types/node@25.9.1':
|
'@types/node@25.9.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.24.6
|
undici-types: 7.24.6
|
||||||
|
|
||||||
|
'@uppy/companion-client@2.2.2':
|
||||||
|
dependencies:
|
||||||
|
'@uppy/utils': 4.1.3
|
||||||
|
namespace-emitter: 2.0.1
|
||||||
|
|
||||||
|
'@uppy/core@2.3.4':
|
||||||
|
dependencies:
|
||||||
|
'@transloadit/prettier-bytes': 0.0.7
|
||||||
|
'@uppy/store-default': 2.1.1
|
||||||
|
'@uppy/utils': 4.1.3
|
||||||
|
lodash.throttle: 4.1.1
|
||||||
|
mime-match: 1.0.2
|
||||||
|
namespace-emitter: 2.0.1
|
||||||
|
nanoid: 3.3.12
|
||||||
|
preact: 10.29.7
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- preact-render-to-string
|
||||||
|
|
||||||
|
'@uppy/store-default@2.1.1': {}
|
||||||
|
|
||||||
|
'@uppy/utils@4.1.3':
|
||||||
|
dependencies:
|
||||||
|
lodash.throttle: 4.1.1
|
||||||
|
|
||||||
|
'@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4)':
|
||||||
|
dependencies:
|
||||||
|
'@uppy/companion-client': 2.2.2
|
||||||
|
'@uppy/core': 2.3.4
|
||||||
|
'@uppy/utils': 4.1.3
|
||||||
|
nanoid: 3.3.12
|
||||||
|
|
||||||
'@vitejs/plugin-vue@5.2.4(vite@6.4.2(@types/node@25.9.1))(vue@3.5.34)':
|
'@vitejs/plugin-vue@5.2.4(vite@6.4.2(@types/node@25.9.1))(vue@3.5.34)':
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 6.4.2(@types/node@25.9.1)
|
vite: 6.4.2(@types/node@25.9.1)
|
||||||
@@ -1140,6 +1412,118 @@ snapshots:
|
|||||||
vue: 3.5.34
|
vue: 3.5.34
|
||||||
xe-utils: 4.0.8
|
xe-utils: 4.0.8
|
||||||
|
|
||||||
|
'@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)':
|
||||||
|
dependencies:
|
||||||
|
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
dom7: 3.0.0
|
||||||
|
is-url: 1.2.4
|
||||||
|
lodash.throttle: 4.1.1
|
||||||
|
nanoid: 3.3.12
|
||||||
|
slate: 0.72.8
|
||||||
|
snabbdom: 3.6.4
|
||||||
|
|
||||||
|
'@wangeditor/code-highlight@1.0.3(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.4)':
|
||||||
|
dependencies:
|
||||||
|
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
dom7: 3.0.0
|
||||||
|
prismjs: 1.30.0
|
||||||
|
slate: 0.72.8
|
||||||
|
snabbdom: 3.6.4
|
||||||
|
|
||||||
|
'@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)':
|
||||||
|
dependencies:
|
||||||
|
'@types/event-emitter': 0.3.5
|
||||||
|
'@uppy/core': 2.3.4
|
||||||
|
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||||
|
dom7: 3.0.0
|
||||||
|
event-emitter: 0.3.5
|
||||||
|
html-void-elements: 2.0.1
|
||||||
|
i18next: 20.6.1
|
||||||
|
is-hotkey: 0.2.0
|
||||||
|
lodash.camelcase: 4.3.0
|
||||||
|
lodash.clonedeep: 4.5.0
|
||||||
|
lodash.debounce: 4.0.8
|
||||||
|
lodash.foreach: 4.5.0
|
||||||
|
lodash.isequal: 4.5.0
|
||||||
|
lodash.throttle: 4.1.1
|
||||||
|
lodash.toarray: 4.4.0
|
||||||
|
nanoid: 3.3.12
|
||||||
|
scroll-into-view-if-needed: 2.2.31
|
||||||
|
slate: 0.72.8
|
||||||
|
slate-history: 0.66.0(slate@0.72.8)
|
||||||
|
snabbdom: 3.6.4
|
||||||
|
|
||||||
|
'@wangeditor/editor-for-vue@5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.34)':
|
||||||
|
dependencies:
|
||||||
|
'@wangeditor/editor': 5.1.23
|
||||||
|
vue: 3.5.34
|
||||||
|
|
||||||
|
'@wangeditor/editor@5.1.23':
|
||||||
|
dependencies:
|
||||||
|
'@uppy/core': 2.3.4
|
||||||
|
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||||
|
'@wangeditor/basic-modules': 1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
'@wangeditor/code-highlight': 1.0.3(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
'@wangeditor/list-module': 1.0.5(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
'@wangeditor/table-module': 1.1.4(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
'@wangeditor/upload-image-module': 1.0.2(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(lodash.foreach@4.5.0)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
'@wangeditor/video-module': 1.1.4(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
dom7: 3.0.0
|
||||||
|
is-hotkey: 0.2.0
|
||||||
|
lodash.camelcase: 4.3.0
|
||||||
|
lodash.clonedeep: 4.5.0
|
||||||
|
lodash.debounce: 4.0.8
|
||||||
|
lodash.foreach: 4.5.0
|
||||||
|
lodash.isequal: 4.5.0
|
||||||
|
lodash.throttle: 4.1.1
|
||||||
|
lodash.toarray: 4.4.0
|
||||||
|
nanoid: 3.3.12
|
||||||
|
slate: 0.72.8
|
||||||
|
snabbdom: 3.6.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- preact-render-to-string
|
||||||
|
|
||||||
|
'@wangeditor/list-module@1.0.5(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.4)':
|
||||||
|
dependencies:
|
||||||
|
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
dom7: 3.0.0
|
||||||
|
slate: 0.72.8
|
||||||
|
snabbdom: 3.6.4
|
||||||
|
|
||||||
|
'@wangeditor/table-module@1.1.4(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)':
|
||||||
|
dependencies:
|
||||||
|
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
dom7: 3.0.0
|
||||||
|
lodash.isequal: 4.5.0
|
||||||
|
lodash.throttle: 4.1.1
|
||||||
|
nanoid: 3.3.12
|
||||||
|
slate: 0.72.8
|
||||||
|
snabbdom: 3.6.4
|
||||||
|
|
||||||
|
'@wangeditor/upload-image-module@1.0.2(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(lodash.foreach@4.5.0)(slate@0.72.8)(snabbdom@3.6.4)':
|
||||||
|
dependencies:
|
||||||
|
'@uppy/core': 2.3.4
|
||||||
|
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||||
|
'@wangeditor/basic-modules': 1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
dom7: 3.0.0
|
||||||
|
lodash.foreach: 4.5.0
|
||||||
|
slate: 0.72.8
|
||||||
|
snabbdom: 3.6.4
|
||||||
|
|
||||||
|
'@wangeditor/video-module@1.1.4(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4))(dom7@3.0.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)':
|
||||||
|
dependencies:
|
||||||
|
'@uppy/core': 2.3.4
|
||||||
|
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||||
|
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.12)(slate@0.72.8)(snabbdom@3.6.4)
|
||||||
|
dom7: 3.0.0
|
||||||
|
nanoid: 3.3.12
|
||||||
|
slate: 0.72.8
|
||||||
|
snabbdom: 3.6.4
|
||||||
|
|
||||||
|
'@xmldom/xmldom@0.8.13': {}
|
||||||
|
|
||||||
'@xmldom/xmldom@0.9.10': {}
|
'@xmldom/xmldom@0.9.10': {}
|
||||||
|
|
||||||
agent-base@6.0.2:
|
agent-base@6.0.2:
|
||||||
@@ -1207,6 +1591,11 @@ snapshots:
|
|||||||
|
|
||||||
csstype@3.2.3: {}
|
csstype@3.2.3: {}
|
||||||
|
|
||||||
|
d@1.0.2:
|
||||||
|
dependencies:
|
||||||
|
es5-ext: 0.10.64
|
||||||
|
type: 2.7.3
|
||||||
|
|
||||||
dayjs@1.11.20: {}
|
dayjs@1.11.20: {}
|
||||||
|
|
||||||
debug@4.4.3:
|
debug@4.4.3:
|
||||||
@@ -1238,6 +1627,10 @@ snapshots:
|
|||||||
|
|
||||||
dom-zindex@1.0.6: {}
|
dom-zindex@1.0.6: {}
|
||||||
|
|
||||||
|
dom7@3.0.0:
|
||||||
|
dependencies:
|
||||||
|
ssr-window: 3.0.0
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
@@ -1261,6 +1654,24 @@ snapshots:
|
|||||||
has-tostringtag: 1.0.2
|
has-tostringtag: 1.0.2
|
||||||
hasown: 2.0.3
|
hasown: 2.0.3
|
||||||
|
|
||||||
|
es5-ext@0.10.64:
|
||||||
|
dependencies:
|
||||||
|
es6-iterator: 2.0.3
|
||||||
|
es6-symbol: 3.1.4
|
||||||
|
esniff: 2.0.1
|
||||||
|
next-tick: 1.1.0
|
||||||
|
|
||||||
|
es6-iterator@2.0.3:
|
||||||
|
dependencies:
|
||||||
|
d: 1.0.2
|
||||||
|
es5-ext: 0.10.64
|
||||||
|
es6-symbol: 3.1.4
|
||||||
|
|
||||||
|
es6-symbol@3.1.4:
|
||||||
|
dependencies:
|
||||||
|
d: 1.0.2
|
||||||
|
ext: 1.7.0
|
||||||
|
|
||||||
esbuild@0.25.12:
|
esbuild@0.25.12:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/aix-ppc64': 0.25.12
|
'@esbuild/aix-ppc64': 0.25.12
|
||||||
@@ -1290,8 +1701,24 @@ snapshots:
|
|||||||
'@esbuild/win32-ia32': 0.25.12
|
'@esbuild/win32-ia32': 0.25.12
|
||||||
'@esbuild/win32-x64': 0.25.12
|
'@esbuild/win32-x64': 0.25.12
|
||||||
|
|
||||||
|
esniff@2.0.1:
|
||||||
|
dependencies:
|
||||||
|
d: 1.0.2
|
||||||
|
es5-ext: 0.10.64
|
||||||
|
event-emitter: 0.3.5
|
||||||
|
type: 2.7.3
|
||||||
|
|
||||||
estree-walker@2.0.2: {}
|
estree-walker@2.0.2: {}
|
||||||
|
|
||||||
|
event-emitter@0.3.5:
|
||||||
|
dependencies:
|
||||||
|
d: 1.0.2
|
||||||
|
es5-ext: 0.10.64
|
||||||
|
|
||||||
|
ext@1.7.0:
|
||||||
|
dependencies:
|
||||||
|
type: 2.7.3
|
||||||
|
|
||||||
fdir@6.5.0(picomatch@4.0.4):
|
fdir@6.5.0(picomatch@4.0.4):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
picomatch: 4.0.4
|
picomatch: 4.0.4
|
||||||
@@ -1348,6 +1775,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
|
html-void-elements@2.0.1: {}
|
||||||
|
|
||||||
https-proxy-agent@5.0.1:
|
https-proxy-agent@5.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 6.0.2
|
agent-base: 6.0.2
|
||||||
@@ -1355,12 +1784,24 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
i18next@20.6.1:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.29.2
|
||||||
|
|
||||||
immediate@3.0.6: {}
|
immediate@3.0.6: {}
|
||||||
|
|
||||||
|
immer@9.0.21: {}
|
||||||
|
|
||||||
inherits@2.0.4: {}
|
inherits@2.0.4: {}
|
||||||
|
|
||||||
|
is-hotkey@0.2.0: {}
|
||||||
|
|
||||||
is-plain-object@3.0.1: {}
|
is-plain-object@3.0.1: {}
|
||||||
|
|
||||||
|
is-plain-object@5.0.0: {}
|
||||||
|
|
||||||
|
is-url@1.2.4: {}
|
||||||
|
|
||||||
isarray@1.0.0: {}
|
isarray@1.0.0: {}
|
||||||
|
|
||||||
js-tokens@4.0.0: {}
|
js-tokens@4.0.0: {}
|
||||||
@@ -1378,6 +1819,20 @@ snapshots:
|
|||||||
|
|
||||||
lodash-es@4.18.1: {}
|
lodash-es@4.18.1: {}
|
||||||
|
|
||||||
|
lodash.camelcase@4.3.0: {}
|
||||||
|
|
||||||
|
lodash.clonedeep@4.5.0: {}
|
||||||
|
|
||||||
|
lodash.debounce@4.0.8: {}
|
||||||
|
|
||||||
|
lodash.foreach@4.5.0: {}
|
||||||
|
|
||||||
|
lodash.isequal@4.5.0: {}
|
||||||
|
|
||||||
|
lodash.throttle@4.1.1: {}
|
||||||
|
|
||||||
|
lodash.toarray@4.4.0: {}
|
||||||
|
|
||||||
lodash@4.18.1: {}
|
lodash@4.18.1: {}
|
||||||
|
|
||||||
loose-envify@1.4.0:
|
loose-envify@1.4.0:
|
||||||
@@ -1392,6 +1847,10 @@ snapshots:
|
|||||||
|
|
||||||
mime-db@1.52.0: {}
|
mime-db@1.52.0: {}
|
||||||
|
|
||||||
|
mime-match@1.0.2:
|
||||||
|
dependencies:
|
||||||
|
wildcard: 1.1.2
|
||||||
|
|
||||||
mime-types@2.1.35:
|
mime-types@2.1.35:
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-db: 1.52.0
|
mime-db: 1.52.0
|
||||||
@@ -1400,12 +1859,16 @@ snapshots:
|
|||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
|
namespace-emitter@2.0.1: {}
|
||||||
|
|
||||||
nanoid@3.3.12: {}
|
nanoid@3.3.12: {}
|
||||||
|
|
||||||
nanoid@5.1.11: {}
|
nanoid@5.1.11: {}
|
||||||
|
|
||||||
nanopop@2.4.2: {}
|
nanopop@2.4.2: {}
|
||||||
|
|
||||||
|
next-tick@1.1.0: {}
|
||||||
|
|
||||||
pako@1.0.11: {}
|
pako@1.0.11: {}
|
||||||
|
|
||||||
pako@2.1.0: {}
|
pako@2.1.0: {}
|
||||||
@@ -1432,6 +1895,10 @@ snapshots:
|
|||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
preact@10.29.7: {}
|
||||||
|
|
||||||
|
prismjs@1.30.0: {}
|
||||||
|
|
||||||
process-nextick-args@2.0.1: {}
|
process-nextick-args@2.0.1: {}
|
||||||
|
|
||||||
proxy-from-env@2.1.0: {}
|
proxy-from-env@2.1.0: {}
|
||||||
@@ -1491,8 +1958,23 @@ snapshots:
|
|||||||
|
|
||||||
shallow-equal@1.2.1: {}
|
shallow-equal@1.2.1: {}
|
||||||
|
|
||||||
|
slate-history@0.66.0(slate@0.72.8):
|
||||||
|
dependencies:
|
||||||
|
is-plain-object: 5.0.0
|
||||||
|
slate: 0.72.8
|
||||||
|
|
||||||
|
slate@0.72.8:
|
||||||
|
dependencies:
|
||||||
|
immer: 9.0.21
|
||||||
|
is-plain-object: 5.0.0
|
||||||
|
tiny-warning: 1.0.3
|
||||||
|
|
||||||
|
snabbdom@3.6.4: {}
|
||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
ssr-window@3.0.0: {}
|
||||||
|
|
||||||
string_decoder@1.1.1:
|
string_decoder@1.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.1.2
|
safe-buffer: 5.1.2
|
||||||
@@ -1501,11 +1983,15 @@ snapshots:
|
|||||||
|
|
||||||
throttle-debounce@5.0.2: {}
|
throttle-debounce@5.0.2: {}
|
||||||
|
|
||||||
|
tiny-warning@1.0.3: {}
|
||||||
|
|
||||||
tinyglobby@0.2.16:
|
tinyglobby@0.2.16:
|
||||||
dependencies:
|
dependencies:
|
||||||
fdir: 6.5.0(picomatch@4.0.4)
|
fdir: 6.5.0(picomatch@4.0.4)
|
||||||
picomatch: 4.0.4
|
picomatch: 4.0.4
|
||||||
|
|
||||||
|
type@2.7.3: {}
|
||||||
|
|
||||||
undici-types@7.24.6: {}
|
undici-types@7.24.6: {}
|
||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
@@ -1560,6 +2046,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
loose-envify: 1.4.0
|
loose-envify: 1.4.0
|
||||||
|
|
||||||
|
wildcard@1.1.2: {}
|
||||||
|
|
||||||
xe-utils@4.0.8: {}
|
xe-utils@4.0.8: {}
|
||||||
|
|
||||||
xml-js@1.6.11:
|
xml-js@1.6.11:
|
||||||
|
|||||||
@@ -71,12 +71,34 @@
|
|||||||
v-for="field in launchFieldList"
|
v-for="field in launchFieldList"
|
||||||
:key="field.key"
|
:key="field.key"
|
||||||
:label="field.label"
|
:label="field.label"
|
||||||
:required="!field.readonly"
|
:required="field.required"
|
||||||
|
:extra="field.remark || undefined"
|
||||||
|
:class="{ 'grid-span-2': field.fieldType === 'rich_text' }"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-select
|
||||||
|
v-if="field.fieldType === 'select'"
|
||||||
:value="getLaunchFieldValue(field.key)"
|
:value="getLaunchFieldValue(field.key)"
|
||||||
:placeholder="`请输入${field.label}`"
|
:options="getFieldDictOptions(field)"
|
||||||
:readonly="field.readonly"
|
:placeholder="field.placeholder"
|
||||||
|
:loading="isDictLoading(field.dictType)"
|
||||||
|
:disabled="isViewMode"
|
||||||
|
allow-clear
|
||||||
|
show-search
|
||||||
|
option-filter-prop="label"
|
||||||
|
@update:value="setLaunchFieldValue(field.key, $event)"
|
||||||
|
/>
|
||||||
|
<TemplateRichTextEditor
|
||||||
|
v-else-if="field.fieldType === 'rich_text'"
|
||||||
|
:model-value="getLaunchFieldValue(field.key)"
|
||||||
|
:placeholder="field.placeholder"
|
||||||
|
:disabled="isViewMode"
|
||||||
|
@update:model-value="setLaunchFieldValue(field.key, $event)"
|
||||||
|
/>
|
||||||
|
<a-input
|
||||||
|
v-else
|
||||||
|
:value="getLaunchFieldValue(field.key)"
|
||||||
|
:placeholder="field.placeholder"
|
||||||
|
:readonly="isViewMode"
|
||||||
@update:value="setLaunchFieldValue(field.key, $event)"
|
@update:value="setLaunchFieldValue(field.key, $event)"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -177,7 +199,6 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, nextTick, onBeforeUnmount, ref, watch } from "vue";
|
import { computed, nextTick, onBeforeUnmount, ref, watch } from "vue";
|
||||||
import Docxtemplater from "docxtemplater";
|
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import {
|
import {
|
||||||
FileWordOutlined,
|
FileWordOutlined,
|
||||||
@@ -185,9 +206,9 @@ import {
|
|||||||
SettingOutlined,
|
SettingOutlined,
|
||||||
} from "@ant-design/icons-vue";
|
} from "@ant-design/icons-vue";
|
||||||
import { message } from "ant-design-vue";
|
import { message } from "ant-design-vue";
|
||||||
import PizZip from "pizzip";
|
|
||||||
import { renderAsync } from "docx-preview";
|
import { renderAsync } from "docx-preview";
|
||||||
import { saveAs } from "file-saver";
|
import { saveAs } from "file-saver";
|
||||||
|
import { getDictDataByType } from "@/api/dict.js";
|
||||||
import {
|
import {
|
||||||
downloadTemplateFile,
|
downloadTemplateFile,
|
||||||
queryPublishedManifestList,
|
queryPublishedManifestList,
|
||||||
@@ -197,6 +218,9 @@ import {
|
|||||||
buildTemplateFieldLabelMap,
|
buildTemplateFieldLabelMap,
|
||||||
loadTemplateFieldList,
|
loadTemplateFieldList,
|
||||||
} from "../../shared/templateFieldDict.js";
|
} from "../../shared/templateFieldDict.js";
|
||||||
|
import { renderTemplateDocxBlob } from "../../shared/templateDocxRenderer.js";
|
||||||
|
import { buildTemplateLaunchFieldList } from "../../shared/templateVariableConfig.js";
|
||||||
|
import TemplateRichTextEditor from "./TemplateRichTextEditor.vue";
|
||||||
import {
|
import {
|
||||||
extraAmountFieldOptions,
|
extraAmountFieldOptions,
|
||||||
} from "../contractLaunchOptions.js";
|
} from "../contractLaunchOptions.js";
|
||||||
@@ -599,16 +623,9 @@ function copyContractFormData(data = {}) {
|
|||||||
return form;
|
return form;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTemplateRenderData(templateFieldValues = {}) {
|
|
||||||
const data = {};
|
|
||||||
(templateFieldList.value || []).forEach((item) => {
|
|
||||||
data[item.value] = templateFieldValues?.[item.value] ?? "";
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits(["save"]);
|
const emit = defineEmits(["save"]);
|
||||||
|
|
||||||
|
const formRef = ref(null);
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const previewRef = ref(null);
|
const previewRef = ref(null);
|
||||||
const modalMode = ref("create");
|
const modalMode = ref("create");
|
||||||
@@ -622,6 +639,8 @@ const previewBlob = ref(null);
|
|||||||
const manualBodyFileList = ref([]);
|
const manualBodyFileList = ref([]);
|
||||||
const publishedTemplates = ref([]);
|
const publishedTemplates = ref([]);
|
||||||
const templateFieldList = ref([]);
|
const templateFieldList = ref([]);
|
||||||
|
const dictOptionMap = ref({});
|
||||||
|
const dictLoadingMap = ref({});
|
||||||
|
|
||||||
const templateBufferCache = new Map();
|
const templateBufferCache = new Map();
|
||||||
let previewTimer = null;
|
let previewTimer = null;
|
||||||
@@ -648,19 +667,10 @@ const templateFieldLabelMap = computed(() =>
|
|||||||
|
|
||||||
const launchFieldList = computed(() => {
|
const launchFieldList = computed(() => {
|
||||||
if (creationMode.value === "manual") return [];
|
if (creationMode.value === "manual") return [];
|
||||||
const mappings = activeTemplate.value?.variableMappings || [];
|
return buildTemplateLaunchFieldList(
|
||||||
const keys = [];
|
activeTemplate.value?.variableMappings || [],
|
||||||
mappings.forEach((item) => {
|
templateFieldLabelMap.value,
|
||||||
const fieldKey = item.bindField || item.variableKey;
|
);
|
||||||
if (fieldKey && !keys.includes(fieldKey)) {
|
|
||||||
keys.push(fieldKey);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return keys.map((key) => ({
|
|
||||||
key,
|
|
||||||
label: templateFieldLabelMap.value[key] || key,
|
|
||||||
readonly: false,
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function getLaunchFieldValue(fieldKey) {
|
function getLaunchFieldValue(fieldKey) {
|
||||||
@@ -671,15 +681,111 @@ function setLaunchFieldValue(fieldKey, value) {
|
|||||||
if (!contractDetailState.value.templateFieldValues) {
|
if (!contractDetailState.value.templateFieldValues) {
|
||||||
contractDetailState.value.templateFieldValues = {};
|
contractDetailState.value.templateFieldValues = {};
|
||||||
}
|
}
|
||||||
contractDetailState.value.templateFieldValues[fieldKey] = value;
|
contractDetailState.value.templateFieldValues[fieldKey] = value ?? "";
|
||||||
if (visible.value) {
|
if (visible.value) {
|
||||||
schedulePreview();
|
schedulePreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const templateVariables = computed(() =>
|
function normalizeDictOptions(list = []) {
|
||||||
buildTemplateRenderData(contractDetailState.value.templateFieldValues || {}),
|
return (list || [])
|
||||||
);
|
.map((item) => ({
|
||||||
|
label: item?.k || item?.label || "",
|
||||||
|
value: item?.v || item?.value || "",
|
||||||
|
remark: item?.remark || "",
|
||||||
|
}))
|
||||||
|
.filter((item) => item.label && item.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadDictOptionsByType(dictType) {
|
||||||
|
const key = String(dictType || "").trim();
|
||||||
|
if (!key) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (dictOptionMap.value[key]?.length) {
|
||||||
|
return dictOptionMap.value[key];
|
||||||
|
}
|
||||||
|
if (dictLoadingMap.value[key]) {
|
||||||
|
return dictOptionMap.value[key] || [];
|
||||||
|
}
|
||||||
|
dictLoadingMap.value = { ...dictLoadingMap.value, [key]: true };
|
||||||
|
try {
|
||||||
|
const result = await getDictDataByType(key);
|
||||||
|
const options = normalizeDictOptions(result);
|
||||||
|
dictOptionMap.value = { ...dictOptionMap.value, [key]: options };
|
||||||
|
return options;
|
||||||
|
} finally {
|
||||||
|
dictLoadingMap.value = { ...dictLoadingMap.value, [key]: false };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadCurrentTemplateDictOptions() {
|
||||||
|
if (creationMode.value !== "template") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const dictTypes = [...new Set(
|
||||||
|
launchFieldList.value
|
||||||
|
.filter((item) => item.fieldType === "select" && item.dictType)
|
||||||
|
.map((item) => item.dictType),
|
||||||
|
)];
|
||||||
|
await Promise.all(dictTypes.map((item) => loadDictOptionsByType(item)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFieldDictOptions(field = {}) {
|
||||||
|
return dictOptionMap.value[String(field.dictType || "").trim()] || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDictLoading(dictType) {
|
||||||
|
return !!dictLoadingMap.value[String(dictType || "").trim()];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLaunchFieldByKey(fieldKey) {
|
||||||
|
return launchFieldList.value.find((item) => item.key === fieldKey) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLaunchFieldDisplayValue(field = {}) {
|
||||||
|
const rawValue = getLaunchFieldValue(field.key);
|
||||||
|
if (field.fieldType !== "select") {
|
||||||
|
return rawValue;
|
||||||
|
}
|
||||||
|
const option = getFieldDictOptions(field).find(
|
||||||
|
(item) => String(item.value) === String(rawValue ?? ""),
|
||||||
|
);
|
||||||
|
return option?.label ?? rawValue ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripRichTextContent(htmlValue) {
|
||||||
|
return String(htmlValue || "")
|
||||||
|
.replace(/<table[\s\S]*?<\/table>/gi, " [表格] ")
|
||||||
|
.replace(/<style[\s\S]*?<\/style>/gi, " ")
|
||||||
|
.replace(/<script[\s\S]*?<\/script>/gi, " ")
|
||||||
|
.replace(/<[^>]+>/g, " ")
|
||||||
|
.replace(/ /gi, " ")
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLaunchFieldEmpty(field = {}, value) {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (field.fieldType === "rich_text") {
|
||||||
|
return !stripRichTextContent(value);
|
||||||
|
}
|
||||||
|
return String(value).trim() === "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTemplateRenderFieldValues() {
|
||||||
|
const values = {
|
||||||
|
...(contractDetailState.value.templateFieldValues || {}),
|
||||||
|
};
|
||||||
|
launchFieldList.value.forEach((field) => {
|
||||||
|
if (field.fieldType === "select") {
|
||||||
|
values[field.key] = getLaunchFieldDisplayValue(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
const hasPreviewSource = computed(() => {
|
const hasPreviewSource = computed(() => {
|
||||||
return creationMode.value === "manual"
|
return creationMode.value === "manual"
|
||||||
@@ -710,9 +816,11 @@ watch(
|
|||||||
previewError.value = "";
|
previewError.value = "";
|
||||||
if (visible.value && creationMode.value === "template") {
|
if (visible.value && creationMode.value === "template") {
|
||||||
prefillFromMainFields();
|
prefillFromMainFields();
|
||||||
|
loadCurrentTemplateDictOptions().finally(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
schedulePreview();
|
schedulePreview();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -721,15 +829,17 @@ watch(
|
|||||||
() => visible.value,
|
() => visible.value,
|
||||||
(open) => {
|
(open) => {
|
||||||
if (open) {
|
if (open) {
|
||||||
|
loadCurrentTemplateDictOptions().finally(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
refreshPreview();
|
refreshPreview();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => JSON.stringify(templateVariables.value),
|
() => JSON.stringify(contractDetailState.value.templateFieldValues || {}),
|
||||||
() => {
|
() => {
|
||||||
if (visible.value) {
|
if (visible.value) {
|
||||||
schedulePreview();
|
schedulePreview();
|
||||||
@@ -764,7 +874,9 @@ watch(
|
|||||||
previewBlob.value = null;
|
previewBlob.value = null;
|
||||||
previewError.value = "";
|
previewError.value = "";
|
||||||
if (visible.value) {
|
if (visible.value) {
|
||||||
|
loadCurrentTemplateDictOptions().finally(() => {
|
||||||
schedulePreview();
|
schedulePreview();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -793,6 +905,22 @@ function loadTemplateFields() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => JSON.stringify(
|
||||||
|
launchFieldList.value.map((item) => ({
|
||||||
|
key: item.key,
|
||||||
|
fieldType: item.fieldType,
|
||||||
|
dictType: item.dictType,
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
() => {
|
||||||
|
if (visible.value && creationMode.value === "template") {
|
||||||
|
loadCurrentTemplateDictOptions();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: false },
|
||||||
|
);
|
||||||
|
|
||||||
function getManifestDetailLocal(templateId) {
|
function getManifestDetailLocal(templateId) {
|
||||||
return (
|
return (
|
||||||
publishedTemplates.value.find((item) => item.id === templateId) || null
|
publishedTemplates.value.find((item) => item.id === templateId) || null
|
||||||
@@ -869,6 +997,8 @@ async function buildFilledDocumentBlob() {
|
|||||||
throw new Error("请选择合同模板");
|
throw new Error("请选择合同模板");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await loadCurrentTemplateDictOptions();
|
||||||
|
|
||||||
const buffer = activeTemplate.value.templateArrayBuffer
|
const buffer = activeTemplate.value.templateArrayBuffer
|
||||||
? activeTemplate.value.templateArrayBuffer.slice(0)
|
? activeTemplate.value.templateArrayBuffer.slice(0)
|
||||||
: await fetchTemplateBuffer(
|
: await fetchTemplateBuffer(
|
||||||
@@ -876,36 +1006,10 @@ async function buildFilledDocumentBlob() {
|
|||||||
activeTemplate.value.templateFileUrl ||
|
activeTemplate.value.templateFileUrl ||
|
||||||
activeTemplate.value.fileUrl,
|
activeTemplate.value.fileUrl,
|
||||||
);
|
);
|
||||||
const zip = new PizZip(buffer);
|
return await renderTemplateDocxBlob({
|
||||||
const doc = new Docxtemplater(zip, {
|
templateArrayBuffer: buffer,
|
||||||
paragraphLoop: true,
|
variableMappings: activeTemplate.value.variableMappings || [],
|
||||||
linebreaks: true,
|
templateFieldValues: buildTemplateRenderFieldValues(),
|
||||||
nullGetter(part) {
|
|
||||||
return part?.raw ? `[${part.raw}]` : "";
|
|
||||||
},
|
|
||||||
});
|
|
||||||
//这里是生成的测试数据
|
|
||||||
const sourceValues = buildTemplateRenderData(
|
|
||||||
contractDetailState.value.templateFieldValues || {},
|
|
||||||
);
|
|
||||||
const mappings = activeTemplate.value.variableMappings || [];
|
|
||||||
|
|
||||||
const renderData = {};
|
|
||||||
if (mappings.length) {
|
|
||||||
mappings.forEach((item) => {
|
|
||||||
if (!item.variableKey) return;
|
|
||||||
renderData[item.variableKey] = sourceValues[item.bindField] ?? "";
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Object.assign(renderData, sourceValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.render(renderData);
|
|
||||||
|
|
||||||
return doc.getZip().generate({
|
|
||||||
type: "blob",
|
|
||||||
mimeType:
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1048,12 +1152,11 @@ function validateMainForm() {
|
|||||||
return "请选择合同模板";
|
return "请选择合同模板";
|
||||||
|
|
||||||
for (const field of launchFieldList.value) {
|
for (const field of launchFieldList.value) {
|
||||||
if (field.readonly) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const value = getLaunchFieldValue(field.key);
|
const value = getLaunchFieldValue(field.key);
|
||||||
if (value === null || value === undefined || value === "") {
|
if (field.required && isLaunchFieldEmpty(field, value)) {
|
||||||
return `请输入${field.label}`;
|
return field.fieldType === "select"
|
||||||
|
? `请选择${field.label}`
|
||||||
|
: `请输入${field.label}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1129,6 +1232,7 @@ async function showModal(initialValues = {}, mode = "create") {
|
|||||||
|
|
||||||
// 预填充:从主合同同名字段自动取值填入模板变量
|
// 预填充:从主合同同名字段自动取值填入模板变量
|
||||||
prefillFromMainFields(initialValues.detailState || initialValues);
|
prefillFromMainFields(initialValues.detailState || initialValues);
|
||||||
|
await loadCurrentTemplateDictOptions();
|
||||||
|
|
||||||
syncManualBodyFileList();
|
syncManualBodyFileList();
|
||||||
previewBlob.value = null;
|
previewBlob.value = null;
|
||||||
@@ -1274,6 +1378,15 @@ onBeforeUnmount(() => {
|
|||||||
gap: 14px;
|
gap: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid-span-2 {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-form :deep(.ant-select),
|
||||||
|
.config-form :deep(.ant-input) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.template-tip {
|
.template-tip {
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
<template>
|
||||||
|
<div class="template-rich-editor" :class="{ 'is-disabled': disabled }">
|
||||||
|
<Toolbar
|
||||||
|
class="editor-toolbar"
|
||||||
|
:editor="editorRef"
|
||||||
|
:default-config="toolbarConfig"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
<Editor
|
||||||
|
class="editor-content"
|
||||||
|
:model-value="modelValue"
|
||||||
|
:default-config="editorConfig"
|
||||||
|
:mode="mode"
|
||||||
|
@onCreated="handleCreated"
|
||||||
|
@update:modelValue="handleChange"
|
||||||
|
/>
|
||||||
|
<div class="editor-tip">
|
||||||
|
当前支持普通文字、列表和基础表格。为保证导出 Word 效果,建议不要使用合并单元格和复杂样式。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, onBeforeUnmount, shallowRef } from 'vue'
|
||||||
|
import '@wangeditor/editor/dist/css/style.css'
|
||||||
|
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入内容,支持插入表格',
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const mode = 'default'
|
||||||
|
const editorRef = shallowRef(null)
|
||||||
|
|
||||||
|
const toolbarConfig = {
|
||||||
|
toolbarKeys: [
|
||||||
|
'headerSelect',
|
||||||
|
'|',
|
||||||
|
'bold',
|
||||||
|
'italic',
|
||||||
|
'underline',
|
||||||
|
'through',
|
||||||
|
'|',
|
||||||
|
'color',
|
||||||
|
'bgColor',
|
||||||
|
'|',
|
||||||
|
'bulletedList',
|
||||||
|
'numberedList',
|
||||||
|
'|',
|
||||||
|
'justifyLeft',
|
||||||
|
'justifyCenter',
|
||||||
|
'justifyRight',
|
||||||
|
'|',
|
||||||
|
'insertTable',
|
||||||
|
'deleteTable',
|
||||||
|
'insertTableRow',
|
||||||
|
'deleteTableRow',
|
||||||
|
'insertTableCol',
|
||||||
|
'deleteTableCol',
|
||||||
|
'tableHeader',
|
||||||
|
'|',
|
||||||
|
'undo',
|
||||||
|
'redo',
|
||||||
|
],
|
||||||
|
excludeKeys: ['fullScreen'],
|
||||||
|
}
|
||||||
|
|
||||||
|
const editorConfig = computed(() => ({
|
||||||
|
placeholder: props.placeholder,
|
||||||
|
readOnly: props.disabled,
|
||||||
|
autoFocus: false,
|
||||||
|
scroll: true,
|
||||||
|
hoverbarKeys: {
|
||||||
|
table: {
|
||||||
|
menuKeys: [
|
||||||
|
'insertTableRow',
|
||||||
|
'deleteTableRow',
|
||||||
|
'insertTableCol',
|
||||||
|
'deleteTableCol',
|
||||||
|
'tableHeader',
|
||||||
|
'deleteTable',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MENU_CONF: {
|
||||||
|
insertTable: {
|
||||||
|
rows: 3,
|
||||||
|
cols: 4,
|
||||||
|
},
|
||||||
|
insertImage: { base64LimitSize: 0 },
|
||||||
|
uploadImage: { server: '' },
|
||||||
|
uploadVideo: { server: '' },
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
function handleCreated(editor) {
|
||||||
|
editorRef.value = editor
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChange(value) {
|
||||||
|
emit('update:modelValue', value || '')
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
const editor = editorRef.value
|
||||||
|
if (editor) {
|
||||||
|
editor.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.template-rich-editor {
|
||||||
|
border: 1px solid #d9e1ec;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-rich-editor.is-disabled {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-toolbar {
|
||||||
|
border-bottom: 1px solid #edf2f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content {
|
||||||
|
min-height: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content :deep(.w-e-text-container) {
|
||||||
|
min-height: 240px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content :deep(.w-e-text-placeholder) {
|
||||||
|
top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tip {
|
||||||
|
padding: 8px 12px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #64748b;
|
||||||
|
background: #f8fafc;
|
||||||
|
border-top: 1px solid #edf2f7;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<div>
|
<div>
|
||||||
<h3>合同模板配置中心</h3>
|
<h3>合同模板配置中心</h3>
|
||||||
<p>在线维护模板配置与变量映射,推荐在本地 Word 编辑正文后回传系统。</p>
|
<p>上传模板后自动识别 `{中文变量}` 占位符,并为每个变量配置录入类型、展示名称和数据源。</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -33,18 +33,11 @@
|
|||||||
<a-card size="small" title="基本信息" class="panel-card">
|
<a-card size="small" title="基本信息" class="panel-card">
|
||||||
<div class="field-grid field-grid-2">
|
<div class="field-grid field-grid-2">
|
||||||
<a-form-item label="范本名称" name="templateName">
|
<a-form-item label="范本名称" name="templateName">
|
||||||
<a-input
|
<a-input v-model:value="formState.templateName" placeholder="请输入范本名称" />
|
||||||
v-model:value="formState.templateName"
|
|
||||||
placeholder="请输入范本名称"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item label="范本编号" name="templateCode">
|
<a-form-item label="范本编号" name="templateCode">
|
||||||
<a-input
|
<a-input v-model:value="formState.templateCode" placeholder="保存后自动生成" readonly />
|
||||||
v-model:value="formState.templateCode"
|
|
||||||
placeholder="保存后自动生成"
|
|
||||||
readonly
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item label="范本类型" name="source">
|
<a-form-item label="范本类型" name="source">
|
||||||
@@ -62,11 +55,9 @@
|
|||||||
placeholder="请选择合同类型"
|
placeholder="请选择合同类型"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item label="版本号" name="version">
|
<a-form-item label="版本号" name="version">
|
||||||
<a-input
|
<a-input v-model:value="formState.version" placeholder="例如 V1.0" />
|
||||||
v-model:value="formState.version"
|
|
||||||
placeholder="例如 V1.0"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item label="发布范围" name="publishOrgIds" class="field-span-2">
|
<a-form-item label="发布范围" name="publishOrgIds" class="field-span-2">
|
||||||
@@ -102,20 +93,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<a-card size="small" title="模板文件与配置预览" class="panel-card">
|
<a-card size="small" title="模板文件与识别结果" class="panel-card">
|
||||||
<a-alert
|
<a-alert
|
||||||
type="info"
|
type="info"
|
||||||
show-icon
|
show-icon
|
||||||
class="workflow-alert"
|
class="workflow-alert"
|
||||||
message="推荐维护方式"
|
message="维护建议"
|
||||||
description="下载当前模板到本地 Word 编辑正文与占位符,保存后重新上传回传;平台负责变量识别、映射、预览与发布。"
|
description="富文本变量建议单独占一行或单独放在表格单元格内,这样后续渲染表格和多段文字会更稳。"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="upload-meta">
|
<div class="upload-meta">
|
||||||
<div>
|
<div>
|
||||||
<div class="meta-label">当前模板文件</div>
|
<div class="meta-label">当前模板文件</div>
|
||||||
<div class="meta-value">
|
<div class="meta-value">{{ formState.templateFileName || '尚未上传 .docx 模板文件' }}</div>
|
||||||
{{ formState.templateFileName || '尚未上传 .docx 模板文件' }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a-space v-if="!isViewMode">
|
<a-space v-if="!isViewMode">
|
||||||
@@ -123,7 +113,7 @@
|
|||||||
<DownloadOutlined />
|
<DownloadOutlined />
|
||||||
下载当前模板
|
下载当前模板
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button @click="handleReDetectVariables">
|
<a-button @click="handleReDetectVariables" :disabled="!templateArrayBuffer">
|
||||||
<ReloadOutlined />
|
<ReloadOutlined />
|
||||||
重新识别变量
|
重新识别变量
|
||||||
</a-button>
|
</a-button>
|
||||||
@@ -148,22 +138,20 @@
|
|||||||
<FileWordOutlined />
|
<FileWordOutlined />
|
||||||
</p>
|
</p>
|
||||||
<p class="ant-upload-text">上传 Word 模板文件(支持 `.docx`)</p>
|
<p class="ant-upload-text">上传 Word 模板文件(支持 `.docx`)</p>
|
||||||
<p class="ant-upload-hint">
|
<p class="ant-upload-hint">上传后自动识别 `{合同名称}`、`{附件一内容}` 这类花括号变量。</p>
|
||||||
上传后会自动识别花括号变量,如 `{contractName}`、`{partyAName}`,并生成变量匹配清单。
|
<p class="ant-upload-hint">推荐先在本地 Word 调整正文,再上传到平台做变量配置。</p>
|
||||||
</p>
|
|
||||||
<p class="ant-upload-hint">
|
|
||||||
如需修改正文内容,建议先下载模板到本地 Word 编辑后再重新上传回传。
|
|
||||||
</p>
|
|
||||||
</a-upload-dragger>
|
</a-upload-dragger>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<a-card size="small" title="占位符工具栏与变量映射" class="panel-card">
|
<a-card size="small" title="变量映射与录入类型" class="panel-card">
|
||||||
<div class="variable-header">
|
<div class="variable-header">
|
||||||
<div>
|
<div>
|
||||||
<div class="meta-label">已识别变量</div>
|
<div class="meta-label">已识别变量</div>
|
||||||
<div class="meta-value">{{ detectedVariableKeys.length ? detectedVariableKeys.join('、') : '暂未识别到变量' }}</div>
|
<div class="meta-value">
|
||||||
|
{{ detectedVariableKeys.length ? detectedVariableKeys.join('、') : '暂未识别到变量' }}
|
||||||
|
</div>
|
||||||
<div class="catalog-help">
|
<div class="catalog-help">
|
||||||
点击下方字段标签可直接复制占位符,点击“加入映射”可快速补充变量绑定。
|
每个变量都要配置展示名称和录入类型。下拉变量需要填写字典类型,富文本变量支持文字和表格。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a-space>
|
<a-space>
|
||||||
@@ -178,33 +166,13 @@
|
|||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="catalog-wrap">
|
<a-alert
|
||||||
<div class="catalog-title">占位符工具栏</div>
|
type="warning"
|
||||||
<div class="catalog-list">
|
show-icon
|
||||||
<div
|
class="workflow-alert"
|
||||||
v-for="item in templateFieldList"
|
message="富文本变量说明"
|
||||||
:key="item.value"
|
description="富文本变量最终会替换为 Word 正文内容,支持多段文本和表格。请尽量把富文本占位符单独放在一行。"
|
||||||
class="catalog-item"
|
/>
|
||||||
>
|
|
||||||
<a-tag
|
|
||||||
color="blue"
|
|
||||||
class="catalog-tag"
|
|
||||||
@click="handleCopyPlaceholder(item.value)"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</a-tag>
|
|
||||||
<a-button
|
|
||||||
v-if="!isViewMode"
|
|
||||||
type="link"
|
|
||||||
size="small"
|
|
||||||
class="catalog-action"
|
|
||||||
@click.stop="handleQuickAddCatalogField(item.value)"
|
|
||||||
>
|
|
||||||
加入映射
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div v-if="variableMappings.length" class="mapping-list">
|
<div v-if="variableMappings.length" class="mapping-list">
|
||||||
<div
|
<div
|
||||||
@@ -230,31 +198,81 @@
|
|||||||
<a-input
|
<a-input
|
||||||
v-model:value="item.variableKey"
|
v-model:value="item.variableKey"
|
||||||
:disabled="isViewMode"
|
:disabled="isViewMode"
|
||||||
placeholder="例如 contractName"
|
placeholder="例如 合同名称、附件一内容"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item label="匹配业务字段">
|
<a-form-item label="匹配业务字段">
|
||||||
<a-select
|
<a-auto-complete
|
||||||
v-model:value="item.bindField"
|
v-model:value="item.bindField"
|
||||||
:options="templateFieldOptions"
|
:options="templateFieldAutoOptions"
|
||||||
:disabled="isViewMode"
|
:disabled="isViewMode"
|
||||||
placeholder="请选择业务字段"
|
placeholder="请选择或直接输入业务字段编码"
|
||||||
|
allow-clear
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="展示名称">
|
||||||
|
<a-input
|
||||||
|
v-model:value="item.fieldLabel"
|
||||||
|
:disabled="isViewMode"
|
||||||
|
placeholder="合同发起页表单展示名称"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="录入类型">
|
||||||
|
<a-select
|
||||||
|
v-model:value="item.fieldType"
|
||||||
|
:options="fieldTypeOptions"
|
||||||
|
:disabled="isViewMode"
|
||||||
|
placeholder="请选择录入类型"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="是否必填">
|
||||||
|
<a-switch
|
||||||
|
v-model:checked="item.required"
|
||||||
|
:disabled="isViewMode"
|
||||||
|
checked-children="必填"
|
||||||
|
un-checked-children="选填"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="输入提示">
|
||||||
|
<a-input
|
||||||
|
v-model:value="item.placeholder"
|
||||||
|
:disabled="isViewMode"
|
||||||
|
placeholder="可选,例如 请输入附件一内容"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item v-if="item.fieldType === 'select'" label="字典类型" class="field-span-2">
|
||||||
|
<a-auto-complete
|
||||||
|
v-model:value="item.dictType"
|
||||||
|
:options="dictTypePresetOptions"
|
||||||
|
:disabled="isViewMode"
|
||||||
|
placeholder="例如 orgBusType、contractPayMethod"
|
||||||
|
allow-clear
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="备注" class="field-span-2">
|
||||||
|
<a-input
|
||||||
|
v-model:value="item.remark"
|
||||||
|
:disabled="isViewMode"
|
||||||
|
placeholder="可选,说明该变量的填写要求"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a-empty
|
<a-empty v-else description="暂无变量匹配项" />
|
||||||
v-else
|
|
||||||
description="暂无变量匹配项"
|
|
||||||
/>
|
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<a-card size="small" title="维护信息" class="panel-card">
|
<a-card size="small" title="维护信息" class="panel-card">
|
||||||
<div class="field-grid field-grid-2">
|
<div class="field-grid field-grid-2">
|
||||||
<a-form-item label="创建人">
|
<a-form-item label="维护人">
|
||||||
<a-input v-model:value="formState.updatedBy" disabled />
|
<a-input v-model:value="formState.updatedBy" disabled />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="创建时间">
|
<a-form-item label="创建时间">
|
||||||
@@ -269,12 +287,8 @@
|
|||||||
<a-space>
|
<a-space>
|
||||||
<a-button @click="visible = false">关闭</a-button>
|
<a-button @click="visible = false">关闭</a-button>
|
||||||
<template v-if="!isViewMode">
|
<template v-if="!isViewMode">
|
||||||
<a-button @click="handleSubmit('draft')">
|
<a-button @click="handleSubmit('draft')">保存</a-button>
|
||||||
保存
|
<a-button type="primary" @click="handleSubmit('published')">发布</a-button>
|
||||||
</a-button>
|
|
||||||
<a-button type="primary" @click="handleSubmit('published')">
|
|
||||||
发布
|
|
||||||
</a-button>
|
|
||||||
</template>
|
</template>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
@@ -284,7 +298,7 @@
|
|||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<div>
|
<div>
|
||||||
<h3>模板预览</h3>
|
<h3>模板预览</h3>
|
||||||
<p>右侧基于当前变量映射渲染模板效果,用于检查占位符位置与展示结果,本页不直接在线修改 Word 正文。</p>
|
<p>右侧用变量展示名模拟填充效果,帮助检查占位符是否识别正确。</p>
|
||||||
</div>
|
</div>
|
||||||
<a-space size="small">
|
<a-space size="small">
|
||||||
<a-tag color="geekblue">{{ formState.source || '未分类' }}</a-tag>
|
<a-tag color="geekblue">{{ formState.source || '未分类' }}</a-tag>
|
||||||
@@ -295,7 +309,7 @@
|
|||||||
<div class="preview-shell">
|
<div class="preview-shell">
|
||||||
<div v-if="!templateArrayBuffer" class="preview-state">
|
<div v-if="!templateArrayBuffer" class="preview-state">
|
||||||
<FileWordOutlined style="font-size: 42px; color: #94a3b8" />
|
<FileWordOutlined style="font-size: 42px; color: #94a3b8" />
|
||||||
<p>上传 `.docx` 模板文件后,这里会显示填充后的预览;正文修改建议在本地 Word 完成后回传。</p>
|
<p>上传 `.docx` 模板文件后,这里会显示填充预览。</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-else ref="previewRef" class="preview-stage"></div>
|
<div v-else ref="previewRef" class="preview-stage"></div>
|
||||||
<div v-if="rendering" class="preview-state preview-mask">
|
<div v-if="rendering" class="preview-state preview-mask">
|
||||||
@@ -334,16 +348,23 @@ import {
|
|||||||
import { contractTypeTreeOptions } from '../contractTypeOptions.js'
|
import { contractTypeTreeOptions } from '../contractTypeOptions.js'
|
||||||
import {
|
import {
|
||||||
buildTemplateFieldLabelMap,
|
buildTemplateFieldLabelMap,
|
||||||
buildTemplateFieldOptions,
|
|
||||||
loadTemplateFieldList,
|
loadTemplateFieldList,
|
||||||
} from '../../shared/templateFieldDict.js'
|
} from '../../shared/templateFieldDict.js'
|
||||||
|
import {
|
||||||
|
buildTemplatePreviewData,
|
||||||
|
} from '../../shared/templateDocxRenderer.js'
|
||||||
|
import {
|
||||||
|
createEmptyTemplateVariableMapping,
|
||||||
|
normalizeTemplateVariableMapping,
|
||||||
|
TEMPLATE_FIELD_TYPE_OPTIONS,
|
||||||
|
} from '../../shared/templateVariableConfig.js'
|
||||||
|
import {
|
||||||
|
loadDictTypeOptions,
|
||||||
|
buildDictTypeSelectOptions,
|
||||||
|
} from '../../shared/dictTypeOptions.js'
|
||||||
|
|
||||||
// ========== 模板管理字典(后续可由后端接口替换) ==========
|
|
||||||
|
|
||||||
// 合同类型选项
|
|
||||||
const contractTypeOptions = contractTypeTreeOptions
|
const contractTypeOptions = contractTypeTreeOptions
|
||||||
|
|
||||||
// 范本类型选项
|
|
||||||
const templateSourceOptions = [
|
const templateSourceOptions = [
|
||||||
{ label: '标准模板', value: '标准模板' },
|
{ label: '标准模板', value: '标准模板' },
|
||||||
{ label: '推荐文本', value: '推荐文本' },
|
{ label: '推荐文本', value: '推荐文本' },
|
||||||
@@ -351,13 +372,8 @@ const templateSourceOptions = [
|
|||||||
{ label: '对方文本', value: '对方文本' },
|
{ label: '对方文本', value: '对方文本' },
|
||||||
]
|
]
|
||||||
|
|
||||||
// 批量创建变量映射
|
|
||||||
function createSimpleVariableList(list = []) {
|
function createSimpleVariableList(list = []) {
|
||||||
return list.map((item, index) => ({
|
return list.map((item, index) => normalizeTemplateVariableMapping(item, index))
|
||||||
id: item.id || `var_${Date.now()}_${index}`,
|
|
||||||
variableKey: item.variableKey || '',
|
|
||||||
bindField: item.bindField || '',
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['submit'])
|
const emit = defineEmits(['submit'])
|
||||||
@@ -379,14 +395,20 @@ const templateFieldList = ref([])
|
|||||||
let previewTimer = null
|
let previewTimer = null
|
||||||
let renderTaskId = 0
|
let renderTaskId = 0
|
||||||
|
|
||||||
const templateFieldOptions = computed(() =>
|
|
||||||
buildTemplateFieldOptions(templateFieldList.value),
|
|
||||||
)
|
|
||||||
|
|
||||||
const templateFieldLabelMap = computed(() =>
|
const templateFieldLabelMap = computed(() =>
|
||||||
buildTemplateFieldLabelMap(templateFieldList.value),
|
buildTemplateFieldLabelMap(templateFieldList.value),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const templateFieldAutoOptions = computed(() =>
|
||||||
|
(templateFieldList.value || []).map((item) => ({
|
||||||
|
value: item.value,
|
||||||
|
label: `${item.label}(${item.value})`,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
|
||||||
|
const fieldTypeOptions = TEMPLATE_FIELD_TYPE_OPTIONS
|
||||||
|
const dictTypePresetOptions = ref([])
|
||||||
|
|
||||||
const formRules = {
|
const formRules = {
|
||||||
templateName: [{ required: true, message: '请输入范本名称', trigger: 'blur' }],
|
templateName: [{ required: true, message: '请输入范本名称', trigger: 'blur' }],
|
||||||
source: [{ required: true, message: '请选择范本类型', trigger: 'change' }],
|
source: [{ required: true, message: '请选择范本类型', trigger: 'change' }],
|
||||||
@@ -446,6 +468,11 @@ watch(
|
|||||||
variableMappings.value.map((item) => ({
|
variableMappings.value.map((item) => ({
|
||||||
variableKey: item.variableKey,
|
variableKey: item.variableKey,
|
||||||
bindField: item.bindField,
|
bindField: item.bindField,
|
||||||
|
fieldLabel: item.fieldLabel,
|
||||||
|
fieldType: item.fieldType,
|
||||||
|
required: item.required,
|
||||||
|
dictType: item.dictType,
|
||||||
|
placeholder: item.placeholder,
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
() => {
|
() => {
|
||||||
@@ -520,7 +547,6 @@ function resolveUploadedFilePath(res) {
|
|||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function extractVariablesFromText(text) {
|
function extractVariablesFromText(text) {
|
||||||
const result = new Set()
|
const result = new Set()
|
||||||
const regex = /\{+\s*([^{}\s]+)\s*\}+/g
|
const regex = /\{+\s*([^{}\s]+)\s*\}+/g
|
||||||
@@ -543,11 +569,17 @@ function mergeDetectedVariables(variableKeys) {
|
|||||||
|
|
||||||
const detectedRows = nextKeys.map((variableKey) => {
|
const detectedRows = nextKeys.map((variableKey) => {
|
||||||
const existing = existingMap.get(variableKey)
|
const existing = existingMap.get(variableKey)
|
||||||
return {
|
return normalizeTemplateVariableMapping({
|
||||||
id: existing?.id || `var_${Date.now()}_${variableKey}`,
|
id: existing?.id || `var_${Date.now()}_${variableKey}`,
|
||||||
variableKey,
|
variableKey,
|
||||||
bindField: existing?.bindField || variableKey,
|
bindField: existing?.bindField || variableKey,
|
||||||
}
|
fieldLabel: existing?.fieldLabel || variableKey,
|
||||||
|
fieldType: existing?.fieldType || 'input',
|
||||||
|
required: existing?.required !== false,
|
||||||
|
placeholder: existing?.placeholder || '',
|
||||||
|
dictType: existing?.dictType || '',
|
||||||
|
remark: existing?.remark || '',
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const manualRows = variableMappings.value
|
const manualRows = variableMappings.value
|
||||||
@@ -575,7 +607,6 @@ async function detectVariablesFromBuffer(buffer) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
mergeDetectedVariables([...allVariables])
|
mergeDetectedVariables([...allVariables])
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.warning('模板文件已上传,但变量自动识别失败,请手动维护变量')
|
message.warning('模板文件已上传,但变量自动识别失败,请手动维护变量')
|
||||||
}
|
}
|
||||||
@@ -649,22 +680,8 @@ async function handleReDetectVariables() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleAddManualVariable() {
|
function handleAddManualVariable() {
|
||||||
variableMappings.value.push({
|
|
||||||
id: `var_${Date.now()}_${variableMappings.value.length + 1}`,
|
|
||||||
variableKey: '',
|
|
||||||
bindField: '',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleQuickAddCatalogField(fieldKey) {
|
|
||||||
if (isViewMode.value) return
|
|
||||||
|
|
||||||
variableMappings.value.push(
|
variableMappings.value.push(
|
||||||
{
|
createEmptyTemplateVariableMapping(variableMappings.value.length + 1),
|
||||||
id: `var_${Date.now()}_${fieldKey}`,
|
|
||||||
variableKey: fieldKey,
|
|
||||||
bindField: fieldKey,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,47 +689,12 @@ function buildPlaceholderText(fieldKey) {
|
|||||||
return `{${fieldKey}}`
|
return `{${fieldKey}}`
|
||||||
}
|
}
|
||||||
|
|
||||||
async function copyTextToClipboard(text) {
|
|
||||||
if (navigator?.clipboard?.writeText) {
|
|
||||||
await navigator.clipboard.writeText(text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const textarea = document.createElement('textarea')
|
|
||||||
textarea.value = text
|
|
||||||
textarea.setAttribute('readonly', 'readonly')
|
|
||||||
textarea.style.position = 'fixed'
|
|
||||||
textarea.style.left = '-9999px'
|
|
||||||
document.body.appendChild(textarea)
|
|
||||||
textarea.select()
|
|
||||||
document.execCommand('copy')
|
|
||||||
document.body.removeChild(textarea)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleCopyPlaceholder(fieldKey) {
|
|
||||||
const placeholder = buildPlaceholderText(fieldKey)
|
|
||||||
try {
|
|
||||||
await copyTextToClipboard(placeholder)
|
|
||||||
message.success(`已复制占位符:${placeholder}`)
|
|
||||||
} catch (error) {
|
|
||||||
message.warning(`复制失败,请手动使用占位符:${placeholder}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeVariable(id) {
|
function removeVariable(id) {
|
||||||
variableMappings.value = variableMappings.value.filter((item) => item.id !== id)
|
variableMappings.value = variableMappings.value.filter((item) => item.id !== id)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildPreviewData() {
|
function buildPreviewData() {
|
||||||
const data = {}
|
return buildTemplatePreviewData(variableMappings.value, templateFieldLabelMap.value)
|
||||||
variableMappings.value.forEach((item) => {
|
|
||||||
if (!item.variableKey) return
|
|
||||||
data[item.variableKey] =
|
|
||||||
templateFieldLabelMap.value[item.bindField] ||
|
|
||||||
item.bindField ||
|
|
||||||
`[${item.variableKey}]`
|
|
||||||
})
|
|
||||||
return data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function renderPreview() {
|
async function renderPreview() {
|
||||||
@@ -796,9 +778,9 @@ function buildRecord(status) {
|
|||||||
variables: variableMappings.value
|
variables: variableMappings.value
|
||||||
.filter((item) => item.variableKey)
|
.filter((item) => item.variableKey)
|
||||||
.map((item) => item.variableKey),
|
.map((item) => item.variableKey),
|
||||||
variableMappings: variableMappings.value.map((item) => ({
|
variableMappings: variableMappings.value.map((item, index) =>
|
||||||
...item,
|
normalizeTemplateVariableMapping(item, index),
|
||||||
})),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,6 +806,18 @@ function validateVariableMappings() {
|
|||||||
if (!item.bindField) {
|
if (!item.bindField) {
|
||||||
return `请为变量【${item.variableKey}】选择匹配业务字段`
|
return `请为变量【${item.variableKey}】选择匹配业务字段`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!item.fieldLabel) {
|
||||||
|
return `请为变量【${item.variableKey}】填写展示名称`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.fieldType) {
|
||||||
|
return `请为变量【${item.variableKey}】选择录入类型`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.fieldType === 'select' && !item.dictType) {
|
||||||
|
return `请为下拉变量【${item.variableKey}】配置字典类型`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
@@ -888,13 +882,18 @@ function buildVariableGuideText() {
|
|||||||
'',
|
'',
|
||||||
'推荐维护方式:',
|
'推荐维护方式:',
|
||||||
'1. 下载当前模板到本地 Word 编辑正文内容。',
|
'1. 下载当前模板到本地 Word 编辑正文内容。',
|
||||||
'2. 在正文中插入占位符,例如 {contractName}、{partyAName}。',
|
'2. 在正文中插入占位符,例如 {合同名称}、{附件一内容}。',
|
||||||
'3. 保存后重新上传 .docx 文件回传系统。',
|
'3. 保存后重新上传 .docx 文件回传系统。',
|
||||||
'4. 在平台内完成变量识别、字段映射、预览和发布。',
|
'4. 在平台内为每个变量配置展示名称、录入类型和数据源。',
|
||||||
'',
|
'',
|
||||||
'可用占位符清单:',
|
'录入类型说明:',
|
||||||
|
'- 输入框:普通文本输入。',
|
||||||
|
'- 下拉框:需配置 dictType,例如 orgBusType。',
|
||||||
|
'- 富文本:支持多段文本与表格,建议占位符单独成段。',
|
||||||
|
'',
|
||||||
|
'可用业务字段参考:',
|
||||||
...templateFieldList.value.map(
|
...templateFieldList.value.map(
|
||||||
(item) => `- ${item.label}: ${buildPlaceholderText(item.value)}`,
|
(item) => `- ${item.label}: ${item.value}`,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -942,9 +941,6 @@ async function handleDownloadCurrentTemplate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将后端组织树节点转为 a-tree-select 需要的格式
|
|
||||||
*/
|
|
||||||
function convertOrgTreeToTreeSelect(node) {
|
function convertOrgTreeToTreeSelect(node) {
|
||||||
const treeNode = {
|
const treeNode = {
|
||||||
value: String(node.id),
|
value: String(node.id),
|
||||||
@@ -956,9 +952,6 @@ function convertOrgTreeToTreeSelect(node) {
|
|||||||
return treeNode
|
return treeNode
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从树数据构建 orgId → orgName 的映射(递归遍历)
|
|
||||||
*/
|
|
||||||
function buildOrgNameMap(treeData) {
|
function buildOrgNameMap(treeData) {
|
||||||
const map = new Map()
|
const map = new Map()
|
||||||
function walk(list) {
|
function walk(list) {
|
||||||
@@ -976,6 +969,10 @@ async function showModal(record = {}, mode = 'create') {
|
|||||||
resetState()
|
resetState()
|
||||||
modalMode.value = mode || 'create'
|
modalMode.value = mode || 'create'
|
||||||
await ensureTemplateFieldListLoaded()
|
await ensureTemplateFieldListLoaded()
|
||||||
|
if (!dictTypePresetOptions.value.length) {
|
||||||
|
const list = await loadDictTypeOptions()
|
||||||
|
dictTypePresetOptions.value = buildDictTypeSelectOptions(list)
|
||||||
|
}
|
||||||
if (!orgTreeData.value.length) {
|
if (!orgTreeData.value.length) {
|
||||||
const tree = await getOrgTree()
|
const tree = await getOrgTree()
|
||||||
orgTreeData.value = (tree || []).map(convertOrgTreeToTreeSelect)
|
orgTreeData.value = (tree || []).map(convertOrgTreeToTreeSelect)
|
||||||
@@ -1017,7 +1014,6 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 详情模式下禁用表单文字颜色加深 */
|
|
||||||
.view-form:deep(.ant-select-disabled .ant-select-selection-item) {
|
.view-form:deep(.ant-select-disabled .ant-select-selection-item) {
|
||||||
color: rgba(0, 0, 0, 0.85) !important;
|
color: rgba(0, 0, 0, 0.85) !important;
|
||||||
}
|
}
|
||||||
@@ -1028,20 +1024,6 @@ defineExpose({
|
|||||||
color: rgba(0, 0, 0, 0.85) !important;
|
color: rgba(0, 0, 0, 0.85) !important;
|
||||||
-webkit-text-fill-color: rgba(0, 0, 0, 0.85) !important;
|
-webkit-text-fill-color: rgba(0, 0, 0, 0.85) !important;
|
||||||
}
|
}
|
||||||
.view-form:deep(.ant-input-number-disabled .ant-input-number-input) {
|
|
||||||
color: rgba(0, 0, 0, 0.85) !important;
|
|
||||||
-webkit-text-fill-color: rgba(0, 0, 0, 0.85) !important;
|
|
||||||
}
|
|
||||||
.view-form:deep(.ant-picker.ant-picker-disabled .ant-picker-input input) {
|
|
||||||
color: rgba(0, 0, 0, 0.85) !important;
|
|
||||||
-webkit-text-fill-color: rgba(0, 0, 0, 0.85) !important;
|
|
||||||
}
|
|
||||||
.view-form:deep(.ant-radio-wrapper.ant-radio-wrapper-disabled .ant-radio + span) {
|
|
||||||
color: rgba(0, 0, 0, 0.85) !important;
|
|
||||||
}
|
|
||||||
.view-form:deep(.ant-checkbox-wrapper.ant-checkbox-wrapper-disabled .ant-checkbox + span) {
|
|
||||||
color: rgba(0, 0, 0, 0.85) !important;
|
|
||||||
}
|
|
||||||
.view-form:deep(.ant-input-disabled) {
|
.view-form:deep(.ant-input-disabled) {
|
||||||
color: rgba(0, 0, 0, 0.85) !important;
|
color: rgba(0, 0, 0, 0.85) !important;
|
||||||
-webkit-text-fill-color: rgba(0, 0, 0, 0.85) !important;
|
-webkit-text-fill-color: rgba(0, 0, 0, 0.85) !important;
|
||||||
@@ -1049,7 +1031,7 @@ defineExpose({
|
|||||||
|
|
||||||
.template-manage-modal {
|
.template-manage-modal {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 560px minmax(0, 1fr);
|
grid-template-columns: 580px minmax(0, 1fr);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
@@ -1157,21 +1139,6 @@ defineExpose({
|
|||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.catalog-wrap {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding: 12px 14px;
|
|
||||||
border-radius: 12px;
|
|
||||||
background: #f8fbff;
|
|
||||||
border: 1px solid #e0eaf8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.catalog-title {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #334155;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.catalog-help {
|
.catalog-help {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@@ -1179,30 +1146,6 @@ defineExpose({
|
|||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.catalog-list {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.catalog-item {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 2px;
|
|
||||||
padding: 2px 4px;
|
|
||||||
border-radius: 999px;
|
|
||||||
background: rgba(255, 255, 255, 0.72);
|
|
||||||
}
|
|
||||||
|
|
||||||
.catalog-tag {
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.catalog-action {
|
|
||||||
padding-inline: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapping-list {
|
.mapping-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -1290,7 +1233,7 @@ defineExpose({
|
|||||||
|
|
||||||
@media (max-width: 1280px) {
|
@media (max-width: 1280px) {
|
||||||
.template-manage-modal {
|
.template-manage-modal {
|
||||||
grid-template-columns: 520px minmax(0, 1fr);
|
grid-template-columns: 540px minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { getDictDataByType } from "@/api/dict.js";
|
||||||
|
|
||||||
|
export const TEMPLATE_DICT_TYPES_KEY = "TEMPLATE_DICT_TYPES";
|
||||||
|
|
||||||
|
let cachedDictTypeOptions = null;
|
||||||
|
|
||||||
|
function normalizeDictTypeList(list = []) {
|
||||||
|
return list
|
||||||
|
.map((item) => ({
|
||||||
|
label: item?.k || item?.label || "",
|
||||||
|
value: item?.v || item?.value || "",
|
||||||
|
remark: item?.remark || "",
|
||||||
|
}))
|
||||||
|
.filter((item) => item.label && item.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadDictTypeOptions() {
|
||||||
|
if (cachedDictTypeOptions?.length) {
|
||||||
|
return [...cachedDictTypeOptions];
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await getDictDataByType(TEMPLATE_DICT_TYPES_KEY);
|
||||||
|
cachedDictTypeOptions = normalizeDictTypeList(result);
|
||||||
|
return [...cachedDictTypeOptions];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildDictTypeSelectOptions(list = []) {
|
||||||
|
return list.map((item) => ({
|
||||||
|
label: item.label,
|
||||||
|
value: item.value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
@@ -0,0 +1,789 @@
|
|||||||
|
import Docxtemplater from 'docxtemplater'
|
||||||
|
import { DOMParser, XMLSerializer } from '@xmldom/xmldom'
|
||||||
|
import PizZip from 'pizzip'
|
||||||
|
|
||||||
|
const DOCX_MIME_TYPE =
|
||||||
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
||||||
|
|
||||||
|
const WORD_XML_FILE_REGEX = /^word\/(document|header\d+|footer\d+)\.xml$/i
|
||||||
|
const WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
|
||||||
|
const ELEMENT_NODE = 1
|
||||||
|
const TEXT_NODE = 3
|
||||||
|
const DEFAULT_WORD_TABLE_WIDTH_TWIPS = 9000
|
||||||
|
const DEFAULT_WORD_TABLE_WIDTH_PERCENT = 5000
|
||||||
|
const DEFAULT_TABLE_CELL_PADDING_TWIPS = 120
|
||||||
|
const DEFAULT_PARAGRAPH_SPACING_BEFORE = 40
|
||||||
|
const DEFAULT_PARAGRAPH_SPACING_AFTER = 40
|
||||||
|
const DEFAULT_PARAGRAPH_LINE = 300
|
||||||
|
|
||||||
|
export function buildTemplatePreviewData(variableMappings = [], templateFieldLabelMap = {}) {
|
||||||
|
const data = {}
|
||||||
|
;(variableMappings || []).forEach((item) => {
|
||||||
|
const variableKey = String(item?.variableKey || '').trim()
|
||||||
|
if (!variableKey) return
|
||||||
|
const fieldType = normalizeFieldType(item?.fieldType)
|
||||||
|
const fieldLabel = String(item?.fieldLabel || '').trim()
|
||||||
|
const bindField = String(item?.bindField || '').trim()
|
||||||
|
data[variableKey] =
|
||||||
|
fieldType === 'rich_text'
|
||||||
|
? `[富文本:${fieldLabel || variableKey}]`
|
||||||
|
: fieldType === 'select'
|
||||||
|
? `[下拉:${fieldLabel || variableKey}]`
|
||||||
|
: fieldLabel || templateFieldLabelMap[bindField] || bindField || `[${variableKey}]`
|
||||||
|
})
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function renderTemplateDocxBlob({
|
||||||
|
templateArrayBuffer,
|
||||||
|
variableMappings = [],
|
||||||
|
templateFieldValues = {},
|
||||||
|
}) {
|
||||||
|
if (!(templateArrayBuffer instanceof ArrayBuffer)) {
|
||||||
|
throw new Error('模板文件尚未加载完成')
|
||||||
|
}
|
||||||
|
|
||||||
|
const zip = new PizZip(templateArrayBuffer.slice(0))
|
||||||
|
const richMappings = (variableMappings || []).filter(
|
||||||
|
(item) => normalizeFieldType(item?.fieldType) === 'rich_text',
|
||||||
|
)
|
||||||
|
|
||||||
|
if (richMappings.length) {
|
||||||
|
transformRichTextPlaceholders(zip, richMappings)
|
||||||
|
}
|
||||||
|
|
||||||
|
const doc = new Docxtemplater(zip, {
|
||||||
|
paragraphLoop: true,
|
||||||
|
linebreaks: true,
|
||||||
|
nullGetter() {
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
doc.render(buildTemplateRenderData(variableMappings, templateFieldValues))
|
||||||
|
|
||||||
|
return doc.getZip().generate({
|
||||||
|
type: 'blob',
|
||||||
|
mimeType: DOCX_MIME_TYPE,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildTemplateRenderData(variableMappings = [], templateFieldValues = {}) {
|
||||||
|
const renderData = {}
|
||||||
|
;(variableMappings || []).forEach((item) => {
|
||||||
|
const variableKey = String(item?.variableKey || '').trim()
|
||||||
|
if (!variableKey) return
|
||||||
|
|
||||||
|
const bindField = String(item?.bindField || variableKey).trim()
|
||||||
|
const fieldType = normalizeFieldType(item?.fieldType)
|
||||||
|
const rawValue = templateFieldValues?.[bindField]
|
||||||
|
|
||||||
|
renderData[variableKey] =
|
||||||
|
fieldType === 'rich_text'
|
||||||
|
? buildRichTextWordXml(rawValue)
|
||||||
|
: stringifyPlainTemplateValue(rawValue)
|
||||||
|
})
|
||||||
|
return renderData
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformRichTextPlaceholders(zip, richMappings = []) {
|
||||||
|
const richPlaceholderSet = new Set(
|
||||||
|
richMappings
|
||||||
|
.map((item) => String(item?.variableKey || '').trim())
|
||||||
|
.filter(Boolean),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!richPlaceholderSet.size) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(zip.files)
|
||||||
|
.filter((name) => WORD_XML_FILE_REGEX.test(name))
|
||||||
|
.forEach((name) => {
|
||||||
|
const xmlText = zip.files[name].asText()
|
||||||
|
const parser = new DOMParser()
|
||||||
|
const xmlDoc = parser.parseFromString(xmlText, 'application/xml')
|
||||||
|
const paragraphs = xmlDoc.getElementsByTagNameNS(WORD_NAMESPACE, 'p')
|
||||||
|
let changed = false
|
||||||
|
|
||||||
|
Array.from(paragraphs).forEach((paragraph) => {
|
||||||
|
const text = getParagraphText(paragraph).trim()
|
||||||
|
if (!text.startsWith('{') || !text.endsWith('}')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const variableKey = text.slice(1, -1).trim()
|
||||||
|
if (!richPlaceholderSet.has(variableKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rewriteParagraphAsRawTag(xmlDoc, paragraph, variableKey)
|
||||||
|
changed = true
|
||||||
|
})
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
zip.file(name, new XMLSerializer().serializeToString(xmlDoc))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParagraphText(paragraphNode) {
|
||||||
|
const textNodes = paragraphNode.getElementsByTagNameNS(WORD_NAMESPACE, 't')
|
||||||
|
return Array.from(textNodes)
|
||||||
|
.map((node) => node.textContent || '')
|
||||||
|
.join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewriteParagraphAsRawTag(xmlDoc, paragraphNode, variableKey) {
|
||||||
|
const paragraphProps = paragraphNode.getElementsByTagNameNS(WORD_NAMESPACE, 'pPr')[0]
|
||||||
|
while (paragraphNode.firstChild) {
|
||||||
|
paragraphNode.removeChild(paragraphNode.firstChild)
|
||||||
|
}
|
||||||
|
if (paragraphProps) {
|
||||||
|
paragraphNode.appendChild(paragraphProps.cloneNode(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
const runNode = xmlDoc.createElementNS(WORD_NAMESPACE, 'w:r')
|
||||||
|
const textNode = xmlDoc.createElementNS(WORD_NAMESPACE, 'w:t')
|
||||||
|
textNode.appendChild(xmlDoc.createTextNode(`{@${variableKey}}`))
|
||||||
|
runNode.appendChild(textNode)
|
||||||
|
paragraphNode.appendChild(runNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRichTextWordXml(htmlValue) {
|
||||||
|
const html = String(htmlValue || '').trim()
|
||||||
|
if (!html) {
|
||||||
|
return '<w:p><w:r><w:t></w:t></w:r></w:p>'
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new DOMParser()
|
||||||
|
const htmlDoc = parser.parseFromString(`<html><body><div>${html}</div></body></html>`, 'text/html')
|
||||||
|
const bodyNode = htmlDoc.getElementsByTagName('body')[0]
|
||||||
|
const root = firstElementChild(bodyNode) || bodyNode
|
||||||
|
const blocks = []
|
||||||
|
|
||||||
|
collectBlocksFromChildren(root?.childNodes || [], blocks)
|
||||||
|
|
||||||
|
if (!blocks.length) {
|
||||||
|
const paragraph = buildParagraphXml(flattenNodeText(root).trim())
|
||||||
|
return paragraph || '<w:p><w:r><w:t></w:t></w:r></w:p>'
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks.join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectBlocksFromChildren(nodeList, blocks, baseStyle = {}) {
|
||||||
|
Array.from(nodeList || []).forEach((node) => {
|
||||||
|
if (node.nodeType === TEXT_NODE) {
|
||||||
|
const text = normalizeText(node.data || node.nodeValue || '')
|
||||||
|
if (text) {
|
||||||
|
blocks.push(buildParagraphXml(text, baseStyle))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.nodeType !== ELEMENT_NODE) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const tag = String(node.tagName || '').toLowerCase()
|
||||||
|
if (tag === 'table') {
|
||||||
|
blocks.push(buildTableXml(node))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (['p', 'div', 'section', 'article', 'blockquote'].includes(tag)) {
|
||||||
|
const paragraphXml = buildParagraphXmlFromNode(node, baseStyle)
|
||||||
|
if (paragraphXml) {
|
||||||
|
blocks.push(paragraphXml)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)) {
|
||||||
|
const paragraphXml = buildParagraphXmlFromNode(node, { ...baseStyle, bold: true })
|
||||||
|
if (paragraphXml) {
|
||||||
|
blocks.push(paragraphXml)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (['ul', 'ol'].includes(tag)) {
|
||||||
|
childElements(node).forEach((child) => {
|
||||||
|
const line = flattenNodeText(child).trim()
|
||||||
|
if (line) {
|
||||||
|
blocks.push(buildParagraphXml(`• ${line}`, baseStyle))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (tag === 'br') {
|
||||||
|
blocks.push(buildParagraphXml('', baseStyle))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const paragraphXml = buildParagraphXmlFromNode(node, baseStyle)
|
||||||
|
if (paragraphXml) {
|
||||||
|
blocks.push(paragraphXml)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildParagraphXmlFromNode(node, extraStyle = {}) {
|
||||||
|
const mergedStyle = mergeTextStyle(extraStyle, parseNodeStyleInfo(node))
|
||||||
|
const segments = []
|
||||||
|
collectInlineSegments(node, mergedStyle, segments)
|
||||||
|
return buildParagraphXmlBySegments(segments, mergedStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectInlineSegments(node, style = {}, segments = []) {
|
||||||
|
Array.from(node?.childNodes || []).forEach((child) => {
|
||||||
|
if (child.nodeType === TEXT_NODE) {
|
||||||
|
const text = normalizeText(child.data || child.nodeValue || '')
|
||||||
|
if (text) {
|
||||||
|
segments.push({
|
||||||
|
text,
|
||||||
|
bold: !!style.bold,
|
||||||
|
italic: !!style.italic,
|
||||||
|
underline: !!style.underline,
|
||||||
|
color: style.color || '',
|
||||||
|
bgColor: style.bgColor || '',
|
||||||
|
break: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.nodeType !== ELEMENT_NODE) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const tag = String(child.tagName || '').toLowerCase()
|
||||||
|
if (tag === 'br') {
|
||||||
|
segments.push({ break: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const childStyle = parseNodeStyleInfo(child)
|
||||||
|
const nextStyle = mergeTextStyle(style, {
|
||||||
|
bold: !!style.bold || ['b', 'strong'].includes(tag),
|
||||||
|
italic: !!style.italic || ['i', 'em'].includes(tag),
|
||||||
|
underline: !!style.underline || tag === 'u',
|
||||||
|
color: childStyle.color,
|
||||||
|
bgColor: childStyle.bgColor,
|
||||||
|
align: childStyle.align,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (tag === 'table') {
|
||||||
|
const tableText = flattenNodeText(child).trim()
|
||||||
|
if (tableText) {
|
||||||
|
segments.push({
|
||||||
|
text: tableText,
|
||||||
|
bold: nextStyle.bold,
|
||||||
|
italic: nextStyle.italic,
|
||||||
|
underline: nextStyle.underline,
|
||||||
|
color: nextStyle.color || '',
|
||||||
|
bgColor: nextStyle.bgColor || '',
|
||||||
|
break: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
collectInlineSegments(child, nextStyle, segments)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildParagraphXml(text = '', style = {}) {
|
||||||
|
const normalized = typeof text === 'string' ? text : ''
|
||||||
|
return buildParagraphXmlBySegments(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: normalized,
|
||||||
|
bold: !!style.bold,
|
||||||
|
italic: !!style.italic,
|
||||||
|
underline: !!style.underline,
|
||||||
|
color: style.color || '',
|
||||||
|
bgColor: style.bgColor || '',
|
||||||
|
break: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
style,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildParagraphXmlBySegments(segments = [], paragraphStyle = {}) {
|
||||||
|
const validSegments = segments.filter((item) => item.break || item.text !== undefined)
|
||||||
|
if (!validSegments.length) {
|
||||||
|
return '<w:p><w:r><w:t></w:t></w:r></w:p>'
|
||||||
|
}
|
||||||
|
|
||||||
|
const runXml = validSegments
|
||||||
|
.map((item) => {
|
||||||
|
if (item.break) {
|
||||||
|
return '<w:r><w:br/></w:r>'
|
||||||
|
}
|
||||||
|
const text = escapeXml(String(item.text || ''))
|
||||||
|
const runProps = []
|
||||||
|
if (item.bold) runProps.push('<w:b/>')
|
||||||
|
if (item.italic) runProps.push('<w:i/>')
|
||||||
|
if (item.underline) runProps.push('<w:u w:val="single"/>')
|
||||||
|
if (item.color) runProps.push(`<w:color w:val="${item.color}"/>`)
|
||||||
|
if (item.bgColor) {
|
||||||
|
runProps.push(`<w:shd w:val="clear" w:color="auto" w:fill="${item.bgColor}"/>`)
|
||||||
|
}
|
||||||
|
const propsXml = runProps.length ? `<w:rPr>${runProps.join('')}</w:rPr>` : ''
|
||||||
|
return `<w:r>${propsXml}<w:t xml:space="preserve">${text}</w:t></w:r>`
|
||||||
|
})
|
||||||
|
.join('')
|
||||||
|
|
||||||
|
const paragraphProps = [
|
||||||
|
`<w:spacing w:before="${DEFAULT_PARAGRAPH_SPACING_BEFORE}" w:after="${DEFAULT_PARAGRAPH_SPACING_AFTER}" w:line="${DEFAULT_PARAGRAPH_LINE}" w:lineRule="auto"/>`,
|
||||||
|
]
|
||||||
|
const alignmentValue = normalizeWordAlignment(paragraphStyle.align)
|
||||||
|
if (alignmentValue) {
|
||||||
|
paragraphProps.push(`<w:jc w:val="${alignmentValue}"/>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<w:p><w:pPr>${paragraphProps.join('')}</w:pPr>${runXml}</w:p>`
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTableXml(tableElement) {
|
||||||
|
const directRows = getDirectChildElements(tableElement, 'tr')
|
||||||
|
const rows = directRows.length ? directRows : Array.from(tableElement.getElementsByTagName('tr'))
|
||||||
|
const columnWidths = extractTableColumnWidths(tableElement)
|
||||||
|
const tableWidth = resolveTableWordWidth(readElementWidth(tableElement))
|
||||||
|
const normalizedColumnWidths = normalizeTableColumnWidths(rows, columnWidths, tableWidth)
|
||||||
|
|
||||||
|
const rowXml = rows
|
||||||
|
.map((row) => {
|
||||||
|
const cells = getDirectCellElements(row)
|
||||||
|
let logicalColumnIndex = 0
|
||||||
|
const cellXml = cells
|
||||||
|
.map((cell) => {
|
||||||
|
const isHeader = isHeaderCell(cell)
|
||||||
|
const cellStyle = parseNodeStyleInfo(cell)
|
||||||
|
const defaultCellAlign = cellStyle.align || 'center'
|
||||||
|
const blocks = []
|
||||||
|
collectBlocksFromChildren(cell.childNodes, blocks, {
|
||||||
|
bold: isHeader,
|
||||||
|
color: cellStyle.color || '',
|
||||||
|
bgColor: '',
|
||||||
|
align: defaultCellAlign,
|
||||||
|
})
|
||||||
|
const contentXml =
|
||||||
|
blocks.filter(Boolean).join('') || buildParagraphXml('', { align: defaultCellAlign })
|
||||||
|
const gridSpan = parseSpanValue(cell.getAttribute?.('colspan'))
|
||||||
|
const tcWidth =
|
||||||
|
buildCellWidthFromGrid(normalizedColumnWidths, logicalColumnIndex, gridSpan) || {
|
||||||
|
value: 0,
|
||||||
|
type: 'auto',
|
||||||
|
}
|
||||||
|
logicalColumnIndex += gridSpan
|
||||||
|
const tcProps = [
|
||||||
|
`<w:tcW w:w="${tcWidth.value}" w:type="${tcWidth.type}"/>`,
|
||||||
|
'<w:vAlign w:val="center"/>',
|
||||||
|
cellStyle.bgColor
|
||||||
|
? `<w:shd w:val="clear" w:color="auto" w:fill="${cellStyle.bgColor}"/>`
|
||||||
|
: '',
|
||||||
|
gridSpan > 1 ? `<w:gridSpan w:val="${gridSpan}"/>` : '',
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('')
|
||||||
|
return `<w:tc><w:tcPr>${tcProps}</w:tcPr>${contentXml}</w:tc>`
|
||||||
|
})
|
||||||
|
.join('')
|
||||||
|
return `<w:tr>${cellXml}</w:tr>`
|
||||||
|
})
|
||||||
|
.join('')
|
||||||
|
|
||||||
|
const normalizedTableWidth = buildNormalizedTableWidth(tableWidth, normalizedColumnWidths)
|
||||||
|
const tableGridXml = buildTableGridXml(normalizedColumnWidths)
|
||||||
|
return `<w:tbl><w:tblPr><w:tblW w:w="${normalizedTableWidth.value}" w:type="${normalizedTableWidth.type}"/><w:tblLayout w:type="fixed"/><w:tblCellMar><w:top w:w="${DEFAULT_TABLE_CELL_PADDING_TWIPS}" w:type="dxa"/><w:left w:w="${DEFAULT_TABLE_CELL_PADDING_TWIPS}" w:type="dxa"/><w:bottom w:w="${DEFAULT_TABLE_CELL_PADDING_TWIPS}" w:type="dxa"/><w:right w:w="${DEFAULT_TABLE_CELL_PADDING_TWIPS}" w:type="dxa"/></w:tblCellMar><w:tblBorders><w:top w:val="single" w:sz="8" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="8" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/><w:right w:val="single" w:sz="8" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="6" w:space="0" w:color="000000"/><w:insideV w:val="single" w:sz="6" w:space="0" w:color="000000"/></w:tblBorders></w:tblPr>${tableGridXml}${rowXml}</w:tbl>`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDirectChildElements(parent, tagName) {
|
||||||
|
return childElements(parent).filter(
|
||||||
|
(child) => String(child.tagName || '').toLowerCase() === tagName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDirectCellElements(row) {
|
||||||
|
const directCells = childElements(row).filter((child) => {
|
||||||
|
const tag = String(child.tagName || '').toLowerCase()
|
||||||
|
return tag === 'td' || tag === 'th'
|
||||||
|
})
|
||||||
|
return directCells.length
|
||||||
|
? directCells
|
||||||
|
: Array.from(row.getElementsByTagName('td')).concat(Array.from(row.getElementsByTagName('th')))
|
||||||
|
}
|
||||||
|
|
||||||
|
function isHeaderCell(cell) {
|
||||||
|
return String(cell?.tagName || '').toLowerCase() === 'th'
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTableColumnWidths(tableElement) {
|
||||||
|
const colGroups = getDirectChildElements(tableElement, 'colgroup')
|
||||||
|
const cols = colGroups.flatMap((group) => getDirectChildElements(group, 'col'))
|
||||||
|
return cols.map((col) => resolveCellWordWidth(readElementWidth(col))).filter(Boolean)
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeTableColumnWidths(rows, initialColumnWidths, tableWidth) {
|
||||||
|
const columnCount = getTableColumnCount(rows)
|
||||||
|
if (!columnCount) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetWidth = resolveTableTargetWidthTwips(tableWidth, columnCount)
|
||||||
|
const widths = Array.from({ length: columnCount }, (_, index) => {
|
||||||
|
const existingWidth = initialColumnWidths[index]?.value
|
||||||
|
return Number.isFinite(existingWidth) && existingWidth > 0 ? existingWidth : 0
|
||||||
|
})
|
||||||
|
|
||||||
|
rows.forEach((row) => {
|
||||||
|
let logicalColumnIndex = 0
|
||||||
|
getDirectCellElements(row).forEach((cell) => {
|
||||||
|
const gridSpan = parseSpanValue(cell.getAttribute?.('colspan'))
|
||||||
|
const cellWidth = resolveCellWordWidth(readElementWidth(cell))
|
||||||
|
if (cellWidth?.type === 'dxa' && cellWidth.value > 0) {
|
||||||
|
const distributedWidth = Math.max(300, Math.round(cellWidth.value / gridSpan))
|
||||||
|
for (let offset = 0; offset < gridSpan; offset += 1) {
|
||||||
|
const columnIndex = logicalColumnIndex + offset
|
||||||
|
if (columnIndex < columnCount) {
|
||||||
|
widths[columnIndex] = Math.max(widths[columnIndex] || 0, distributedWidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logicalColumnIndex += gridSpan
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const defaultWidth = Math.max(300, Math.round(targetWidth / columnCount))
|
||||||
|
const filledWidths = widths.map((width) => (width > 0 ? width : defaultWidth))
|
||||||
|
const currentTotal = filledWidths.reduce((sum, width) => sum + width, 0)
|
||||||
|
if (currentTotal <= 0) {
|
||||||
|
return filledWidths.map((width) => Math.max(300, Math.round(width)))
|
||||||
|
}
|
||||||
|
|
||||||
|
const scaledWidths = filledWidths.map((width) =>
|
||||||
|
Math.max(300, Math.round((width / currentTotal) * targetWidth)),
|
||||||
|
)
|
||||||
|
let scaledTotal = scaledWidths.reduce((sum, width) => sum + width, 0)
|
||||||
|
let adjustIndex = 0
|
||||||
|
while (scaledTotal !== targetWidth && scaledWidths.length) {
|
||||||
|
const diff = targetWidth - scaledTotal
|
||||||
|
const step = diff > 0 ? 1 : -1
|
||||||
|
const nextWidth = scaledWidths[adjustIndex] + step
|
||||||
|
if (nextWidth >= 300) {
|
||||||
|
scaledWidths[adjustIndex] = nextWidth
|
||||||
|
scaledTotal += step
|
||||||
|
}
|
||||||
|
adjustIndex = (adjustIndex + 1) % scaledWidths.length
|
||||||
|
}
|
||||||
|
return scaledWidths.map((width) => Math.max(300, Math.round(width)))
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTableColumnCount(rows) {
|
||||||
|
return rows.reduce((maxCount, row) => {
|
||||||
|
const count = getDirectCellElements(row).reduce(
|
||||||
|
(sum, cell) => sum + parseSpanValue(cell.getAttribute?.('colspan')),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
return Math.max(maxCount, count)
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveTableTargetWidthTwips(tableWidth, columnCount) {
|
||||||
|
if (tableWidth?.type === 'dxa' && tableWidth.value > 0) {
|
||||||
|
return Math.max(300 * columnCount, Math.round(tableWidth.value))
|
||||||
|
}
|
||||||
|
return Math.max(300 * columnCount, DEFAULT_WORD_TABLE_WIDTH_TWIPS)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCellWidthFromGrid(columnWidths, startIndex, gridSpan) {
|
||||||
|
const totalWidth = (columnWidths || [])
|
||||||
|
.slice(startIndex, startIndex + gridSpan)
|
||||||
|
.reduce((sum, width) => sum + (Number.isFinite(width) ? width : 0), 0)
|
||||||
|
if (totalWidth > 0) {
|
||||||
|
return { value: totalWidth, type: 'dxa' }
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildNormalizedTableWidth(tableWidth, columnWidths) {
|
||||||
|
const totalWidth = (columnWidths || []).reduce(
|
||||||
|
(sum, width) => sum + (Number.isFinite(width) ? width : 0),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
if (totalWidth > 0) {
|
||||||
|
return { value: totalWidth, type: 'dxa' }
|
||||||
|
}
|
||||||
|
return tableWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTableGridXml(columnWidths = []) {
|
||||||
|
if (!columnWidths.length) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const gridColumns = columnWidths
|
||||||
|
.map((width) => `<w:gridCol w:w="${Math.max(300, Math.round(width))}"/>`)
|
||||||
|
.join('')
|
||||||
|
return `<w:tblGrid>${gridColumns}</w:tblGrid>`
|
||||||
|
}
|
||||||
|
|
||||||
|
function readElementWidth(element) {
|
||||||
|
if (!element) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const directWidth = String(element.getAttribute?.('width') || '').trim()
|
||||||
|
if (directWidth) {
|
||||||
|
return directWidth
|
||||||
|
}
|
||||||
|
const styleText = String(element.getAttribute?.('style') || '').trim()
|
||||||
|
if (!styleText) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const widthMatch = styleText.match(/(?:^|;)\s*width\s*:\s*([^;]+)/i)
|
||||||
|
if (widthMatch?.[1]) {
|
||||||
|
return widthMatch[1].trim()
|
||||||
|
}
|
||||||
|
const minWidthMatch = styleText.match(/(?:^|;)\s*min-width\s*:\s*([^;]+)/i)
|
||||||
|
return minWidthMatch?.[1] ? minWidthMatch[1].trim() : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveTableWordWidth(rawWidth) {
|
||||||
|
const normalized = String(rawWidth || '').trim().toLowerCase()
|
||||||
|
if (!normalized) {
|
||||||
|
return { value: DEFAULT_WORD_TABLE_WIDTH_PERCENT, type: 'pct' }
|
||||||
|
}
|
||||||
|
const numericValue = parseFloat(normalized)
|
||||||
|
if (!Number.isFinite(numericValue) || numericValue <= 0) {
|
||||||
|
return { value: DEFAULT_WORD_TABLE_WIDTH_PERCENT, type: 'pct' }
|
||||||
|
}
|
||||||
|
if (normalized.endsWith('%')) {
|
||||||
|
return {
|
||||||
|
value: Math.max(500, Math.min(Math.round((numericValue / 100) * 5000), 5000)),
|
||||||
|
type: 'pct',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resolveCellWordWidth(normalized) || { value: DEFAULT_WORD_TABLE_WIDTH_PERCENT, type: 'pct' }
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveCellWordWidth(rawWidth, fallbackWidth = null) {
|
||||||
|
const normalized = String(rawWidth || '').trim().toLowerCase()
|
||||||
|
if (!normalized) {
|
||||||
|
return fallbackWidth
|
||||||
|
}
|
||||||
|
const numericValue = parseFloat(normalized)
|
||||||
|
if (!Number.isFinite(numericValue) || numericValue <= 0) {
|
||||||
|
return fallbackWidth
|
||||||
|
}
|
||||||
|
if (normalized.endsWith('%')) {
|
||||||
|
return {
|
||||||
|
value: clampWordWidth(Math.round((numericValue / 100) * DEFAULT_WORD_TABLE_WIDTH_TWIPS)),
|
||||||
|
type: 'dxa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (normalized.endsWith('px')) {
|
||||||
|
return {
|
||||||
|
value: clampWordWidth(Math.round(numericValue * 15)),
|
||||||
|
type: 'dxa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (normalized.endsWith('pt')) {
|
||||||
|
return {
|
||||||
|
value: clampWordWidth(Math.round(numericValue * 20)),
|
||||||
|
type: 'dxa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (normalized.endsWith('cm')) {
|
||||||
|
return {
|
||||||
|
value: clampWordWidth(Math.round(numericValue * 567)),
|
||||||
|
type: 'dxa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (normalized.endsWith('mm')) {
|
||||||
|
return {
|
||||||
|
value: clampWordWidth(Math.round(numericValue * 57)),
|
||||||
|
type: 'dxa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (normalized.endsWith('in')) {
|
||||||
|
return {
|
||||||
|
value: clampWordWidth(Math.round(numericValue * 1440)),
|
||||||
|
type: 'dxa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
value: clampWordWidth(Math.round(numericValue * 15)),
|
||||||
|
type: 'dxa',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clampWordWidth(value) {
|
||||||
|
return Math.max(300, Math.min(Math.round(value || 0), DEFAULT_WORD_TABLE_WIDTH_TWIPS))
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseSpanValue(rawValue) {
|
||||||
|
const value = parseInt(String(rawValue || '').trim(), 10)
|
||||||
|
return Number.isFinite(value) && value > 1 ? value : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseNodeStyleInfo(node) {
|
||||||
|
const tag = String(node?.tagName || '').toLowerCase()
|
||||||
|
const styleText = String(node?.getAttribute?.('style') || '')
|
||||||
|
const color = normalizeCssColor(readStyleProperty(styleText, 'color'))
|
||||||
|
const bgColor = normalizeCssColor(readStyleProperty(styleText, 'background-color'))
|
||||||
|
const textAlign = normalizeTextAlign(readStyleProperty(styleText, 'text-align'))
|
||||||
|
return {
|
||||||
|
bold: tag === 'strong' || tag === 'b',
|
||||||
|
italic: tag === 'em' || tag === 'i',
|
||||||
|
underline: tag === 'u',
|
||||||
|
color,
|
||||||
|
bgColor,
|
||||||
|
align: textAlign,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeTextStyle(baseStyle = {}, overrideStyle = {}) {
|
||||||
|
return {
|
||||||
|
bold: overrideStyle.bold === true || baseStyle.bold === true,
|
||||||
|
italic: overrideStyle.italic === true || baseStyle.italic === true,
|
||||||
|
underline: overrideStyle.underline === true || baseStyle.underline === true,
|
||||||
|
color: overrideStyle.color || baseStyle.color || '',
|
||||||
|
bgColor: overrideStyle.bgColor || baseStyle.bgColor || '',
|
||||||
|
align: overrideStyle.align || baseStyle.align || '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readStyleProperty(styleText, propertyName) {
|
||||||
|
const match = String(styleText || '').match(
|
||||||
|
new RegExp(`(?:^|;)\\s*${escapeRegExp(propertyName)}\\s*:\\s*([^;]+)`, 'i'),
|
||||||
|
)
|
||||||
|
return match?.[1] ? match[1].trim() : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCssColor(rawColor) {
|
||||||
|
const value = String(rawColor || '').trim().toLowerCase()
|
||||||
|
if (!value || value === 'transparent' || value === 'inherit') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if (value.startsWith('#')) {
|
||||||
|
const hex = value.slice(1)
|
||||||
|
if (hex.length === 3) {
|
||||||
|
return hex
|
||||||
|
.split('')
|
||||||
|
.map((char) => char + char)
|
||||||
|
.join('')
|
||||||
|
.toUpperCase()
|
||||||
|
}
|
||||||
|
if (hex.length >= 6) {
|
||||||
|
return hex.slice(0, 6).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const rgbMatch = value.match(/rgba?\(([^)]+)\)/i)
|
||||||
|
if (rgbMatch?.[1]) {
|
||||||
|
const [r, g, b] = rgbMatch[1]
|
||||||
|
.split(',')
|
||||||
|
.slice(0, 3)
|
||||||
|
.map((item) => Math.max(0, Math.min(255, parseInt(item.trim(), 10) || 0)))
|
||||||
|
return [r, g, b]
|
||||||
|
.map((num) => num.toString(16).padStart(2, '0'))
|
||||||
|
.join('')
|
||||||
|
.toUpperCase()
|
||||||
|
}
|
||||||
|
const colorMap = {
|
||||||
|
black: '000000',
|
||||||
|
white: 'FFFFFF',
|
||||||
|
red: 'FF0000',
|
||||||
|
blue: '0000FF',
|
||||||
|
green: '008000',
|
||||||
|
yellow: 'FFFF00',
|
||||||
|
gray: '808080',
|
||||||
|
grey: '808080',
|
||||||
|
orange: 'FFA500',
|
||||||
|
purple: '800080',
|
||||||
|
}
|
||||||
|
return colorMap[value] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeTextAlign(rawValue) {
|
||||||
|
const value = String(rawValue || '').trim().toLowerCase()
|
||||||
|
if (['left', 'center', 'right', 'justify'].includes(value)) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeWordAlignment(value) {
|
||||||
|
if (value === 'left') return 'left'
|
||||||
|
if (value === 'center') return 'center'
|
||||||
|
if (value === 'right') return 'right'
|
||||||
|
if (value === 'justify') return 'both'
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeRegExp(text) {
|
||||||
|
return String(text).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenNodeText(node) {
|
||||||
|
if (!node) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const text = Array.from(node.childNodes || [])
|
||||||
|
.map((child) => {
|
||||||
|
if (child.nodeType === TEXT_NODE) {
|
||||||
|
return child.data || child.nodeValue || ''
|
||||||
|
}
|
||||||
|
if (child.nodeType === ELEMENT_NODE) {
|
||||||
|
if (String(child.tagName || '').toLowerCase() === 'br') {
|
||||||
|
return '\n'
|
||||||
|
}
|
||||||
|
return flattenNodeText(child)
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
.join('')
|
||||||
|
return normalizeText(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
function childElements(node) {
|
||||||
|
return Array.from(node?.childNodes || []).filter((item) => item.nodeType === ELEMENT_NODE)
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstElementChild(node) {
|
||||||
|
return childElements(node)[0] || null
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeText(text) {
|
||||||
|
return String(text || '')
|
||||||
|
.replace(/\u00a0/g, ' ')
|
||||||
|
.replace(/[\ufeff\u200b]/g, '')
|
||||||
|
.replace(/\r/g, '')
|
||||||
|
.replace(/\t/g, ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyPlainTemplateValue(value) {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return String(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeFieldType(fieldType) {
|
||||||
|
const value = String(fieldType || 'input').trim()
|
||||||
|
if (value === 'select') {
|
||||||
|
return 'select'
|
||||||
|
}
|
||||||
|
if (value === 'rich_text') {
|
||||||
|
return 'rich_text'
|
||||||
|
}
|
||||||
|
return 'input'
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeXml(text) {
|
||||||
|
return String(text)
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DOCX_MIME_TYPE }
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
export const TEMPLATE_FIELD_TYPE_OPTIONS = [
|
||||||
|
{ label: "输入框", value: "input" },
|
||||||
|
{ label: "下拉框", value: "select" },
|
||||||
|
{ label: "富文本", value: "rich_text" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export function normalizeTemplateVariableMapping(item = {}, index = 0) {
|
||||||
|
const variableKey = String(item.variableKey || "").trim();
|
||||||
|
const bindField = String(item.bindField || variableKey || "").trim();
|
||||||
|
const fieldType = normalizeFieldType(item.fieldType);
|
||||||
|
return {
|
||||||
|
id: item.id || `var_${Date.now()}_${index}`,
|
||||||
|
variableKey,
|
||||||
|
bindField,
|
||||||
|
fieldLabel: String(item.fieldLabel || variableKey || bindField || "").trim(),
|
||||||
|
fieldType,
|
||||||
|
required: item.required !== false,
|
||||||
|
placeholder: String(item.placeholder || "").trim(),
|
||||||
|
dictType: String(item.dictType || "").trim(),
|
||||||
|
remark: String(item.remark || "").trim(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createEmptyTemplateVariableMapping(index = 0) {
|
||||||
|
return normalizeTemplateVariableMapping({}, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildTemplateLaunchFieldList(variableMappings = [], templateFieldLabelMap = {}) {
|
||||||
|
const fieldMap = new Map();
|
||||||
|
variableMappings.forEach((item, index) => {
|
||||||
|
const mapping = normalizeTemplateVariableMapping(item, index);
|
||||||
|
const fieldKey = mapping.bindField || mapping.variableKey;
|
||||||
|
if (!fieldKey || fieldMap.has(fieldKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fieldMap.set(fieldKey, {
|
||||||
|
key: fieldKey,
|
||||||
|
label:
|
||||||
|
mapping.fieldLabel ||
|
||||||
|
templateFieldLabelMap[fieldKey] ||
|
||||||
|
mapping.variableKey ||
|
||||||
|
fieldKey,
|
||||||
|
fieldType: mapping.fieldType,
|
||||||
|
required: mapping.required !== false,
|
||||||
|
placeholder: mapping.placeholder || buildDefaultPlaceholder(mapping),
|
||||||
|
dictType: mapping.dictType || "",
|
||||||
|
remark: mapping.remark || "",
|
||||||
|
variableKey: mapping.variableKey || fieldKey,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return [...fieldMap.values()];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeFieldType(fieldType) {
|
||||||
|
const value = String(fieldType || "input").trim();
|
||||||
|
if (value === "select") {
|
||||||
|
return "select";
|
||||||
|
}
|
||||||
|
if (value === "rich_text") {
|
||||||
|
return "rich_text";
|
||||||
|
}
|
||||||
|
return "input";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildDefaultPlaceholder(mapping = {}) {
|
||||||
|
const label = mapping.fieldLabel || mapping.variableKey || mapping.bindField || "内容";
|
||||||
|
if (mapping.fieldType === "select") {
|
||||||
|
return `请选择${label}`;
|
||||||
|
}
|
||||||
|
if (mapping.fieldType === "rich_text") {
|
||||||
|
return `请输入${label},支持表格`;
|
||||||
|
}
|
||||||
|
return `请输入${label}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stringifyTemplateFieldValue(value, fieldType = "input") {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (fieldType === "rich_text") {
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
return String(value).trim();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user