feat: 引入新版报告在线编辑功能,优化旧版编辑器资源处理并增加背景设置,同时新增报告模板。
This commit is contained in:
parent
89ccaa8b16
commit
afea5b6335
@ -5,5 +5,6 @@ VITE_PUBLIC_PATH = '/'
|
||||
VITE_USE_PROXY = true
|
||||
|
||||
# base api
|
||||
VITE_BASE_API = 'http://139.224.70.152:9990/api/v1'
|
||||
# VITE_BASE_API = 'http://139.224.70.152:9990/api/v1'
|
||||
VITE_BASE_API = 'https://manage-value.cdcee.net/api/v1'
|
||||
# VITE_BASE_API = 'http://127.0.0.1:9999/api/v1'
|
||||
|
||||
@ -20,6 +20,15 @@
|
||||
"axios": "^1.4.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"docxtemplater": "^3.67.5",
|
||||
"@tiptap/core": "^2.6.6",
|
||||
"@tiptap/starter-kit": "^2.6.6",
|
||||
"@tiptap/extension-color": "^2.6.6",
|
||||
"@tiptap/extension-text-style": "^2.6.6",
|
||||
"@tiptap/extension-text-align": "^2.6.6",
|
||||
"@tiptap/extension-underline": "^2.6.6",
|
||||
"@tiptap/extension-image": "^2.6.6",
|
||||
"@tiptap/extension-link": "^2.6.6",
|
||||
"@tiptap/vue-3": "^2.6.6",
|
||||
"dotenv": "^16.3.1",
|
||||
"eslint": "^8.46.0",
|
||||
"file-saver": "^2.0.5",
|
||||
|
||||
624
web/pnpm-lock.yaml
generated
624
web/pnpm-lock.yaml
generated
@ -14,6 +14,33 @@ importers:
|
||||
'@iconify/vue':
|
||||
specifier: ^4.1.1
|
||||
version: 4.1.2(vue@3.4.34(typescript@5.5.4))
|
||||
'@tiptap/core':
|
||||
specifier: ^2.6.6
|
||||
version: 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-color':
|
||||
specifier: ^2.6.6
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/extension-text-style@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1)))
|
||||
'@tiptap/extension-image':
|
||||
specifier: ^2.6.6
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-link':
|
||||
specifier: ^2.6.6
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-text-align':
|
||||
specifier: ^2.6.6
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-text-style':
|
||||
specifier: ^2.6.6
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-underline':
|
||||
specifier: ^2.6.6
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/starter-kit':
|
||||
specifier: ^2.6.6
|
||||
version: 2.27.1
|
||||
'@tiptap/vue-3':
|
||||
specifier: ^2.6.6
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)(vue@3.4.34(typescript@5.5.4))
|
||||
'@unocss/eslint-config':
|
||||
specifier: ^0.55.0
|
||||
version: 0.55.7(eslint@8.57.0)(typescript@5.5.4)
|
||||
@ -29,9 +56,6 @@ importers:
|
||||
dayjs:
|
||||
specifier: ^1.11.9
|
||||
version: 1.11.12
|
||||
docx-preview:
|
||||
specifier: ^0.3.7
|
||||
version: 0.3.7
|
||||
docxtemplater:
|
||||
specifier: ^3.67.5
|
||||
version: 3.67.5
|
||||
@ -387,6 +411,12 @@ packages:
|
||||
'@polka/url@1.0.0-next.25':
|
||||
resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==}
|
||||
|
||||
'@popperjs/core@2.11.8':
|
||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||
|
||||
'@remirror/core-constants@3.0.0':
|
||||
resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==}
|
||||
|
||||
'@rollup/pluginutils@4.2.1':
|
||||
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
@ -400,6 +430,163 @@ packages:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@tiptap/core@2.27.1':
|
||||
resolution: {integrity: sha512-nkerkl8syHj44ZzAB7oA2GPmmZINKBKCa79FuNvmGJrJ4qyZwlkDzszud23YteFZEytbc87kVd/fP76ROS6sLg==}
|
||||
peerDependencies:
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-blockquote@2.27.1':
|
||||
resolution: {integrity: sha512-QrUX3muElDrNjKM3nqCSAtm3H3pT33c6ON8kwRiQboOAjT/9D57Cs7XEVY7r6rMaJPeKztrRUrNVF9w/w/6B0A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-bold@2.27.1':
|
||||
resolution: {integrity: sha512-g4l4p892x/r7mhea8syp3fNYODxsDrimgouQ+q4DKXIgQmm5+uNhyuEPexP3I8TFNXqQ4DlMNFoM9yCqk97etQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-bubble-menu@2.27.1':
|
||||
resolution: {integrity: sha512-ki1R27VsSvY2tT9Q2DIlcATwLOoEjf5DsN+5sExarQ8S/ZxT/tvIjRxB8Dx7lb2a818W5f/NER26YchGtmHfpg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-bullet-list@2.27.1':
|
||||
resolution: {integrity: sha512-5FmnfXkJ76wN4EbJNzBhAlmQxho8yEMIJLchTGmXdsD/n/tsyVVtewnQYaIOj/Z7naaGySTGDmjVtLgTuQ+Sxw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-code-block@2.27.1':
|
||||
resolution: {integrity: sha512-wCI5VIOfSAdkenCWFvh4m8FFCJ51EOK+CUmOC/PWUjyo2Dgn8QC8HMi015q8XF7886T0KvYVVoqxmxJSUDAYNg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-code@2.27.1':
|
||||
resolution: {integrity: sha512-i65wUGJevzBTIIUBHBc1ggVa27bgemvGl/tY1/89fEuS/0Xmre+OQjw8rCtSLevoHSiYYLgLRlvjtUSUhE4kgg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-color@2.27.1':
|
||||
resolution: {integrity: sha512-raYRsdG2tZvVvY1LV/VTZnDG44Y0xRBwo5CZEat0OUqdx34dfvCtYm8HIOTyWBwr7OOW+yR4O1Vc2zFkmfthZw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/extension-text-style': ^2.7.0
|
||||
|
||||
'@tiptap/extension-document@2.27.1':
|
||||
resolution: {integrity: sha512-NtJzJY7Q/6XWjpOm5OXKrnEaofrcc1XOTYlo/SaTwl8k2bZo918Vl0IDBWhPVDsUN7kx767uHwbtuQZ+9I82hA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-dropcursor@2.27.1':
|
||||
resolution: {integrity: sha512-3MBQRGHHZ0by3OT0CWbLKS7J3PH9PpobrXjmIR7kr0nde7+bHqxXiVNuuIf501oKU9rnEUSedipSHkLYGkmfsA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-floating-menu@2.27.1':
|
||||
resolution: {integrity: sha512-nUk/8DbiXO69l6FDwkWso94BTf52IBoWALo+YGWT6o+FO6cI9LbUGghEX2CdmQYXCvSvwvISF2jXeLQWNZvPZQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-gapcursor@2.27.1':
|
||||
resolution: {integrity: sha512-A9e1jr+jGhDWzNSXtIO6PYVYhf5j/udjbZwMja+wCE/3KvZU9V3IrnGKz1xNW+2Q2BDOe1QO7j5uVL9ElR6nTA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-hard-break@2.27.1':
|
||||
resolution: {integrity: sha512-W4hHa4Io6QCTwpyTlN6UAvqMIQ7t56kIUByZhyY9EWrg/+JpbfpxE1kXFLPB4ZGgwBknFOw+e4bJ1j3oAbTJFw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-heading@2.27.1':
|
||||
resolution: {integrity: sha512-6xoC7igZlW1EmnQ5WVH9IL7P1nCQb3bBUaIDLvk7LbweEogcTUECI4Xg1vxMOVmj9tlDe1I4BsgfcKpB5KEsZw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-history@2.27.1':
|
||||
resolution: {integrity: sha512-K8PHC9gegSAt0wzSlsd4aUpoEyIJYOmVVeyniHr1P1mIblW1KYEDbRGbDlrLALTyUEfMcBhdIm8zrB9X2Nihvg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-horizontal-rule@2.27.1':
|
||||
resolution: {integrity: sha512-WxXWGEEsqDmGIF2o9av+3r9Qje4CKrqrpeQY6aRO5bxvWX9AabQCfasepayBok6uwtvNzh3Xpsn9zbbSk09dNA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-image@2.27.1':
|
||||
resolution: {integrity: sha512-wu3vMKDYWJwKS6Hrw5PPCKBO2RxyHNeFLiA/uDErEV7axzNpievK/U9DyaDXmtK3K/h1XzJAJz19X+2d/pY68w==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-italic@2.27.1':
|
||||
resolution: {integrity: sha512-rcm0GyniWW0UhcNI9+1eIK64GqWQLyIIrWGINslvqSUoBc+WkfocLvv4CMpRkzKlfsAxwVIBuH2eLxHKDtAREA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-link@2.27.1':
|
||||
resolution: {integrity: sha512-cCwWPZsnVh9MXnGOqSIRXPPuUixRDK8eMN2TvqwbxUBb1TU7b/HtNvfMU4tAOqAuMRJ0aJkFuf3eB0Gi8LVb1g==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@tiptap/extension-list-item@2.27.1':
|
||||
resolution: {integrity: sha512-dtsxvtzxfwOJP6dKGf0vb2MJAoDF2NxoiWzpq0XTvo7NGGYUHfuHjX07Zp0dYqb4seaDXjwsi5BIQUOp3+WMFQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-ordered-list@2.27.1':
|
||||
resolution: {integrity: sha512-U1/sWxc2TciozQsZjH35temyidYUjvroHj3PUPzPyh19w2fwKh1NSbFybWuoYs6jS3XnMSwnM2vF52tOwvfEmA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-paragraph@2.27.1':
|
||||
resolution: {integrity: sha512-R3QdrHcUdFAsdsn2UAIvhY0yWyHjqGyP/Rv8RRdN0OyFiTKtwTPqreKMHKJOflgX4sMJl/OpHTpNG1Kaf7Lo2A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-strike@2.27.1':
|
||||
resolution: {integrity: sha512-S9I//K8KPgfFTC5I5lorClzXk0g4lrAv9y5qHzHO5EOWt7AFl0YTg2oN8NKSIBK4bHRnPIrjJJKv+dDFnUp5jQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-text-align@2.27.1':
|
||||
resolution: {integrity: sha512-D7dLPk7y5mDn9ZNANQ4K2gCq4vy+Emm5AdeWOGzNeqJsYrBotiQYXd9rb1QYjdup2kzAoKduMTUXV92ujo5cEg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-text-style@2.27.1':
|
||||
resolution: {integrity: sha512-NagQ9qLk0Ril83gfrk+C65SvTqPjL3WVnLF2arsEVnCrxcx3uDOvdJW67f/K5HEwEHsoqJ4Zq9Irco/koXrOXA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-text@2.27.1':
|
||||
resolution: {integrity: sha512-a4GCT+GZ9tUwl82F4CEum9/+WsuW0/De9Be/NqrMmi7eNfAwbUTbLCTFU0gEvv25WMHCoUzaeNk/qGmzeVPJ1Q==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-underline@2.27.1':
|
||||
resolution: {integrity: sha512-fPTmfJFAQWg1O/os1pYSPVdtvly6eW/w5sDofG7pre+bdQUN+8s1cZYelSuj/ltNVioRaB2Ws7tvNgnHL0aAJQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/pm@2.27.1':
|
||||
resolution: {integrity: sha512-ijKo3+kIjALthYsnBmkRXAuw2Tswd9gd7BUR5OMfIcjGp8v576vKxOxrRfuYiUM78GPt//P0sVc1WV82H5N0PQ==}
|
||||
|
||||
'@tiptap/starter-kit@2.27.1':
|
||||
resolution: {integrity: sha512-uQQlP0Nmn9eq19qm8YoOeloEfmcGbPpB1cujq54Q6nPgxaBozR7rE7tXbFTinxRW2+Hr7XyNWhpjB7DMNkdU2Q==}
|
||||
|
||||
'@tiptap/vue-3@2.27.1':
|
||||
resolution: {integrity: sha512-1D0gTlGBeDmrl+APm/JKoNs/KnW5PecpD1PbQmg2GEHVxVZNeIUpG48D/V5uTIiRwJsDx3PMd8AmsZs1QS6GLw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
vue: ^3.0.0
|
||||
|
||||
'@trysound/sax@0.2.0':
|
||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@ -413,12 +600,21 @@ packages:
|
||||
'@types/katex@0.16.7':
|
||||
resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
|
||||
|
||||
'@types/linkify-it@5.0.0':
|
||||
resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
|
||||
|
||||
'@types/lodash@4.17.7':
|
||||
resolution: {integrity: sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==}
|
||||
|
||||
'@types/markdown-it@14.1.2':
|
||||
resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==}
|
||||
|
||||
'@types/mdurl@2.0.0':
|
||||
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
|
||||
|
||||
'@types/node@22.0.0':
|
||||
resolution: {integrity: sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==}
|
||||
|
||||
@ -839,6 +1035,9 @@ packages:
|
||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
crelt@1.0.6:
|
||||
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
|
||||
|
||||
cross-spawn@7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -966,9 +1165,6 @@ packages:
|
||||
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
docx-preview@0.3.7:
|
||||
resolution: {integrity: sha512-Lav69CTA/IYZPJTsKH7oYeoZjyg96N0wEJMNslGJnZJ+dMUZK85Lt5ASC79yUlD48ecWjuv+rkcmFt6EVPV0Xg==}
|
||||
|
||||
docxtemplater@3.67.5:
|
||||
resolution: {integrity: sha512-Jnh9rdMf5sDmrfONs3nVDhZwVFxLNdP3RVHkqLQYA6eZLkWA+kx5aYy0cVmEqJcVIaFYf5JJEFdClD7fn6ZUng==}
|
||||
engines: {node: '>=0.10'}
|
||||
@ -1645,6 +1841,12 @@ packages:
|
||||
lie@3.3.0:
|
||||
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
|
||||
|
||||
linkify-it@5.0.0:
|
||||
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
|
||||
|
||||
linkifyjs@4.3.2:
|
||||
resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==}
|
||||
|
||||
loader-utils@1.4.2:
|
||||
resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
@ -1684,6 +1886,10 @@ packages:
|
||||
resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
markdown-it@14.1.0:
|
||||
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
|
||||
hasBin: true
|
||||
|
||||
marked@17.0.1:
|
||||
resolution: {integrity: sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==}
|
||||
engines: {node: '>= 20'}
|
||||
@ -1695,6 +1901,9 @@ packages:
|
||||
mdn-data@2.0.30:
|
||||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||
|
||||
mdurl@2.0.0:
|
||||
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
|
||||
|
||||
merge-options@1.0.1:
|
||||
resolution: {integrity: sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg==}
|
||||
engines: {node: '>=4'}
|
||||
@ -1844,6 +2053,9 @@ packages:
|
||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
orderedmap@2.1.1:
|
||||
resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==}
|
||||
|
||||
p-limit@3.1.0:
|
||||
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -1983,9 +2195,71 @@ packages:
|
||||
process-nextick-args@2.0.1:
|
||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||
|
||||
prosemirror-changeset@2.3.1:
|
||||
resolution: {integrity: sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==}
|
||||
|
||||
prosemirror-collab@1.3.1:
|
||||
resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==}
|
||||
|
||||
prosemirror-commands@1.7.1:
|
||||
resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==}
|
||||
|
||||
prosemirror-dropcursor@1.8.2:
|
||||
resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==}
|
||||
|
||||
prosemirror-gapcursor@1.4.0:
|
||||
resolution: {integrity: sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==}
|
||||
|
||||
prosemirror-history@1.5.0:
|
||||
resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==}
|
||||
|
||||
prosemirror-inputrules@1.5.1:
|
||||
resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==}
|
||||
|
||||
prosemirror-keymap@1.2.3:
|
||||
resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==}
|
||||
|
||||
prosemirror-markdown@1.13.2:
|
||||
resolution: {integrity: sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==}
|
||||
|
||||
prosemirror-menu@1.2.5:
|
||||
resolution: {integrity: sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==}
|
||||
|
||||
prosemirror-model@1.25.4:
|
||||
resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==}
|
||||
|
||||
prosemirror-schema-basic@1.2.4:
|
||||
resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==}
|
||||
|
||||
prosemirror-schema-list@1.5.1:
|
||||
resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==}
|
||||
|
||||
prosemirror-state@1.4.4:
|
||||
resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==}
|
||||
|
||||
prosemirror-tables@1.8.3:
|
||||
resolution: {integrity: sha512-wbqCR/RlRPRe41a4LFtmhKElzBEfBTdtAYWNIGHM6X2e24NN/MTNUKyXjjphfAfdQce37Kh/5yf765mLPYDe7Q==}
|
||||
|
||||
prosemirror-trailing-node@3.0.0:
|
||||
resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==}
|
||||
peerDependencies:
|
||||
prosemirror-model: ^1.22.1
|
||||
prosemirror-state: ^1.4.2
|
||||
prosemirror-view: ^1.33.8
|
||||
|
||||
prosemirror-transform@1.10.5:
|
||||
resolution: {integrity: sha512-RPDQCxIDhIBb1o36xxwsaeAvivO8VLJcgBtzmOwQ64bMtsVFh5SSuJ6dWSxO1UsHTiTXPCgQm3PDJt7p6IOLbw==}
|
||||
|
||||
prosemirror-view@1.41.4:
|
||||
resolution: {integrity: sha512-WkKgnyjNncri03Gjaz3IFWvCAE94XoiEgvtr0/r2Xw7R8/IjK3sKLSiDoCHWcsXSAinVaKlGRZDvMCsF1kbzjA==}
|
||||
|
||||
proxy-from-env@1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
|
||||
punycode.js@2.3.1:
|
||||
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
punycode@2.3.1:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
@ -2075,6 +2349,9 @@ packages:
|
||||
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
rope-sequence@1.3.4:
|
||||
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
|
||||
|
||||
run-parallel@1.2.0:
|
||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||
|
||||
@ -2280,6 +2557,9 @@ packages:
|
||||
text-table@0.2.0:
|
||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||
|
||||
tippy.js@6.3.7:
|
||||
resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==}
|
||||
|
||||
to-fast-properties@2.0.0:
|
||||
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
||||
engines: {node: '>=4'}
|
||||
@ -2353,6 +2633,9 @@ packages:
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
uc.micro@2.1.0:
|
||||
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
|
||||
|
||||
ufo@1.5.4:
|
||||
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
|
||||
|
||||
@ -2553,6 +2836,9 @@ packages:
|
||||
peerDependencies:
|
||||
vue: ^3.0.11
|
||||
|
||||
w3c-keyname@2.2.8:
|
||||
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
|
||||
|
||||
webpack-sources@3.2.3:
|
||||
resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@ -2822,6 +3108,10 @@ snapshots:
|
||||
|
||||
'@polka/url@1.0.0-next.25': {}
|
||||
|
||||
'@popperjs/core@2.11.8': {}
|
||||
|
||||
'@remirror/core-constants@3.0.0': {}
|
||||
|
||||
'@rollup/pluginutils@4.2.1':
|
||||
dependencies:
|
||||
estree-walker: 2.0.2
|
||||
@ -2835,6 +3125,179 @@ snapshots:
|
||||
optionalDependencies:
|
||||
rollup: 3.29.4
|
||||
|
||||
'@tiptap/core@2.27.1(@tiptap/pm@2.27.1)':
|
||||
dependencies:
|
||||
'@tiptap/pm': 2.27.1
|
||||
|
||||
'@tiptap/extension-blockquote@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-bold@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-bubble-menu@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/pm': 2.27.1
|
||||
tippy.js: 6.3.7
|
||||
|
||||
'@tiptap/extension-bullet-list@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-code-block@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/pm': 2.27.1
|
||||
|
||||
'@tiptap/extension-code@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-color@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/extension-text-style@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1)))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-text-style': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
|
||||
'@tiptap/extension-document@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-dropcursor@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/pm': 2.27.1
|
||||
|
||||
'@tiptap/extension-floating-menu@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/pm': 2.27.1
|
||||
tippy.js: 6.3.7
|
||||
|
||||
'@tiptap/extension-gapcursor@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/pm': 2.27.1
|
||||
|
||||
'@tiptap/extension-hard-break@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-heading@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-history@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/pm': 2.27.1
|
||||
|
||||
'@tiptap/extension-horizontal-rule@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/pm': 2.27.1
|
||||
|
||||
'@tiptap/extension-image@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-italic@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-link@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/pm': 2.27.1
|
||||
linkifyjs: 4.3.2
|
||||
|
||||
'@tiptap/extension-list-item@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-ordered-list@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-paragraph@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-strike@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-text-align@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-text-style@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-text@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/extension-underline@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
|
||||
'@tiptap/pm@2.27.1':
|
||||
dependencies:
|
||||
prosemirror-changeset: 2.3.1
|
||||
prosemirror-collab: 1.3.1
|
||||
prosemirror-commands: 1.7.1
|
||||
prosemirror-dropcursor: 1.8.2
|
||||
prosemirror-gapcursor: 1.4.0
|
||||
prosemirror-history: 1.5.0
|
||||
prosemirror-inputrules: 1.5.1
|
||||
prosemirror-keymap: 1.2.3
|
||||
prosemirror-markdown: 1.13.2
|
||||
prosemirror-menu: 1.2.5
|
||||
prosemirror-model: 1.25.4
|
||||
prosemirror-schema-basic: 1.2.4
|
||||
prosemirror-schema-list: 1.5.1
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-tables: 1.8.3
|
||||
prosemirror-trailing-node: 3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.4)
|
||||
prosemirror-transform: 1.10.5
|
||||
prosemirror-view: 1.41.4
|
||||
|
||||
'@tiptap/starter-kit@2.27.1':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-blockquote': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-bold': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-bullet-list': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-code': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-code-block': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-document': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-dropcursor': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-gapcursor': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-hard-break': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-heading': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-history': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-horizontal-rule': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-italic': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-list-item': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-ordered-list': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-paragraph': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-strike': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-text': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/extension-text-style': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
'@tiptap/pm': 2.27.1
|
||||
|
||||
'@tiptap/vue-3@2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)(vue@3.4.34(typescript@5.5.4))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-bubble-menu': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-floating-menu': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/pm': 2.27.1
|
||||
vue: 3.4.34(typescript@5.5.4)
|
||||
|
||||
'@trysound/sax@0.2.0': {}
|
||||
|
||||
'@types/estree@1.0.5': {}
|
||||
@ -2843,12 +3306,21 @@ snapshots:
|
||||
|
||||
'@types/katex@0.16.7': {}
|
||||
|
||||
'@types/linkify-it@5.0.0': {}
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
dependencies:
|
||||
'@types/lodash': 4.17.7
|
||||
|
||||
'@types/lodash@4.17.7': {}
|
||||
|
||||
'@types/markdown-it@14.1.2':
|
||||
dependencies:
|
||||
'@types/linkify-it': 5.0.0
|
||||
'@types/mdurl': 2.0.0
|
||||
|
||||
'@types/mdurl@2.0.0': {}
|
||||
|
||||
'@types/node@22.0.0':
|
||||
dependencies:
|
||||
undici-types: 6.11.1
|
||||
@ -3397,6 +3869,8 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
vary: 1.1.2
|
||||
|
||||
crelt@1.0.6: {}
|
||||
|
||||
cross-spawn@7.0.3:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
@ -3519,10 +3993,6 @@ snapshots:
|
||||
dependencies:
|
||||
esutils: 2.0.3
|
||||
|
||||
docx-preview@0.3.7:
|
||||
dependencies:
|
||||
jszip: 3.10.1
|
||||
|
||||
docxtemplater@3.67.5:
|
||||
dependencies:
|
||||
'@xmldom/xmldom': 0.9.8
|
||||
@ -4299,6 +4769,12 @@ snapshots:
|
||||
dependencies:
|
||||
immediate: 3.0.6
|
||||
|
||||
linkify-it@5.0.0:
|
||||
dependencies:
|
||||
uc.micro: 2.1.0
|
||||
|
||||
linkifyjs@4.3.2: {}
|
||||
|
||||
loader-utils@1.4.2:
|
||||
dependencies:
|
||||
big.js: 5.2.2
|
||||
@ -4336,12 +4812,23 @@ snapshots:
|
||||
dependencies:
|
||||
object-visit: 1.0.1
|
||||
|
||||
markdown-it@14.1.0:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
entities: 4.5.0
|
||||
linkify-it: 5.0.0
|
||||
mdurl: 2.0.0
|
||||
punycode.js: 2.3.1
|
||||
uc.micro: 2.1.0
|
||||
|
||||
marked@17.0.1: {}
|
||||
|
||||
mdn-data@2.0.14: {}
|
||||
|
||||
mdn-data@2.0.30: {}
|
||||
|
||||
mdurl@2.0.0: {}
|
||||
|
||||
merge-options@1.0.1:
|
||||
dependencies:
|
||||
is-plain-obj: 1.1.0
|
||||
@ -4538,6 +5025,8 @@ snapshots:
|
||||
type-check: 0.4.0
|
||||
word-wrap: 1.2.5
|
||||
|
||||
orderedmap@2.1.1: {}
|
||||
|
||||
p-limit@3.1.0:
|
||||
dependencies:
|
||||
yocto-queue: 0.1.0
|
||||
@ -4663,8 +5152,113 @@ snapshots:
|
||||
|
||||
process-nextick-args@2.0.1: {}
|
||||
|
||||
prosemirror-changeset@2.3.1:
|
||||
dependencies:
|
||||
prosemirror-transform: 1.10.5
|
||||
|
||||
prosemirror-collab@1.3.1:
|
||||
dependencies:
|
||||
prosemirror-state: 1.4.4
|
||||
|
||||
prosemirror-commands@1.7.1:
|
||||
dependencies:
|
||||
prosemirror-model: 1.25.4
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-transform: 1.10.5
|
||||
|
||||
prosemirror-dropcursor@1.8.2:
|
||||
dependencies:
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-transform: 1.10.5
|
||||
prosemirror-view: 1.41.4
|
||||
|
||||
prosemirror-gapcursor@1.4.0:
|
||||
dependencies:
|
||||
prosemirror-keymap: 1.2.3
|
||||
prosemirror-model: 1.25.4
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-view: 1.41.4
|
||||
|
||||
prosemirror-history@1.5.0:
|
||||
dependencies:
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-transform: 1.10.5
|
||||
prosemirror-view: 1.41.4
|
||||
rope-sequence: 1.3.4
|
||||
|
||||
prosemirror-inputrules@1.5.1:
|
||||
dependencies:
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-transform: 1.10.5
|
||||
|
||||
prosemirror-keymap@1.2.3:
|
||||
dependencies:
|
||||
prosemirror-state: 1.4.4
|
||||
w3c-keyname: 2.2.8
|
||||
|
||||
prosemirror-markdown@1.13.2:
|
||||
dependencies:
|
||||
'@types/markdown-it': 14.1.2
|
||||
markdown-it: 14.1.0
|
||||
prosemirror-model: 1.25.4
|
||||
|
||||
prosemirror-menu@1.2.5:
|
||||
dependencies:
|
||||
crelt: 1.0.6
|
||||
prosemirror-commands: 1.7.1
|
||||
prosemirror-history: 1.5.0
|
||||
prosemirror-state: 1.4.4
|
||||
|
||||
prosemirror-model@1.25.4:
|
||||
dependencies:
|
||||
orderedmap: 2.1.1
|
||||
|
||||
prosemirror-schema-basic@1.2.4:
|
||||
dependencies:
|
||||
prosemirror-model: 1.25.4
|
||||
|
||||
prosemirror-schema-list@1.5.1:
|
||||
dependencies:
|
||||
prosemirror-model: 1.25.4
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-transform: 1.10.5
|
||||
|
||||
prosemirror-state@1.4.4:
|
||||
dependencies:
|
||||
prosemirror-model: 1.25.4
|
||||
prosemirror-transform: 1.10.5
|
||||
prosemirror-view: 1.41.4
|
||||
|
||||
prosemirror-tables@1.8.3:
|
||||
dependencies:
|
||||
prosemirror-keymap: 1.2.3
|
||||
prosemirror-model: 1.25.4
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-transform: 1.10.5
|
||||
prosemirror-view: 1.41.4
|
||||
|
||||
prosemirror-trailing-node@3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.4):
|
||||
dependencies:
|
||||
'@remirror/core-constants': 3.0.0
|
||||
escape-string-regexp: 4.0.0
|
||||
prosemirror-model: 1.25.4
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-view: 1.41.4
|
||||
|
||||
prosemirror-transform@1.10.5:
|
||||
dependencies:
|
||||
prosemirror-model: 1.25.4
|
||||
|
||||
prosemirror-view@1.41.4:
|
||||
dependencies:
|
||||
prosemirror-model: 1.25.4
|
||||
prosemirror-state: 1.4.4
|
||||
prosemirror-transform: 1.10.5
|
||||
|
||||
proxy-from-env@1.1.0: {}
|
||||
|
||||
punycode.js@2.3.1: {}
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
query-string@4.3.4:
|
||||
@ -4747,6 +5341,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
rope-sequence@1.3.4: {}
|
||||
|
||||
run-parallel@1.2.0:
|
||||
dependencies:
|
||||
queue-microtask: 1.2.3
|
||||
@ -4994,6 +5590,10 @@ snapshots:
|
||||
|
||||
text-table@0.2.0: {}
|
||||
|
||||
tippy.js@6.3.7:
|
||||
dependencies:
|
||||
'@popperjs/core': 2.11.8
|
||||
|
||||
to-fast-properties@2.0.0: {}
|
||||
|
||||
to-object-path@0.3.0:
|
||||
@ -5081,6 +5681,8 @@ snapshots:
|
||||
|
||||
typescript@5.5.4: {}
|
||||
|
||||
uc.micro@2.1.0: {}
|
||||
|
||||
ufo@1.5.4: {}
|
||||
|
||||
unbox-primitive@1.0.2:
|
||||
@ -5336,6 +5938,8 @@ snapshots:
|
||||
vooks: 0.2.12(vue@3.4.34(typescript@5.5.4))
|
||||
vue: 3.4.34(typescript@5.5.4)
|
||||
|
||||
w3c-keyname@2.2.8: {}
|
||||
|
||||
webpack-sources@3.2.3: {}
|
||||
|
||||
webpack-virtual-modules@0.6.2: {}
|
||||
|
||||
BIN
web/public/report_template.pdf
Normal file
BIN
web/public/report_template.pdf
Normal file
Binary file not shown.
@ -139,6 +139,29 @@ export const basicRoutes = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'ReportEditorNew',
|
||||
path: '/valuation/audit/editor-new',
|
||||
component: Layout,
|
||||
isHidden: true,
|
||||
meta: {
|
||||
title: '报告在线编辑(新)',
|
||||
icon: 'mdi:file-document-edit-outline',
|
||||
order: 100,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/valuation/audit/editor/new.vue'),
|
||||
name: 'ReportEditorNewPage',
|
||||
meta: {
|
||||
title: '报告在线编辑(新)',
|
||||
icon: 'mdi:file-document-edit-outline',
|
||||
order: 100,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Login',
|
||||
path: '/login',
|
||||
|
||||
@ -197,6 +197,22 @@ const handleOpenEditor = () => {
|
||||
router.push({ path: '/valuation/audit/editor', query })
|
||||
}
|
||||
|
||||
// 新版在线编辑
|
||||
const handleOpenEditorNew = () => {
|
||||
const detail = props.certificateData?.detailData
|
||||
if (!detail?.id) {
|
||||
message.error('缺少详情数据,无法打开新版编辑页')
|
||||
return
|
||||
}
|
||||
|
||||
const query = {
|
||||
valuationId: detail.id,
|
||||
templateId: detail.template_id || detail.templateId,
|
||||
title: detail.asset_name || detail.institution || '评估报告'
|
||||
}
|
||||
router.push({ path: '/valuation/audit/editor-new', query })
|
||||
}
|
||||
|
||||
// 文件预览
|
||||
const handlePreview = (file) => {
|
||||
// 对于非图片文件,显示提示
|
||||
@ -255,6 +271,9 @@ const handleSmsNotify = async () => {
|
||||
<NButton text type="info" @click="handleOpenEditor">
|
||||
在线编辑
|
||||
</NButton>
|
||||
<NButton text type="success" @click="handleOpenEditorNew">
|
||||
新版在线编辑
|
||||
</NButton>
|
||||
</div>
|
||||
<div class="upload-content">
|
||||
<NUpload
|
||||
|
||||
@ -17,6 +17,8 @@ const exporting = ref(false)
|
||||
const editorRef = ref(null)
|
||||
const htmlContent = ref('')
|
||||
const detailData = ref(null)
|
||||
const selectedBackground = ref(null)
|
||||
const customBackgroundUrl = ref('')
|
||||
|
||||
const pageMeta = computed(() => ({
|
||||
valuationId: route.query.valuationId || route.query.id,
|
||||
@ -41,6 +43,14 @@ const defaultHtml = `
|
||||
</div>
|
||||
`
|
||||
|
||||
const backgroundOptions = computed(() =>
|
||||
Object.entries(assetMap)
|
||||
.filter(([name]) => name.match(/\.(png|jpe?g|svg)$/i))
|
||||
.map(([name, url]) => ({ label: name, value: url }))
|
||||
)
|
||||
|
||||
const effectiveBackground = computed(() => customBackgroundUrl.value || selectedBackground.value || '')
|
||||
|
||||
const syncEditorContent = async () => {
|
||||
await nextTick()
|
||||
if (editorRef.value) {
|
||||
@ -90,7 +100,7 @@ const assetModules = import.meta.glob('../../../../assets/report_template/report
|
||||
as: 'url'
|
||||
})
|
||||
|
||||
// 构建文件名到 URL 的映射
|
||||
// 构建文件名到 URL 的映射,后续替换到模板中,避免 base64 膨胀
|
||||
const assetMap = {}
|
||||
Object.entries(assetModules).forEach(([path, url]) => {
|
||||
const filename = path.split('/').pop()
|
||||
@ -101,73 +111,46 @@ Object.entries(assetModules).forEach(([path, url]) => {
|
||||
|
||||
console.log('Asset Map:', assetMap)
|
||||
|
||||
// 将图片 URL 转换为 base64 data URL
|
||||
const convertToDataURL = async (url) => {
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
const blob = await response.blob()
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.onloadend = () => resolve(reader.result)
|
||||
reader.onerror = reject
|
||||
reader.readAsDataURL(blob)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Failed to convert to data URL:', url, error)
|
||||
return url
|
||||
}
|
||||
// 将引用的资源替换成构建后的绝对 URL,避免相对路径在 dataURL 中失效
|
||||
const mapAssetUrl = (rawUrl) => {
|
||||
if (!rawUrl) return rawUrl
|
||||
const clean = rawUrl.trim().replace(/^['"]|['"]$/g, '')
|
||||
if (/^data:/.test(clean) || /^(https?:)?\/\//.test(clean)) return clean
|
||||
const filename = clean.split('/').pop()?.split(/[?#]/)[0]
|
||||
if (filename && assetMap[filename]) return assetMap[filename]
|
||||
return clean
|
||||
}
|
||||
|
||||
// 将所有图片转换为 base64
|
||||
const convertAssetsToDataURLs = async () => {
|
||||
const dataURLMap = {}
|
||||
console.log('开始转换图片为 base64...')
|
||||
const replaceAssetUrlsInCss = (css) =>
|
||||
css.replace(/url\(([^)]+)\)/g, (match, url) => `url(${mapAssetUrl(url)})`)
|
||||
|
||||
const promises = Object.entries(assetMap).map(async ([filename, url]) => {
|
||||
// 只转换图片文件
|
||||
if (filename.match(/\.(png|jpg|jpeg|svg|gif)$/i)) {
|
||||
console.log(`转换图片: ${filename}`)
|
||||
const dataURL = await convertToDataURL(url)
|
||||
dataURLMap[filename] = dataURL
|
||||
console.log(`✓ ${filename} 转换完成,大小: ${(dataURL.length / 1024).toFixed(2)} KB`)
|
||||
} else {
|
||||
dataURLMap[filename] = url
|
||||
}
|
||||
const replaceAssetUrlsInHtml = (html) => {
|
||||
let processed = html
|
||||
|
||||
processed = processed.replace(/(href|src|data)=["']([^"']+)["']/g, (match, attr, url) => {
|
||||
const mapped = mapAssetUrl(url)
|
||||
return `${attr}="${mapped}"`
|
||||
})
|
||||
|
||||
await Promise.all(promises)
|
||||
console.log('所有图片转换完成:', Object.keys(dataURLMap).filter(k => k.match(/\.(png|jpg|jpeg|svg|gif)$/i)))
|
||||
return dataURLMap
|
||||
processed = processed.replace(/url\(([^)]+)\)/g, (match, url) => `url(${mapAssetUrl(url)})`)
|
||||
|
||||
// 处理 svg 内部的 xlink:href/href 引用
|
||||
processed = processed.replace(/(xlink:href|href)=["']([^"']+)["']/g, (match, attr, url) => {
|
||||
const mapped = mapAssetUrl(url)
|
||||
return `${attr}="${mapped}"`
|
||||
})
|
||||
|
||||
return processed
|
||||
}
|
||||
|
||||
const processTemplate = async (html, css) => {
|
||||
// 先转换所有图片为 base64
|
||||
const dataURLMap = await convertAssetsToDataURLs()
|
||||
// 1) CSS 中的字体、图片引用改为构建后的 URL
|
||||
const processedCss = replaceAssetUrlsInCss(css)
|
||||
|
||||
console.log('dataURLMap keys:', Object.keys(dataURLMap))
|
||||
// 2) HTML 中的资源引用(含内联 style、SVG href)替换为构建 URL
|
||||
let processedHtml = replaceAssetUrlsInHtml(html)
|
||||
|
||||
// 1. 处理 CSS 中的字体和图片引用
|
||||
let processedCss = css.replace(/url\(['"]?([^'"()]+)['"]?\)/g, (match, url) => {
|
||||
const filename = url.split('/').pop()
|
||||
if (filename && dataURLMap[filename]) {
|
||||
console.log(`CSS: 替换 ${filename}`)
|
||||
return `url(${dataURLMap[filename]})`
|
||||
}
|
||||
return match
|
||||
})
|
||||
|
||||
// 2. 处理 HTML 中的资源引用 (图片、对象等)
|
||||
let processedHtml = html.replace(/(href|src|data)=["'](?:\.\/)?report_template\/([^"')]+)["']/g, (match, attr, filename) => {
|
||||
const cleanFilename = filename.split(/[?#]/)[0]
|
||||
if (dataURLMap[cleanFilename]) {
|
||||
console.log(`HTML: 替换 ${attr}="${cleanFilename}" 为 base64`)
|
||||
return `${attr}="${dataURLMap[cleanFilename]}"`
|
||||
}
|
||||
console.warn(`HTML: 未找到 ${cleanFilename}`)
|
||||
return match
|
||||
})
|
||||
|
||||
// 3. 将 object/embed 标签转换为 img 标签
|
||||
// 3) 将 object/embed 标签转换为 img,便于编辑器展示
|
||||
let objectCount = 0
|
||||
processedHtml = processedHtml.replace(
|
||||
/<object([^>]*?)>[\s\S]*?<\/object>/g,
|
||||
@ -175,7 +158,7 @@ const processTemplate = async (html, css) => {
|
||||
const dataMatch = attrs.match(/data=["']([^"']+)["']/)
|
||||
if (!dataMatch) return match
|
||||
|
||||
const src = dataMatch[1]
|
||||
const src = mapAssetUrl(dataMatch[1])
|
||||
const classMatch = attrs.match(/class=["']([^"']+)["']/)
|
||||
const className = classMatch ? classMatch[1] : ''
|
||||
const styleMatch = attrs.match(/style=["']([^"']+)["']/)
|
||||
@ -190,16 +173,64 @@ const processTemplate = async (html, css) => {
|
||||
|
||||
console.log(`总共转换了 ${objectCount} 个 <object> 标签`)
|
||||
|
||||
// 4. 注入处理后的 CSS
|
||||
// 4) 注入处理后的 CSS
|
||||
processedHtml = processedHtml.replace(/<link[^>]+href=["'].*?style\.css["'][^>]*>/, '')
|
||||
processedHtml = processedHtml.replace('</head>', `<style>\n${processedCss}\n</style></head>`)
|
||||
|
||||
// 输出处理后 HTML 的前 500 个字符用于调试
|
||||
console.log('处理后的 HTML 预览:', processedHtml.substring(0, 500))
|
||||
|
||||
return processedHtml
|
||||
}
|
||||
|
||||
const applyCustomBackgroundToDom = () => {
|
||||
if (!editorRef.value) return
|
||||
const target = editorRef.value
|
||||
if (effectiveBackground.value) {
|
||||
target.style.backgroundImage = `url(${effectiveBackground.value})`
|
||||
target.style.backgroundSize = 'cover'
|
||||
target.style.backgroundRepeat = 'no-repeat'
|
||||
target.style.backgroundPosition = 'center top'
|
||||
} else {
|
||||
target.style.backgroundImage = ''
|
||||
target.style.backgroundSize = ''
|
||||
target.style.backgroundRepeat = ''
|
||||
target.style.backgroundPosition = ''
|
||||
}
|
||||
}
|
||||
|
||||
const injectBackgroundIntoHtml = (html) => {
|
||||
if (!effectiveBackground.value || !html) return html
|
||||
const styleTag = `<style id="custom-bg-style">body{background-image:url('${effectiveBackground.value}');background-size:cover;background-repeat:no-repeat;background-position:center top;}</style>`
|
||||
|
||||
if (html.includes('id="custom-bg-style"')) {
|
||||
return html.replace(/<style id="custom-bg-style">[\s\S]*?<\/style>/, styleTag)
|
||||
}
|
||||
if (html.includes('</head>')) {
|
||||
return html.replace('</head>', `${styleTag}</head>`)
|
||||
}
|
||||
return `${styleTag}${html}`
|
||||
}
|
||||
|
||||
const handleBackgroundSelect = (value) => {
|
||||
selectedBackground.value = value || ''
|
||||
if (value) customBackgroundUrl.value = ''
|
||||
applyCustomBackgroundToDom()
|
||||
}
|
||||
|
||||
const handleBackgroundUpload = (event) => {
|
||||
const file = event?.target?.files?.[0]
|
||||
if (!file) return
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => {
|
||||
customBackgroundUrl.value = reader.result
|
||||
selectedBackground.value = ''
|
||||
applyCustomBackgroundToDom()
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
|
||||
watch(effectiveBackground, applyCustomBackgroundToDom)
|
||||
|
||||
const loadTemplate = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
@ -212,6 +243,7 @@ const loadTemplate = async () => {
|
||||
editorRef.value.innerHTML = html
|
||||
editorRef.value.setAttribute('contenteditable', 'true')
|
||||
htmlContent.value = html
|
||||
applyCustomBackgroundToDom()
|
||||
} else {
|
||||
await syncEditorContent()
|
||||
}
|
||||
@ -315,12 +347,13 @@ const handleSave = async () => {
|
||||
message.warning('暂无内容可保存')
|
||||
return
|
||||
}
|
||||
const htmlToPersist = injectBackgroundIntoHtml(htmlContent.value)
|
||||
saving.value = true
|
||||
try {
|
||||
await api.saveReportDraft({
|
||||
valuation_id: pageMeta.value.valuationId,
|
||||
template_id: pageMeta.value.templateId,
|
||||
html: htmlContent.value,
|
||||
html: htmlToPersist,
|
||||
})
|
||||
message.success('草稿已保存')
|
||||
} catch (error) {
|
||||
@ -336,11 +369,13 @@ const handleExport = async () => {
|
||||
message.error('缺少参数,无法导出')
|
||||
return
|
||||
}
|
||||
const htmlToPersist = injectBackgroundIntoHtml(htmlContent.value)
|
||||
exporting.value = true
|
||||
try {
|
||||
const res = await api.exportReportTemplate({
|
||||
valuation_id: pageMeta.value.valuationId,
|
||||
template_id: pageMeta.value.templateId,
|
||||
html: htmlToPersist,
|
||||
})
|
||||
const blob = res instanceof Blob ? res : new Blob([res])
|
||||
const fileName = `${pageMeta.value.title || '报告'}.pdf`
|
||||
@ -425,6 +460,26 @@ onMounted(loadTemplate)
|
||||
<input type="color" @input="applyBackColor" />
|
||||
</label>
|
||||
</NSpace>
|
||||
<div class="bg-controls">
|
||||
<span class="bg-label">背景</span>
|
||||
<NSelect
|
||||
size="small"
|
||||
style="width: 180px"
|
||||
placeholder="选择模板背景"
|
||||
:options="backgroundOptions"
|
||||
@update:value="handleBackgroundSelect"
|
||||
clearable
|
||||
/>
|
||||
<label class="bg-upload">
|
||||
自定义
|
||||
<input type="file" accept="image/*" @change="handleBackgroundUpload" />
|
||||
</label>
|
||||
<span
|
||||
v-if="effectiveBackground"
|
||||
class="bg-preview"
|
||||
:style="{ backgroundImage: `url(${effectiveBackground})` }"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NSpin :show="loading">
|
||||
@ -498,6 +553,32 @@ onMounted(loadTemplate)
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.bg-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.bg-label {
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.bg-upload input {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.bg-preview {
|
||||
width: 44px;
|
||||
height: 30px;
|
||||
border: 1px solid #e0e4eb;
|
||||
border-radius: 6px;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.editor-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
630
web/src/views/valuation/audit/editor/new.vue
Normal file
630
web/src/views/valuation/audit/editor/new.vue
Normal file
@ -0,0 +1,630 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { NButton, NSelect, NSpace, NSpin, NTag, useMessage } from 'naive-ui'
|
||||
import { saveAs } from 'file-saver'
|
||||
import { useEditor, EditorContent } from '@tiptap/vue-3'
|
||||
import { Extension, Node, mergeAttributes } from '@tiptap/core'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import Underline from '@tiptap/extension-underline'
|
||||
import TextStyle from '@tiptap/extension-text-style'
|
||||
import Color from '@tiptap/extension-color'
|
||||
import TextAlign from '@tiptap/extension-text-align'
|
||||
import Image from '@tiptap/extension-image'
|
||||
import Link from '@tiptap/extension-link'
|
||||
|
||||
import CommonPage from '@/components/page/CommonPage.vue'
|
||||
import api from '@/api'
|
||||
|
||||
// 新版编辑器:使用 TipTap 提供更稳定的光标/撤销/样式体验
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const message = useMessage()
|
||||
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const exporting = ref(false)
|
||||
const htmlContent = ref('')
|
||||
const detailData = ref(null)
|
||||
const selectedBackground = ref(null)
|
||||
const customBackgroundUrl = ref('')
|
||||
const editorMountRef = ref(null)
|
||||
|
||||
const pageMeta = computed(() => ({
|
||||
valuationId: route.query.valuationId || route.query.id,
|
||||
templateId: route.query.templateId,
|
||||
title: route.query.title || '评估报告',
|
||||
}))
|
||||
|
||||
const defaultHtml = `
|
||||
<div class="doc-header">
|
||||
<h1>新版在线编辑</h1>
|
||||
<p>这里是新版富文本编辑入口,可自由编辑内容并切换背景。</p>
|
||||
</div>
|
||||
<div class="doc-block">
|
||||
<h2>正文示例</h2>
|
||||
<p>可粘贴 Word/网页内容,或直接编辑。</p>
|
||||
</div>
|
||||
`
|
||||
|
||||
// 导入模板和样式
|
||||
import templateHtmlRaw from '@/assets/report_template/report_template.html?raw'
|
||||
import styleCssRaw from '@/assets/report_template/report_template/style.css?raw'
|
||||
|
||||
// 导入所有资源文件,使用 eager 和 as: 'url' 来获取正确的 URL
|
||||
const assetModules = import.meta.glob('../../../../assets/report_template/report_template/*.*', {
|
||||
eager: true,
|
||||
as: 'url'
|
||||
})
|
||||
|
||||
// 构建文件名到 URL 的映射,后续替换到模板中
|
||||
const assetMap = {}
|
||||
Object.entries(assetModules).forEach(([path, url]) => {
|
||||
const filename = path.split('/').pop()
|
||||
if (filename) assetMap[filename] = url
|
||||
})
|
||||
|
||||
const backgroundOptions = computed(() =>
|
||||
Object.entries(assetMap)
|
||||
.filter(([name]) => name.match(/\.(png|jpe?g|svg)$/i))
|
||||
.map(([name, url]) => ({ label: name, value: url }))
|
||||
)
|
||||
|
||||
// 允许保留 class/style/id 等属性,避免模板样式被裁剪
|
||||
const GlobalAttrs = Extension.create({
|
||||
name: 'globalAttrs',
|
||||
addGlobalAttributes() {
|
||||
return [
|
||||
{
|
||||
types: ['paragraph', 'heading', 'textStyle', 'image', 'bulletList', 'orderedList', 'listItem', 'doc', 'div', 'text'],
|
||||
attributes: {
|
||||
class: { default: null },
|
||||
style: { default: null },
|
||||
id: { default: null },
|
||||
'data-*': { default: null },
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
})
|
||||
|
||||
// 支持原模板中的 div 结构,保留属性用于绝对定位等样式
|
||||
const Div = Node.create({
|
||||
name: 'div',
|
||||
group: 'block',
|
||||
content: 'inline*',
|
||||
parseHTML() {
|
||||
return [{ tag: 'div' }]
|
||||
},
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['div', mergeAttributes(HTMLAttributes), 0]
|
||||
},
|
||||
})
|
||||
|
||||
const effectiveBackground = computed(() => customBackgroundUrl.value || selectedBackground.value || '')
|
||||
|
||||
const ensureDetailData = async () => {
|
||||
if (detailData.value || !pageMeta.value.valuationId) return
|
||||
try {
|
||||
const { data } = await api.getValuationById({ valuation_id: pageMeta.value.valuationId })
|
||||
detailData.value = data
|
||||
} catch (error) {
|
||||
console.error('获取详情数据失败', error)
|
||||
message.warning('未获取到估值详情,占位符将无法替换')
|
||||
}
|
||||
}
|
||||
|
||||
const formatDateVars = () => {
|
||||
const now = new Date()
|
||||
const yyyy = String(now.getFullYear())
|
||||
const mm = String(now.getMonth() + 1).padStart(2, '0')
|
||||
const dd = String(now.getDate()).padStart(2, '0')
|
||||
return { yyyy, mm, dd, yyyymmdd: `${yyyy}${mm}${dd}` }
|
||||
}
|
||||
|
||||
const applyTemplateVars = (html) => {
|
||||
if (!html) return html
|
||||
const vars = {
|
||||
asset_name: detailData.value?.asset_name || detailData.value?.institution || '',
|
||||
...formatDateVars(),
|
||||
...detailData.value,
|
||||
}
|
||||
return html.replace(/\$\{([^}]+)\}/g, (_, key) => {
|
||||
const val = vars[key]
|
||||
return val !== undefined && val !== null ? String(val) : ''
|
||||
})
|
||||
}
|
||||
|
||||
// 资源替换工具
|
||||
const mapAssetUrl = (rawUrl) => {
|
||||
if (!rawUrl) return rawUrl
|
||||
const clean = rawUrl.trim().replace(/^['"]|['"]$/g, '')
|
||||
if (/^data:/.test(clean) || /^(https?:)?\/\//.test(clean)) return clean
|
||||
const filename = clean.split('/').pop()?.split(/[?#]/)[0]
|
||||
if (filename && assetMap[filename]) return assetMap[filename]
|
||||
return clean
|
||||
}
|
||||
|
||||
const replaceAssetUrlsInCss = (css) =>
|
||||
css.replace(/url\(([^)]+)\)/g, (match, url) => `url(${mapAssetUrl(url)})`)
|
||||
|
||||
const replaceAssetUrlsInHtml = (html) => {
|
||||
let processed = html
|
||||
|
||||
processed = processed.replace(/(href|src|data)=["']([^"']+)["']/g, (match, attr, url) => {
|
||||
const mapped = mapAssetUrl(url)
|
||||
return `${attr}="${mapped}"`
|
||||
})
|
||||
|
||||
processed = processed.replace(/url\(([^)]+)\)/g, (match, url) => `url(${mapAssetUrl(url)})`)
|
||||
|
||||
processed = processed.replace(/(xlink:href|href)=["']([^"']+)["']/g, (match, attr, url) => {
|
||||
const mapped = mapAssetUrl(url)
|
||||
return `${attr}="${mapped}"`
|
||||
})
|
||||
|
||||
return processed
|
||||
}
|
||||
|
||||
const processTemplate = async (html, css) => {
|
||||
const processedCss = replaceAssetUrlsInCss(css)
|
||||
let processedHtml = replaceAssetUrlsInHtml(html)
|
||||
|
||||
processedHtml = processedHtml.replace(
|
||||
/<object([^>]*?)>[\s\S]*?<\/object>/g,
|
||||
(match, attrs) => {
|
||||
const dataMatch = attrs.match(/data=["']([^"']+)["']/)
|
||||
if (!dataMatch) return match
|
||||
|
||||
const src = mapAssetUrl(dataMatch[1])
|
||||
const classMatch = attrs.match(/class=["']([^"']+)["']/)
|
||||
const className = classMatch ? classMatch[1] : ''
|
||||
const styleMatch = attrs.match(/style=["']([^"']+)["']/)
|
||||
const style = styleMatch ? styleMatch[1] : ''
|
||||
|
||||
return `<img src="${src}" class="${className}" style="${style}" />`
|
||||
}
|
||||
)
|
||||
|
||||
// 移除 head/link,只保留 body 内容供编辑器使用
|
||||
const bodyMatch = processedHtml.match(/<body[^>]*>([\s\S]*?)<\/body>/i)
|
||||
const bodyContent = bodyMatch ? bodyMatch[1] : processedHtml
|
||||
|
||||
return { bodyContent, processedCss }
|
||||
}
|
||||
|
||||
const applyCustomBackgroundToDom = () => {
|
||||
if (!editorMountRef.value) return
|
||||
const target = editorMountRef.value
|
||||
if (effectiveBackground.value) {
|
||||
target.style.backgroundImage = `url(${effectiveBackground.value})`
|
||||
target.style.backgroundSize = 'cover'
|
||||
target.style.backgroundRepeat = 'no-repeat'
|
||||
target.style.backgroundPosition = 'center top'
|
||||
} else {
|
||||
target.style.backgroundImage = ''
|
||||
target.style.backgroundSize = ''
|
||||
target.style.backgroundRepeat = ''
|
||||
target.style.backgroundPosition = ''
|
||||
}
|
||||
}
|
||||
|
||||
const applyTemplateStyle = (css) => {
|
||||
if (!css) return
|
||||
const styleId = 'report-template-style'
|
||||
let styleEl = document.getElementById(styleId)
|
||||
if (!styleEl) {
|
||||
styleEl = document.createElement('style')
|
||||
styleEl.id = styleId
|
||||
document.head.appendChild(styleEl)
|
||||
}
|
||||
styleEl.textContent = css
|
||||
}
|
||||
|
||||
const injectBackgroundIntoHtml = (html) => {
|
||||
if (!effectiveBackground.value || !html) return html
|
||||
const styleTag = `<style id="custom-bg-style">body{background-image:url('${effectiveBackground.value}');background-size:cover;background-repeat:no-repeat;background-position:center top;}</style>`
|
||||
|
||||
if (html.includes('id="custom-bg-style"')) {
|
||||
return html.replace(/<style id="custom-bg-style">[\s\S]*?<\/style>/, styleTag)
|
||||
}
|
||||
if (html.includes('</head>')) {
|
||||
return html.replace('</head>', `${styleTag}</head>`)
|
||||
}
|
||||
return `${styleTag}${html}`
|
||||
}
|
||||
|
||||
const handleBackgroundSelect = (value) => {
|
||||
selectedBackground.value = value || ''
|
||||
if (value) customBackgroundUrl.value = ''
|
||||
applyCustomBackgroundToDom()
|
||||
}
|
||||
|
||||
const handleBackgroundUpload = (event) => {
|
||||
const file = event?.target?.files?.[0]
|
||||
if (!file) return
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => {
|
||||
customBackgroundUrl.value = reader.result
|
||||
selectedBackground.value = ''
|
||||
applyCustomBackgroundToDom()
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
|
||||
watch(effectiveBackground, applyCustomBackgroundToDom)
|
||||
|
||||
const editor = useEditor({
|
||||
content: defaultHtml,
|
||||
extensions: [
|
||||
StarterKit.configure({
|
||||
heading: { levels: [1, 2, 3, 4] },
|
||||
bulletList: { keepMarks: true },
|
||||
orderedList: { keepMarks: true },
|
||||
}),
|
||||
Div,
|
||||
GlobalAttrs,
|
||||
Underline,
|
||||
TextStyle,
|
||||
Color,
|
||||
TextAlign.configure({ types: ['heading', 'paragraph', 'div'] }),
|
||||
Image.configure({ inline: false }),
|
||||
Link.configure({ openOnClick: false }),
|
||||
],
|
||||
parseOptions: {
|
||||
preserveWhitespace: 'full',
|
||||
},
|
||||
editorProps: {
|
||||
attributes: {
|
||||
class: 'tiptap tiptap-template',
|
||||
},
|
||||
},
|
||||
onUpdate: ({ editor }) => {
|
||||
htmlContent.value = editor.getHTML()
|
||||
},
|
||||
})
|
||||
|
||||
const loadTemplate = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await ensureDetailData()
|
||||
|
||||
const { bodyContent, processedCss } = await processTemplate(templateHtmlRaw, styleCssRaw)
|
||||
const finalHtml = applyTemplateVars(bodyContent || defaultHtml)
|
||||
|
||||
if (editor.value) {
|
||||
editor.value.commands.setContent(finalHtml)
|
||||
htmlContent.value = finalHtml
|
||||
applyTemplateStyle(processedCss)
|
||||
applyCustomBackgroundToDom()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载模板失败', error)
|
||||
message.error('加载模板失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getHtmlWithBg = () => injectBackgroundIntoHtml(htmlContent.value || editor.value?.getHTML() || '')
|
||||
|
||||
const handleSave = async () => {
|
||||
const htmlToPersist = getHtmlWithBg()
|
||||
if (!htmlToPersist) {
|
||||
message.warning('暂无内容可保存')
|
||||
return
|
||||
}
|
||||
saving.value = true
|
||||
try {
|
||||
await api.saveReportDraft({
|
||||
valuation_id: pageMeta.value.valuationId,
|
||||
template_id: pageMeta.value.templateId,
|
||||
html: htmlToPersist,
|
||||
})
|
||||
message.success('草稿已保存')
|
||||
} catch (error) {
|
||||
console.error('保存失败', error)
|
||||
message.error(error?.message || '保存失败,请稍后重试')
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleExport = async () => {
|
||||
if (!pageMeta.value.valuationId) {
|
||||
message.error('缺少参数,无法导出')
|
||||
return
|
||||
}
|
||||
const htmlToPersist = getHtmlWithBg()
|
||||
exporting.value = true
|
||||
try {
|
||||
const res = await api.exportReportTemplate({
|
||||
valuation_id: pageMeta.value.valuationId,
|
||||
template_id: pageMeta.value.templateId,
|
||||
html: htmlToPersist,
|
||||
})
|
||||
const blob = res instanceof Blob ? res : new Blob([res])
|
||||
const fileName = `${pageMeta.value.title || '报告'}.pdf`
|
||||
saveAs(blob, fileName)
|
||||
message.success('导出成功')
|
||||
} catch (error) {
|
||||
console.error('导出失败', error)
|
||||
message.error('导出失败,请检查后端接口')
|
||||
} finally {
|
||||
exporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleBack = () => router.back()
|
||||
|
||||
const applyTextAlign = (value) => editor.value?.chain().focus().setTextAlign(value).run()
|
||||
const toggleBold = () => editor.value?.chain().focus().toggleBold().run()
|
||||
const toggleItalic = () => editor.value?.chain().focus().toggleItalic().run()
|
||||
const toggleUnderline = () => editor.value?.chain().focus().toggleUnderline().run()
|
||||
const toggleBullet = () => editor.value?.chain().focus().toggleBulletList().run()
|
||||
const toggleOrdered = () => editor.value?.chain().focus().toggleOrderedList().run()
|
||||
const undo = () => editor.value?.chain().focus().undo().run()
|
||||
const redo = () => editor.value?.chain().focus().redo().run()
|
||||
const setFontSize = (size) => editor.value?.chain().focus().setMark('textStyle', { fontSize: `${size}px` }).run()
|
||||
const setLineHeight = (height) => editor.value?.chain().focus().setMark('textStyle', { lineHeight: height }).run()
|
||||
const setTextColor = (color) => editor.value?.chain().focus().setColor(color).run()
|
||||
const setBgColor = (color) => editor.value?.chain().focus().setMark('textStyle', { backgroundColor: color }).run()
|
||||
const removeFormat = () => editor.value?.chain().focus().unsetAllMarks().clearNodes().run()
|
||||
const insertImage = () => {
|
||||
const url = window.prompt('输入图片地址:')
|
||||
if (url) editor.value?.chain().focus().setImage({ src: url }).run()
|
||||
}
|
||||
const setLink = () => {
|
||||
const url = window.prompt('输入链接地址:')
|
||||
if (url === null) return
|
||||
if (url === '') {
|
||||
editor.value?.chain().focus().unsetLink().run()
|
||||
return
|
||||
}
|
||||
editor.value?.chain().focus().setLink({ href: url, target: '_blank' }).run()
|
||||
}
|
||||
|
||||
const fontSizeOptions = [12, 14, 16, 18, 20, 24].map((v) => ({ label: `${v}px`, value: v }))
|
||||
const lineHeightOptions = ['1.2', '1.5', '1.8', '2'].map((v) => ({ label: v, value: v }))
|
||||
|
||||
onMounted(loadTemplate)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CommonPage title="报告在线编辑(新)" :show-footer="false">
|
||||
<template #header>
|
||||
<div class="editor-page__header">
|
||||
<div class="title">
|
||||
<h2>{{ pageMeta.title || '报告在线编辑(新)' }}</h2>
|
||||
<div class="meta">
|
||||
<NTag size="small" type="info">估值ID:{{ pageMeta.valuationId || '未知' }}</NTag>
|
||||
<NTag v-if="pageMeta.templateId" size="small" type="success">
|
||||
模板ID:{{ pageMeta.templateId }}
|
||||
</NTag>
|
||||
<NTag size="small" type="warning">新版入口</NTag>
|
||||
</div>
|
||||
</div>
|
||||
<NSpace>
|
||||
<NButton @click="handleBack">返回</NButton>
|
||||
<NButton secondary @click="handleSave" :loading="saving">保存草稿</NButton>
|
||||
<NButton type="primary" @click="handleExport" :loading="exporting">
|
||||
导出 PDF
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="editor-page">
|
||||
<div class="editor-toolbar">
|
||||
<NSpace wrap>
|
||||
<NButton size="small" @click="toggleBold">加粗</NButton>
|
||||
<NButton size="small" @click="toggleItalic">斜体</NButton>
|
||||
<NButton size="small" @click="toggleUnderline">下划线</NButton>
|
||||
<NButton size="small" @click="() => applyTextAlign('left')">左对齐</NButton>
|
||||
<NButton size="small" @click="() => applyTextAlign('center')">居中</NButton>
|
||||
<NButton size="small" @click="() => applyTextAlign('right')">右对齐</NButton>
|
||||
<NButton size="small" @click="toggleBullet">无序列表</NButton>
|
||||
<NButton size="small" @click="toggleOrdered">有序列表</NButton>
|
||||
<NButton size="small" @click="removeFormat">清除格式</NButton>
|
||||
<NButton size="small" @click="undo">撤销</NButton>
|
||||
<NButton size="small" @click="redo">重做</NButton>
|
||||
<NButton size="small" @click="insertImage">插入图片</NButton>
|
||||
<NButton size="small" @click="setLink">链接</NButton>
|
||||
</NSpace>
|
||||
<NSpace wrap>
|
||||
<NSelect
|
||||
size="small"
|
||||
style="width: 120px"
|
||||
placeholder="字号"
|
||||
:options="fontSizeOptions"
|
||||
@update:value="setFontSize"
|
||||
/>
|
||||
<NSelect
|
||||
size="small"
|
||||
style="width: 120px"
|
||||
placeholder="行距"
|
||||
:options="lineHeightOptions"
|
||||
@update:value="setLineHeight"
|
||||
/>
|
||||
<label class="color-picker">
|
||||
文字色
|
||||
<input type="color" @input="(e) => setTextColor(e.target.value)" />
|
||||
</label>
|
||||
<label class="color-picker">
|
||||
背景色
|
||||
<input type="color" @input="(e) => setBgColor(e.target.value)" />
|
||||
</label>
|
||||
</NSpace>
|
||||
<div class="bg-controls">
|
||||
<span class="bg-label">背景</span>
|
||||
<NSelect
|
||||
size="small"
|
||||
style="width: 180px"
|
||||
placeholder="选择模板背景"
|
||||
:options="backgroundOptions"
|
||||
@update:value="handleBackgroundSelect"
|
||||
clearable
|
||||
/>
|
||||
<label class="bg-upload">
|
||||
自定义
|
||||
<input type="file" accept="image/*" @change="handleBackgroundUpload" />
|
||||
</label>
|
||||
<span
|
||||
v-if="effectiveBackground"
|
||||
class="bg-preview"
|
||||
:style="{ backgroundImage: `url(${effectiveBackground})` }"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NSpin :show="loading">
|
||||
<div class="editor-wrapper">
|
||||
<div ref="editorMountRef" class="editor-canvas">
|
||||
<EditorContent :editor="editor" />
|
||||
</div>
|
||||
</div>
|
||||
</NSpin>
|
||||
</div>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.editor-page__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.editor-page__header .title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.editor-page__header h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.editor-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.editor-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #f7f7f9;
|
||||
border: 1px solid #e0e4eb;
|
||||
border-radius: 10px;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.color-picker {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.color-picker input {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.bg-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.bg-label {
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.bg-upload input {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.bg-preview {
|
||||
width: 44px;
|
||||
height: 30px;
|
||||
border: 1px solid #e0e4eb;
|
||||
border-radius: 6px;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.editor-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 12px 0 24px;
|
||||
}
|
||||
|
||||
.editor-canvas {
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
padding: 12px;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.editor-canvas:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.doc-header h1 {
|
||||
margin: 0 0 10px;
|
||||
font-size: 22px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.doc-header p {
|
||||
margin: 0 0 18px;
|
||||
color: #555;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.doc-block h2 {
|
||||
margin: 18px 0 8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.doc-block p {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
/* TipTap 默认内容样式轻度调整,使其接近文档排版 */
|
||||
.tiptap {
|
||||
min-height: 380px;
|
||||
line-height: 1.8;
|
||||
font-size: 14px;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tiptap p { margin: 0 0 10px; }
|
||||
.tiptap h1, .tiptap h2, .tiptap h3, .tiptap h4 { margin: 14px 0 10px; }
|
||||
.tiptap ul, .tiptap ol { padding-left: 22px; margin: 10px 0; }
|
||||
.tiptap img { max-width: 100%; height: auto; }
|
||||
/* 让模板类名的样式能够影响编辑区域 */
|
||||
.tiptap-template :deep(*) {
|
||||
position: inherit;
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user