This commit is contained in:
2026-06-18 17:17:26 +08:00
parent 064bf14a5a
commit 4b4f1d1715
9 changed files with 577 additions and 92 deletions

View File

@@ -12,6 +12,8 @@
"@vueuse/core": "^11.3.0",
"axios": "^1.7.7",
"echarts": "^5.5.1",
"html2canvas": "^1.4.1",
"jspdf": "^4.2.1",
"lodash": "^4.17.21",
"vant": "^4.9.9",
"vue": "^3.5.12",

199
pnpm-lock.yaml generated
View File

@@ -17,6 +17,12 @@ importers:
echarts:
specifier: ^5.5.1
version: 5.6.0
html2canvas:
specifier: ^1.4.1
version: 1.4.1
jspdf:
specifier: ^4.2.1
version: 4.2.1
lodash:
specifier: ^4.17.21
version: 4.17.21
@@ -181,6 +187,10 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/runtime@7.29.7':
resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==}
engines: {node: '>=6.9.0'}
'@babel/template@7.27.2':
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
engines: {node: '>=6.9.0'}
@@ -398,42 +408,36 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@@ -507,67 +511,56 @@ packages:
resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.53.2':
resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.53.2':
resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.53.2':
resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.53.2':
resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.53.2':
resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.53.2':
resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.53.2':
resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.53.2':
resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.53.2':
resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.53.2':
resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-openharmony-arm64@4.53.2':
resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==}
@@ -597,6 +590,15 @@ packages:
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/pako@2.0.4':
resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==}
'@types/raf@3.4.3':
resolution: {integrity: sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==}
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
'@types/web-bluetooth@0.0.20':
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
@@ -729,6 +731,10 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
base64-arraybuffer@1.0.2:
resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
engines: {node: '>= 0.6.0'}
baseline-browser-mapping@2.8.29:
resolution: {integrity: sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==}
hasBin: true
@@ -766,6 +772,10 @@ packages:
caniuse-lite@1.0.30001756:
resolution: {integrity: sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==}
canvg@3.0.11:
resolution: {integrity: sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==}
engines: {node: '>=10.0.0'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
@@ -804,10 +814,16 @@ packages:
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
core-js@3.49.0:
resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
css-line-break@2.1.0:
resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
@@ -840,6 +856,9 @@ packages:
dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
dompurify@3.4.11:
resolution: {integrity: sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@@ -905,9 +924,15 @@ packages:
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
engines: {node: '>=8.6.0'}
fast-png@6.4.0:
resolution: {integrity: sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==}
fastq@1.19.1:
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
fflate@0.8.3:
resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==}
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
@@ -984,9 +1009,16 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
html2canvas@1.4.1:
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
engines: {node: '>=8.0.0'}
immutable@5.1.4:
resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==}
iobuffer@5.4.0:
resolution: {integrity: sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==}
is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
@@ -1037,6 +1069,9 @@ packages:
engines: {node: '>=6'}
hasBin: true
jspdf@4.2.1:
resolution: {integrity: sha512-YyAXyvnmjTbR4bHQRLzex3CuINCDlQnBqoSYyjJwTP2x9jDLuKDzy7aKUl0hgx3uhcl7xzg32agn5vlie6HIlQ==}
lilconfig@3.1.3:
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
engines: {node: '>=14'}
@@ -1131,6 +1166,9 @@ packages:
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
pako@2.1.0:
resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
@@ -1145,6 +1183,9 @@ packages:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
performance-now@2.1.0:
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -1226,6 +1267,9 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
raf@3.4.1:
resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
@@ -1237,6 +1281,9 @@ packages:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
regenerator-runtime@0.13.11:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
resolve@1.22.11:
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
engines: {node: '>= 0.4'}
@@ -1246,6 +1293,10 @@ packages:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
rgbcolor@1.0.1:
resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==}
engines: {node: '>= 0.8.15'}
rollup@4.53.2:
resolution: {integrity: sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -1302,56 +1353,48 @@ packages:
engines: {node: '>=14.0.0'}
cpu: [arm64]
os: [linux]
libc: glibc
sass-embedded-linux-arm@1.93.3:
resolution: {integrity: sha512-yeiv2y+dp8B4wNpd3+JsHYD0mvpXSfov7IGyQ1tMIR40qv+ROkRqYiqQvAOXf76Qwh4Y9OaYZtLpnsPjfeq6mA==}
engines: {node: '>=14.0.0'}
cpu: [arm]
os: [linux]
libc: glibc
sass-embedded-linux-musl-arm64@1.93.3:
resolution: {integrity: sha512-PS829l+eUng+9W4PFclXGb4uA2+965NHV3/Sa5U7qTywjeeUUYTZg70dJHSqvhrBEfCc2XJABeW3adLJbyQYkw==}
engines: {node: '>=14.0.0'}
cpu: [arm64]
os: [linux]
libc: musl
sass-embedded-linux-musl-arm@1.93.3:
resolution: {integrity: sha512-fU0fwAwbp7sBE3h5DVU5UPzvaLg7a4yONfFWkkcCp6ZrOiPuGRHXXYriWQ0TUnWy4wE+svsVuWhwWgvlb/tkKg==}
engines: {node: '>=14.0.0'}
cpu: [arm]
os: [linux]
libc: musl
sass-embedded-linux-musl-riscv64@1.93.3:
resolution: {integrity: sha512-cK1oBY+FWQquaIGEeQ5H74KTO8cWsSWwXb/WaildOO9U6wmUypTgUYKQ0o5o/29nZbWWlM1PHuwVYTSnT23Jjg==}
engines: {node: '>=14.0.0'}
cpu: [riscv64]
os: [linux]
libc: musl
sass-embedded-linux-musl-x64@1.93.3:
resolution: {integrity: sha512-A7wkrsHu2/I4Zpa0NMuPGkWDVV7QGGytxGyUq3opSXgAexHo/vBPlGoDXoRlSdex0cV+aTMRPjoGIfdmNlHwyg==}
engines: {node: '>=14.0.0'}
cpu: [x64]
os: [linux]
libc: musl
sass-embedded-linux-riscv64@1.93.3:
resolution: {integrity: sha512-vWkW1+HTF5qcaHa6hO80gx/QfB6GGjJUP0xLbnAoY4pwEnw5ulGv6RM8qYr8IDhWfVt/KH+lhJ2ZFxnJareisQ==}
engines: {node: '>=14.0.0'}
cpu: [riscv64]
os: [linux]
libc: glibc
sass-embedded-linux-x64@1.93.3:
resolution: {integrity: sha512-k6uFxs+e5jSuk1Y0niCwuq42F9ZC5UEP7P+RIOurIm8w/5QFa0+YqeW+BPWEW5M1FqVOsNZH3qGn4ahqvAEjPA==}
engines: {node: '>=14.0.0'}
cpu: [x64]
os: [linux]
libc: glibc
sass-embedded-unknown-all@1.93.3:
resolution: {integrity: sha512-o5wj2rLpXH0C+GJKt/VpWp6AnMsCCbfFmnMAttcrsa+U3yrs/guhZ3x55KAqqUsE8F47e3frbsDL+1OuQM5DAA==}
@@ -1409,6 +1452,10 @@ packages:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
stackblur-canvas@2.7.0:
resolution: {integrity: sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==}
engines: {node: '>=0.1.14'}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@@ -1441,6 +1488,10 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
svg-pathdata@6.0.3:
resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==}
engines: {node: '>=12.0.0'}
sync-child-process@1.0.2:
resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==}
engines: {node: '>=16.0.0'}
@@ -1459,6 +1510,9 @@ packages:
engines: {node: '>=10'}
hasBin: true
text-segmentation@1.0.3:
resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
thenify-all@1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
engines: {node: '>=0.8'}
@@ -1523,6 +1577,9 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
utrie@1.0.2:
resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
vant@4.9.21:
resolution: {integrity: sha512-hXUoZMrLLjykimFRLDlGNd+K2iYSRh9YwLMKnsVdVZ+9inUKxpqnjhOqlZwocbnYkvJlS+febf9u9aJpDol4Pw==}
peerDependencies:
@@ -1779,6 +1836,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@babel/runtime@7.29.7': {}
'@babel/template@7.27.2':
dependencies:
'@babel/code-frame': 7.27.1
@@ -2060,6 +2119,14 @@ snapshots:
'@types/estree@1.0.8': {}
'@types/pako@2.0.4': {}
'@types/raf@3.4.3':
optional: true
'@types/trusted-types@2.0.7':
optional: true
'@types/web-bluetooth@0.0.20': {}
'@vant/auto-import-resolver@1.3.0': {}
@@ -2233,6 +2300,8 @@ snapshots:
balanced-match@1.0.2: {}
base64-arraybuffer@1.0.2: {}
baseline-browser-mapping@2.8.29: {}
binary-extensions@2.3.0: {}
@@ -2266,6 +2335,18 @@ snapshots:
caniuse-lite@1.0.30001756: {}
canvg@3.0.11:
dependencies:
'@babel/runtime': 7.29.7
'@types/raf': 3.4.3
core-js: 3.49.0
raf: 3.4.1
regenerator-runtime: 0.13.11
rgbcolor: 1.0.1
stackblur-canvas: 2.7.0
svg-pathdata: 6.0.3
optional: true
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
@@ -2305,12 +2386,19 @@ snapshots:
convert-source-map@2.0.0: {}
core-js@3.49.0:
optional: true
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
css-line-break@2.1.0:
dependencies:
utrie: 1.0.2
cssesc@3.0.0: {}
csstype@3.2.3: {}
@@ -2328,6 +2416,11 @@ snapshots:
dlv@1.1.3: {}
dompurify@3.4.11:
optionalDependencies:
'@types/trusted-types': 2.0.7
optional: true
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -2410,10 +2503,18 @@ snapshots:
merge2: 1.4.1
micromatch: 4.0.8
fast-png@6.4.0:
dependencies:
'@types/pako': 2.0.4
iobuffer: 5.4.0
pako: 2.1.0
fastq@1.19.1:
dependencies:
reusify: 1.1.0
fflate@0.8.3: {}
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
@@ -2491,8 +2592,15 @@ snapshots:
dependencies:
function-bind: 1.1.2
html2canvas@1.4.1:
dependencies:
css-line-break: 2.1.0
text-segmentation: 1.0.3
immutable@5.1.4: {}
iobuffer@5.4.0: {}
is-binary-path@2.1.0:
dependencies:
binary-extensions: 2.3.0
@@ -2529,6 +2637,17 @@ snapshots:
json5@2.2.3: {}
jspdf@4.2.1:
dependencies:
'@babel/runtime': 7.29.7
fast-png: 6.4.0
fflate: 0.8.3
optionalDependencies:
canvg: 3.0.11
core-js: 3.49.0
dompurify: 3.4.11
html2canvas: 1.4.1
lilconfig@3.1.3: {}
lines-and-columns@1.2.4: {}
@@ -2609,6 +2728,8 @@ snapshots:
package-json-from-dist@1.0.1: {}
pako@2.1.0: {}
path-key@3.1.1: {}
path-parse@1.0.7: {}
@@ -2620,6 +2741,9 @@ snapshots:
pathe@2.0.3: {}
performance-now@2.1.0:
optional: true
picocolors@1.1.1: {}
picomatch@2.3.1: {}
@@ -2685,6 +2809,11 @@ snapshots:
queue-microtask@1.2.3: {}
raf@3.4.1:
dependencies:
performance-now: 2.1.0
optional: true
read-cache@1.0.0:
dependencies:
pify: 2.3.0
@@ -2696,6 +2825,9 @@ snapshots:
readdirp@4.1.2:
optional: true
regenerator-runtime@0.13.11:
optional: true
resolve@1.22.11:
dependencies:
is-core-module: 2.16.1
@@ -2704,6 +2836,9 @@ snapshots:
reusify@1.1.0: {}
rgbcolor@1.0.1:
optional: true
rollup@4.53.2:
dependencies:
'@types/estree': 1.0.8
@@ -2858,6 +2993,9 @@ snapshots:
source-map@0.6.1: {}
stackblur-canvas@2.7.0:
optional: true
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
@@ -2898,6 +3036,9 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
svg-pathdata@6.0.3:
optional: true
sync-child-process@1.0.2:
dependencies:
sync-message-port: 1.1.3
@@ -2939,6 +3080,10 @@ snapshots:
commander: 2.20.3
source-map-support: 0.5.21
text-segmentation@1.0.3:
dependencies:
utrie: 1.0.2
thenify-all@1.6.0:
dependencies:
thenify: 3.3.1
@@ -3025,6 +3170,10 @@ snapshots:
util-deprecate@1.0.2: {}
utrie@1.0.2:
dependencies:
base64-arraybuffer: 1.0.2
vant@4.9.21(vue@3.5.24):
dependencies:
'@vant/popperjs': 1.3.0

View File

@@ -1,5 +1,17 @@
<template>
<div class="hy-report">
<button
v-if="showToolbar"
type="button"
class="export-fab no-print"
:disabled="exporting"
:aria-busy="exporting"
@click="handleExport"
>
<span class="export-fab__icon">{{ exporting ? '…' : '↓' }}</span>
<span class="export-fab__text">{{ exporting ? '生成中' : '下载 PDF' }}</span>
</button>
<div ref="reportRef" class="hy-container">
<ReportHeaderSection :report-time="reportTime" />
@@ -25,8 +37,8 @@
<script setup>
import { computed, ref } from 'vue';
import { parseRoot, extractReportUrl, REPORT_USAGE_NOTICE } from './reportHelper';
import { printReportAsPdf } from './reportExport';
import { parseRoot, REPORT_USAGE_NOTICE } from './reportHelper';
import { downloadReportAsPdf } from './reportExport';
import ReportHeaderSection from './components/ReportHeaderSection.vue';
import RiskRatingSection from './components/RiskRatingSection.vue';
import RiskOverviewSection from './components/RiskOverviewSection.vue';
@@ -44,10 +56,10 @@ const props = defineProps({
index: { type: Number, default: 0 },
notifyRiskStatus: { type: Function, default: () => {} },
reportDateTime: { type: String, default: '' },
showToolbar: { type: Boolean, default: false },
});
const root = computed(() => parseRoot(props.data));
const reportUrl = computed(() => extractReportUrl(props.data));
const reportRef = ref(null);
const exporting = ref(false);
@@ -58,12 +70,26 @@ const reportTime = computed(
async function handleExport() {
exporting.value = true;
try {
await printReportAsPdf(reportRef.value);
await downloadReportAsPdf(reportRef.value, {
filename: `${props.apiId}_海宇个人风险报告_${formatFileDate(new Date())}.pdf`,
});
} finally {
exporting.value = false;
}
}
function formatFileDate(date) {
const pad = (n) => String(n).padStart(2, '0');
return [
date.getFullYear(),
pad(date.getMonth() + 1),
pad(date.getDate()),
pad(date.getHours()),
pad(date.getMinutes()),
pad(date.getSeconds()),
].join('');
}
defineExpose({ reportRef, handleExport });
</script>
@@ -85,12 +111,70 @@ defineExpose({ reportRef, handleExport });
margin-top: 4px;
}
.export-fab {
position: fixed;
right: 24px;
bottom: 32px;
z-index: 1000;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 18px;
border: none;
border-radius: 999px;
background: #0a6e8e;
color: #fff;
font-size: 14px;
font-weight: 500;
cursor: pointer;
box-shadow: 0 4px 16px rgba(10, 110, 142, 0.35);
transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
&:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(10, 110, 142, 0.45);
}
&:disabled {
opacity: 0.72;
cursor: wait;
}
}
.export-fab__icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.18);
font-size: 16px;
line-height: 1;
}
.export-fab__text {
white-space: nowrap;
}
@media (max-width: 900px) {
.main-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.export-fab {
right: 16px;
bottom: 20px;
padding: 12px 14px;
}
.export-fab__text {
font-size: 13px;
}
}
@media print {
.no-print {
display: none !important;

View File

@@ -1,18 +1,109 @@
import html2canvas from 'html2canvas';
import { jsPDF } from 'jspdf';
const A4_WIDTH_MM = 210;
const A4_HEIGHT_MM = 297;
const PAGE_MARGIN_MM = 8;
/**
* 通过浏览器打印对话框导出 PDF目标打印机选「另存为 PDF」
* 将报告 DOM 渲染为 PDF 文件并触发浏览器下载
*
* @param {HTMLElement} reportElement
* @param {{
* filename?: string,
* beforeCapture?: () => void | Promise<void>,
* afterCapture?: () => void,
* }} [options]
*/
export async function printReportAsPdf(reportElement) {
export async function downloadReportAsPdf(reportElement, options = {}) {
if (!reportElement) return;
document.body.classList.add('dwbg9fb2-printing');
const {
filename = `报告_${formatFileDate(new Date())}.pdf`,
beforeCapture,
afterCapture,
} = options;
await new Promise((resolve) => requestAnimationFrame(resolve));
if (beforeCapture) {
await beforeCapture();
}
const scrollLeft = window.scrollX;
const scrollTop = window.scrollY;
window.scrollTo(0, 0);
await waitForPaint();
try {
window.print();
const canvas = await html2canvas(reportElement, {
scale: 2,
useCORS: true,
logging: false,
backgroundColor: '#ffffff',
scrollX: 0,
scrollY: -window.scrollY,
windowWidth: document.documentElement.clientWidth,
});
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: 'a4',
});
const contentWidth = A4_WIDTH_MM - PAGE_MARGIN_MM * 2;
const contentHeight = A4_HEIGHT_MM - PAGE_MARGIN_MM * 2;
const imgWidth = contentWidth;
const imgHeight = (canvas.height * imgWidth) / canvas.width;
const imgData = canvas.toDataURL('image/jpeg', 0.92);
let heightLeft = imgHeight;
let position = 0;
pdf.addImage(
imgData,
'JPEG',
PAGE_MARGIN_MM,
PAGE_MARGIN_MM + position,
imgWidth,
imgHeight,
);
heightLeft -= contentHeight;
while (heightLeft > 0) {
position = heightLeft - imgHeight;
pdf.addPage();
pdf.addImage(
imgData,
'JPEG',
PAGE_MARGIN_MM,
PAGE_MARGIN_MM + position,
imgWidth,
imgHeight,
);
heightLeft -= contentHeight;
}
pdf.save(filename);
} finally {
window.setTimeout(() => {
document.body.classList.remove('dwbg9fb2-printing');
}, 500);
window.scrollTo(scrollLeft, scrollTop);
if (afterCapture) afterCapture();
}
}
function formatFileDate(date) {
const pad = (n) => String(n).padStart(2, '0');
return [
date.getFullYear(),
pad(date.getMonth() + 1),
pad(date.getDate()),
pad(date.getHours()),
pad(date.getMinutes()),
pad(date.getSeconds()),
].join('');
}
function waitForPaint() {
return new Promise((resolve) => {
requestAnimationFrame(() => requestAnimationFrame(resolve));
});
}

View File

@@ -129,7 +129,7 @@
<span class="case-text">{{ caseListText(c) }}</span>
<span class="case-arrow">{{ expandedIndex === i ? '' : '>' }}</span>
</div>
<div v-if="expandedIndex === i" class="case-block">
<div v-if="isCaseExpanded(i)" class="case-block">
<div class="case-info">
<div><span>案件类型:</span><span>{{ c.sectionLabel }}</span></div>
<div><span>诉讼地位:</span><span>{{ c.n_ssdw }}</span></div>
@@ -361,11 +361,23 @@ const allCases = computed(() => {
});
const expandedIndex = ref(null);
const expandAllForPrint = ref(false);
function isCaseExpanded(index) {
return expandAllForPrint.value || expandedIndex.value === index;
}
function toggleCase(index) {
if (expandAllForPrint.value) return;
expandedIndex.value = expandedIndex.value === index ? null : index;
}
function setExpandAllForPrint(expand) {
expandAllForPrint.value = expand;
}
defineExpose({ setExpandAllForPrint });
const dishonestList = computed(() =>
extractJudicialList(props.data, [
'dishonest',
@@ -985,4 +997,16 @@ function partiesText(dsrxx) {
overflow-x: auto;
}
}
@media print {
.case-arrow {
display: none;
}
.case-list-group,
.case-block,
.module-card {
break-inside: avoid-page;
}
}
</style>

View File

@@ -1,5 +1,17 @@
<template>
<div class="gamma-report">
<button
v-if="showToolbar"
type="button"
class="export-fab no-print"
:disabled="exporting"
:aria-busy="exporting"
@click="handleExport"
>
<span class="export-fab__icon">{{ exporting ? '…' : '↓' }}</span>
<span class="export-fab__text">{{ exporting ? '生成中' : '下载 PDF' }}</span>
</button>
<div ref="reportRef" class="gamma-container">
<ReportHeaderSection :report-time="reportTime" />
@@ -26,15 +38,15 @@
<OverdueSurveySection :data="root.loanRiskTagV10" />
<CreditPanoramaSection :data="root.loanRiskTagV21" />
<LoanIntentSection :data="root.loanRiskTagV11" />
<JudicialCaseSection :data="root.personalLawsuit" />
<JudicialCaseSection ref="judicialCaseRef" :data="root.personalLawsuit" />
</div>
</div>
</template>
<script setup>
import { computed, ref } from 'vue';
import { parseRoot, extractReportUrl } from './reportHelper';
import { printReportAsPdf } from './reportExport';
import { parseRoot } from './reportHelper';
import { downloadReportAsPdf } from './reportExport';
import RiskAssessmentSection from './components/RiskAssessmentSection.vue';
import RiskSummarySection from './components/RiskSummarySection.vue';
import BasicInfoSection from './components/BasicInfoSection.vue';
@@ -59,13 +71,40 @@ const props = defineProps({
});
const root = computed(() => parseRoot(props.data));
const reportUrl = computed(() => extractReportUrl(props.data));
const reportRef = ref(null);
const judicialCaseRef = ref(null);
const exporting = ref(false);
const reportTime = computed(
() => props.reportDateTime || new Date().toLocaleString('zh-CN'),
);
async function handleExport() {
exporting.value = true;
try {
await downloadReportAsPdf(reportRef.value, {
filename: `${props.apiId}_海宇贷前风险档案_${formatFileDate(new Date())}.pdf`,
beforeCapture: () => judicialCaseRef.value?.setExpandAllForPrint(true),
afterCapture: () => judicialCaseRef.value?.setExpandAllForPrint(false),
});
} finally {
exporting.value = false;
}
}
function formatFileDate(date) {
const pad = (n) => String(n).padStart(2, '0');
return [
date.getFullYear(),
pad(date.getMonth() + 1),
pad(date.getDate()),
pad(date.getHours()),
pad(date.getMinutes()),
pad(date.getSeconds()),
].join('');
}
defineExpose({ reportRef, handleExport });
</script>
<style lang="scss">
@@ -73,58 +112,61 @@ const reportTime = computed(
</style>
<style lang="scss" scoped>
.report-toolbar {
max-width: 1200px;
margin: 0 auto 16px;
padding: 12px 20px;
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
display: flex;
justify-content: space-between;
.export-fab {
position: fixed;
right: 24px;
bottom: 32px;
z-index: 1000;
display: inline-flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.toolbar-title {
font-size: 15px;
font-weight: 600;
color: #8b4513;
}
.toolbar-actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.toolbar-btn {
padding: 8px 18px;
gap: 8px;
padding: 12px 18px;
border: none;
border-radius: 6px;
border-radius: 999px;
background: #8b4513;
color: #fff;
font-size: 14px;
font-weight: 500;
cursor: pointer;
box-shadow: 0 4px 16px rgba(139, 69, 19, 0.35);
transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
&:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(139, 69, 19, 0.45);
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
&--secondary {
background: #fff;
color: #8b4513;
border: 1px solid #d4af37;
opacity: 0.72;
cursor: wait;
}
}
@media (max-width: 768px) {
.report-toolbar {
flex-direction: column;
align-items: flex-start;
gap: 8px;
.export-fab__icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.18);
font-size: 16px;
line-height: 1;
}
.export-fab__text {
white-space: nowrap;
}
@media (max-width: 640px) {
.export-fab {
right: 16px;
bottom: 20px;
padding: 12px 14px;
}
.export-fab__text {
font-size: 13px;
}
}

View File

@@ -1,19 +1,109 @@
import html2canvas from 'html2canvas';
import { jsPDF } from 'jspdf';
const A4_WIDTH_MM = 210;
const A4_HEIGHT_MM = 297;
const PAGE_MARGIN_MM = 8;
/**
* 通过浏览器打印对话框导出 PDF目标打印机选「另存为 PDF」
* 零依赖,适合当前纯前端报告查看器;复杂图表场景可改用服务端渲染 PDF。
* 将报告 DOM 渲染为 PDF 文件并触发浏览器下载
*
* @param {HTMLElement} reportElement
* @param {{
* filename?: string,
* beforeCapture?: () => void | Promise<void>,
* afterCapture?: () => void,
* }} [options]
*/
export async function printReportAsPdf(reportElement) {
export async function downloadReportAsPdf(reportElement, options = {}) {
if (!reportElement) return;
document.body.classList.add('dwbg9fb3-printing');
const {
filename = `报告_${formatFileDate(new Date())}.pdf`,
beforeCapture,
afterCapture,
} = options;
await new Promise((resolve) => requestAnimationFrame(resolve));
if (beforeCapture) {
await beforeCapture();
}
const scrollLeft = window.scrollX;
const scrollTop = window.scrollY;
window.scrollTo(0, 0);
await waitForPaint();
try {
window.print();
const canvas = await html2canvas(reportElement, {
scale: 2,
useCORS: true,
logging: false,
backgroundColor: '#ffffff',
scrollX: 0,
scrollY: -window.scrollY,
windowWidth: document.documentElement.clientWidth,
});
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: 'a4',
});
const contentWidth = A4_WIDTH_MM - PAGE_MARGIN_MM * 2;
const contentHeight = A4_HEIGHT_MM - PAGE_MARGIN_MM * 2;
const imgWidth = contentWidth;
const imgHeight = (canvas.height * imgWidth) / canvas.width;
const imgData = canvas.toDataURL('image/jpeg', 0.92);
let heightLeft = imgHeight;
let position = 0;
pdf.addImage(
imgData,
'JPEG',
PAGE_MARGIN_MM,
PAGE_MARGIN_MM + position,
imgWidth,
imgHeight,
);
heightLeft -= contentHeight;
while (heightLeft > 0) {
position = heightLeft - imgHeight;
pdf.addPage();
pdf.addImage(
imgData,
'JPEG',
PAGE_MARGIN_MM,
PAGE_MARGIN_MM + position,
imgWidth,
imgHeight,
);
heightLeft -= contentHeight;
}
pdf.save(filename);
} finally {
window.setTimeout(() => {
document.body.classList.remove('dwbg9fb3-printing');
}, 500);
window.scrollTo(scrollLeft, scrollTop);
if (afterCapture) afterCapture();
}
}
function formatFileDate(date) {
const pad = (n) => String(n).padStart(2, '0');
return [
date.getFullYear(),
pad(date.getMonth() + 1),
pad(date.getDate()),
pad(date.getHours()),
pad(date.getMinutes()),
pad(date.getSeconds()),
].join('');
}
function waitForPaint() {
return new Promise((resolve) => {
requestAnimationFrame(() => requestAnimationFrame(resolve));
});
}

View File

@@ -12,6 +12,8 @@ export const RISK_LEVEL_DESC = [
export const RISK_SUMMARY_CATEGORIES = [
{ key: 'mobile4Verify', title: '基本信息', icon: '📛' },
{ key: 'personalLawsuit', title: '司法案件', icon: '📑' },
{ key: 'courtRiskTagV31', title: '限高被执行人', icon: '⚖️' },
{ key: 'courtRiskTagV41', title: '失信被执行人', icon: '⚖️' },
{ key: 'loanRiskTagV11', title: '借贷意向', icon: '📈' },
{ key: 'loanRiskTagV10', title: '逾期勘测V3', icon: '📑' },
{ key: 'loanRiskTagV12', title: '借贷行为验证', icon: '📊' },
@@ -35,7 +37,7 @@ export function buildRiskSummaryCards(risks = {}) {
return {
key,
title: meta?.title ?? key,
icon: meta?.icon ?? '⚠️',
icon: meta?.icon ?? '📋',
items: Array.isArray(risks[key]) ? risks[key] : [],
};
});

View File

@@ -4,6 +4,7 @@
:data="reportData"
:params="reportParams"
:report-date-time="reportDateTime"
:show-toolbar="true"
/>
<div v-else class="loading-container">
<div class="loading-spinner" />