feat: 完成显示docx, pptx, xlsx文件
This commit is contained in:
parent
4123bc7673
commit
ba9af026f7
|
|
@ -63,6 +63,7 @@
|
||||||
"codemirror": "^6.0.2",
|
"codemirror": "^6.0.2",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"docx": "^9.6.1",
|
"docx": "^9.6.1",
|
||||||
|
"docx-preview": "^0.3.7",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"embla-carousel-react": "^8.6.0",
|
"embla-carousel-react": "^8.6.0",
|
||||||
"gsap": "^3.13.0",
|
"gsap": "^3.13.0",
|
||||||
|
|
@ -79,6 +80,7 @@
|
||||||
"nextra-theme-docs": "^4.6.1",
|
"nextra-theme-docs": "^4.6.1",
|
||||||
"nuxt-og-image": "^5.1.13",
|
"nuxt-og-image": "^5.1.13",
|
||||||
"ogl": "^1.0.11",
|
"ogl": "^1.0.11",
|
||||||
|
"pptx-preview": "^1.0.7",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-resizable-panels": "^4.4.1",
|
"react-resizable-panels": "^4.4.1",
|
||||||
|
|
@ -94,6 +96,7 @@
|
||||||
"unist-util-visit": "^5.0.0",
|
"unist-util-visit": "^5.0.0",
|
||||||
"use-stick-to-bottom": "^1.1.1",
|
"use-stick-to-bottom": "^1.1.1",
|
||||||
"uuid": "^13.0.0",
|
"uuid": "^13.0.0",
|
||||||
|
"xlsx": "^0.18.5",
|
||||||
"zod": "^3.24.2"
|
"zod": "^3.24.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,9 @@ importers:
|
||||||
docx:
|
docx:
|
||||||
specifier: ^9.6.1
|
specifier: ^9.6.1
|
||||||
version: 9.6.1
|
version: 9.6.1
|
||||||
|
docx-preview:
|
||||||
|
specifier: ^0.3.7
|
||||||
|
version: 0.3.7
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^17.2.3
|
specifier: ^17.2.3
|
||||||
version: 17.2.4
|
version: 17.2.4
|
||||||
|
|
@ -185,6 +188,9 @@ importers:
|
||||||
ogl:
|
ogl:
|
||||||
specifier: ^1.0.11
|
specifier: ^1.0.11
|
||||||
version: 1.0.11
|
version: 1.0.11
|
||||||
|
pptx-preview:
|
||||||
|
specifier: ^1.0.7
|
||||||
|
version: 1.0.7
|
||||||
react:
|
react:
|
||||||
specifier: ^19.0.0
|
specifier: ^19.0.0
|
||||||
version: 19.2.4
|
version: 19.2.4
|
||||||
|
|
@ -230,6 +236,9 @@ importers:
|
||||||
uuid:
|
uuid:
|
||||||
specifier: ^13.0.0
|
specifier: ^13.0.0
|
||||||
version: 13.0.0
|
version: 13.0.0
|
||||||
|
xlsx:
|
||||||
|
specifier: ^0.18.5
|
||||||
|
version: 0.18.5
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.24.2
|
specifier: ^3.24.2
|
||||||
version: 3.25.76
|
version: 3.25.76
|
||||||
|
|
@ -2548,6 +2557,10 @@ packages:
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
adler-32@1.3.1:
|
||||||
|
resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
ai@6.0.78:
|
ai@6.0.78:
|
||||||
resolution: {integrity: sha512-eriIX/NLWfWNDeE/OJy8wmIp9fyaH7gnxTOCPT5bp0MNkvORstp1TwRUql9au8XjXzH7o2WApqbwgxJDDV0Rbw==}
|
resolution: {integrity: sha512-eriIX/NLWfWNDeE/OJy8wmIp9fyaH7gnxTOCPT5bp0MNkvORstp1TwRUql9au8XjXzH7o2WApqbwgxJDDV0Rbw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
@ -2803,6 +2816,10 @@ packages:
|
||||||
ccount@2.0.1:
|
ccount@2.0.1:
|
||||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||||
|
|
||||||
|
cfb@1.2.2:
|
||||||
|
resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
chalk@4.1.2:
|
chalk@4.1.2:
|
||||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -2875,6 +2892,10 @@ packages:
|
||||||
codemirror@6.0.2:
|
codemirror@6.0.2:
|
||||||
resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==}
|
resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==}
|
||||||
|
|
||||||
|
codepage@1.15.0:
|
||||||
|
resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
collapse-white-space@2.1.0:
|
collapse-white-space@2.1.0:
|
||||||
resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==}
|
resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==}
|
||||||
|
|
||||||
|
|
@ -2934,6 +2955,11 @@ packages:
|
||||||
cose-base@2.2.0:
|
cose-base@2.2.0:
|
||||||
resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==}
|
resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==}
|
||||||
|
|
||||||
|
crc-32@1.2.2:
|
||||||
|
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
crelt@1.0.6:
|
crelt@1.0.6:
|
||||||
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
|
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
|
||||||
|
|
||||||
|
|
@ -3206,6 +3232,9 @@ packages:
|
||||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
docx-preview@0.3.7:
|
||||||
|
resolution: {integrity: sha512-Lav69CTA/IYZPJTsKH7oYeoZjyg96N0wEJMNslGJnZJ+dMUZK85Lt5ASC79yUlD48ecWjuv+rkcmFt6EVPV0Xg==}
|
||||||
|
|
||||||
docx@9.6.1:
|
docx@9.6.1:
|
||||||
resolution: {integrity: sha512-ZJja9/KBUuFC109sCMzovoq2GR2wCG/AuxivjA+OHj/q0TEgJIm3S7yrlUxIy3B+bV8YDj/BiHfWyrRFmyWpDQ==}
|
resolution: {integrity: sha512-ZJja9/KBUuFC109sCMzovoq2GR2wCG/AuxivjA+OHj/q0TEgJIm3S7yrlUxIy3B+bV8YDj/BiHfWyrRFmyWpDQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -3221,6 +3250,9 @@ packages:
|
||||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
echarts@5.6.0:
|
||||||
|
resolution: {integrity: sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==}
|
||||||
|
|
||||||
embla-carousel-react@8.6.0:
|
embla-carousel-react@8.6.0:
|
||||||
resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==}
|
resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -3553,6 +3585,10 @@ packages:
|
||||||
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
|
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
|
||||||
engines: {node: '>=0.4.x'}
|
engines: {node: '>=0.4.x'}
|
||||||
|
|
||||||
|
frac@1.1.2:
|
||||||
|
resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
framer-motion@12.34.0:
|
framer-motion@12.34.0:
|
||||||
resolution: {integrity: sha512-+/H49owhzkzQyxtn7nZeF4kdH++I2FWrESQ184Zbcw5cEqNHYkE5yxWxcTLSj5lNx3NWdbIRy5FHqUvetD8FWg==}
|
resolution: {integrity: sha512-+/H49owhzkzQyxtn7nZeF4kdH++I2FWrESQ184Zbcw5cEqNHYkE5yxWxcTLSj5lNx3NWdbIRy5FHqUvetD8FWg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -4190,6 +4226,9 @@ packages:
|
||||||
lodash.merge@4.6.2:
|
lodash.merge@4.6.2:
|
||||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||||
|
|
||||||
|
lodash@4.18.1:
|
||||||
|
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
|
||||||
|
|
||||||
longest-streak@3.1.0:
|
longest-streak@3.1.0:
|
||||||
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
||||||
|
|
||||||
|
|
@ -4818,6 +4857,9 @@ packages:
|
||||||
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
|
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
pptx-preview@1.0.7:
|
||||||
|
resolution: {integrity: sha512-YByocJuyxAR4YB4Q3+VAxdLfEvA5LojG1gAJsx2Mw0QU5FJPps/2fkJOupJ6oBbA+KdWRpuAk6G6T34rKCHVxw==}
|
||||||
|
|
||||||
prelude-ls@1.2.1:
|
prelude-ls@1.2.1:
|
||||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
@ -5274,6 +5316,10 @@ packages:
|
||||||
resolution: {integrity: sha512-SBMgkuJYvP4F62daRfBNwYC2nXTEhNXAfsBZ/BB7Ly85/KnbnjmKM7/45ZrFbH6jIMiAliDUDPSZFUuXDvcg6A==}
|
resolution: {integrity: sha512-SBMgkuJYvP4F62daRfBNwYC2nXTEhNXAfsBZ/BB7Ly85/KnbnjmKM7/45ZrFbH6jIMiAliDUDPSZFUuXDvcg6A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
ssf@0.11.2:
|
||||||
|
resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
stable-hash@0.0.5:
|
stable-hash@0.0.5:
|
||||||
resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
|
resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
|
||||||
|
|
||||||
|
|
@ -5449,6 +5495,9 @@ packages:
|
||||||
tsconfig-paths@3.15.0:
|
tsconfig-paths@3.15.0:
|
||||||
resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
|
resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
|
||||||
|
|
||||||
|
tslib@2.3.0:
|
||||||
|
resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
|
||||||
|
|
||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
|
@ -5800,10 +5849,23 @@ packages:
|
||||||
wicked-good-xpath@1.3.0:
|
wicked-good-xpath@1.3.0:
|
||||||
resolution: {integrity: sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==}
|
resolution: {integrity: sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==}
|
||||||
|
|
||||||
|
wmf@1.0.2:
|
||||||
|
resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
word-wrap@1.2.5:
|
word-wrap@1.2.5:
|
||||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
word@0.3.0:
|
||||||
|
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
xlsx@0.18.5:
|
||||||
|
resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
xml-js@1.6.11:
|
xml-js@1.6.11:
|
||||||
resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
|
resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -5836,6 +5898,9 @@ packages:
|
||||||
zod@4.3.6:
|
zod@4.3.6:
|
||||||
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||||
|
|
||||||
|
zrender@5.6.1:
|
||||||
|
resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==}
|
||||||
|
|
||||||
zustand@4.5.7:
|
zustand@4.5.7:
|
||||||
resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==}
|
resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==}
|
||||||
engines: {node: '>=12.7.0'}
|
engines: {node: '>=12.7.0'}
|
||||||
|
|
@ -8234,6 +8299,8 @@ snapshots:
|
||||||
|
|
||||||
acorn@8.15.0: {}
|
acorn@8.15.0: {}
|
||||||
|
|
||||||
|
adler-32@1.3.1: {}
|
||||||
|
|
||||||
ai@6.0.78(zod@3.25.76):
|
ai@6.0.78(zod@3.25.76):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/gateway': 3.0.39(zod@3.25.76)
|
'@ai-sdk/gateway': 3.0.39(zod@3.25.76)
|
||||||
|
|
@ -8476,6 +8543,11 @@ snapshots:
|
||||||
|
|
||||||
ccount@2.0.1: {}
|
ccount@2.0.1: {}
|
||||||
|
|
||||||
|
cfb@1.2.2:
|
||||||
|
dependencies:
|
||||||
|
adler-32: 1.3.1
|
||||||
|
crc-32: 1.2.2
|
||||||
|
|
||||||
chalk@4.1.2:
|
chalk@4.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
|
|
@ -8564,6 +8636,8 @@ snapshots:
|
||||||
'@codemirror/state': 6.5.4
|
'@codemirror/state': 6.5.4
|
||||||
'@codemirror/view': 6.39.13
|
'@codemirror/view': 6.39.13
|
||||||
|
|
||||||
|
codepage@1.15.0: {}
|
||||||
|
|
||||||
collapse-white-space@2.1.0: {}
|
collapse-white-space@2.1.0: {}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
|
|
@ -8609,6 +8683,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
layout-base: 2.0.1
|
layout-base: 2.0.1
|
||||||
|
|
||||||
|
crc-32@1.2.2: {}
|
||||||
|
|
||||||
crelt@1.0.6: {}
|
crelt@1.0.6: {}
|
||||||
|
|
||||||
cross-spawn@7.0.6:
|
cross-spawn@7.0.6:
|
||||||
|
|
@ -8899,6 +8975,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
|
|
||||||
|
docx-preview@0.3.7:
|
||||||
|
dependencies:
|
||||||
|
jszip: 3.10.1
|
||||||
|
|
||||||
docx@9.6.1:
|
docx@9.6.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.5.0
|
'@types/node': 25.5.0
|
||||||
|
|
@ -8920,6 +9000,11 @@ snapshots:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
gopd: 1.2.0
|
gopd: 1.2.0
|
||||||
|
|
||||||
|
echarts@5.6.0:
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.3.0
|
||||||
|
zrender: 5.6.1
|
||||||
|
|
||||||
embla-carousel-react@8.6.0(react@19.2.4):
|
embla-carousel-react@8.6.0(react@19.2.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
embla-carousel: 8.6.0
|
embla-carousel: 8.6.0
|
||||||
|
|
@ -9449,6 +9534,8 @@ snapshots:
|
||||||
|
|
||||||
format@0.2.2: {}
|
format@0.2.2: {}
|
||||||
|
|
||||||
|
frac@1.1.2: {}
|
||||||
|
|
||||||
framer-motion@12.34.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
framer-motion@12.34.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
motion-dom: 12.34.0
|
motion-dom: 12.34.0
|
||||||
|
|
@ -10154,6 +10241,8 @@ snapshots:
|
||||||
|
|
||||||
lodash.merge@4.6.2: {}
|
lodash.merge@4.6.2: {}
|
||||||
|
|
||||||
|
lodash@4.18.1: {}
|
||||||
|
|
||||||
longest-streak@3.1.0: {}
|
longest-streak@3.1.0: {}
|
||||||
|
|
||||||
loose-envify@1.4.0:
|
loose-envify@1.4.0:
|
||||||
|
|
@ -11179,6 +11268,14 @@ snapshots:
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
pptx-preview@1.0.7:
|
||||||
|
dependencies:
|
||||||
|
echarts: 5.6.0
|
||||||
|
jszip: 3.10.1
|
||||||
|
lodash: 4.18.1
|
||||||
|
tslib: 2.8.1
|
||||||
|
uuid: 10.0.0
|
||||||
|
|
||||||
prelude-ls@1.2.1: {}
|
prelude-ls@1.2.1: {}
|
||||||
|
|
||||||
prettier-plugin-tailwindcss@0.6.14(prettier@3.8.1):
|
prettier-plugin-tailwindcss@0.6.14(prettier@3.8.1):
|
||||||
|
|
@ -11771,6 +11868,10 @@ snapshots:
|
||||||
commander: 13.1.0
|
commander: 13.1.0
|
||||||
wicked-good-xpath: 1.3.0
|
wicked-good-xpath: 1.3.0
|
||||||
|
|
||||||
|
ssf@0.11.2:
|
||||||
|
dependencies:
|
||||||
|
frac: 1.1.2
|
||||||
|
|
||||||
stable-hash@0.0.5: {}
|
stable-hash@0.0.5: {}
|
||||||
|
|
||||||
stackblur-canvas@2.7.0:
|
stackblur-canvas@2.7.0:
|
||||||
|
|
@ -11966,6 +12067,8 @@ snapshots:
|
||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
strip-bom: 3.0.0
|
strip-bom: 3.0.0
|
||||||
|
|
||||||
|
tslib@2.3.0: {}
|
||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
tw-animate-css@1.4.0: {}
|
tw-animate-css@1.4.0: {}
|
||||||
|
|
@ -12335,8 +12438,22 @@ snapshots:
|
||||||
|
|
||||||
wicked-good-xpath@1.3.0: {}
|
wicked-good-xpath@1.3.0: {}
|
||||||
|
|
||||||
|
wmf@1.0.2: {}
|
||||||
|
|
||||||
word-wrap@1.2.5: {}
|
word-wrap@1.2.5: {}
|
||||||
|
|
||||||
|
word@0.3.0: {}
|
||||||
|
|
||||||
|
xlsx@0.18.5:
|
||||||
|
dependencies:
|
||||||
|
adler-32: 1.3.1
|
||||||
|
cfb: 1.2.2
|
||||||
|
codepage: 1.15.0
|
||||||
|
crc-32: 1.2.2
|
||||||
|
ssf: 0.11.2
|
||||||
|
wmf: 1.0.2
|
||||||
|
word: 0.3.0
|
||||||
|
|
||||||
xml-js@1.6.11:
|
xml-js@1.6.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
sax: 1.6.0
|
sax: 1.6.0
|
||||||
|
|
@ -12357,6 +12474,10 @@ snapshots:
|
||||||
|
|
||||||
zod@4.3.6: {}
|
zod@4.3.6: {}
|
||||||
|
|
||||||
|
zrender@5.6.1:
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.3.0
|
||||||
|
|
||||||
zustand@4.5.7(@types/react@19.2.13)(react@19.2.4):
|
zustand@4.5.7(@types/react@19.2.13)(react@19.2.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
use-sync-external-store: 1.6.0(react@19.2.4)
|
use-sync-external-store: 1.6.0(react@19.2.4)
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ export const ChainOfThoughtHeader = memo(
|
||||||
export type ChainOfThoughtStepProps = ComponentProps<"div"> & {
|
export type ChainOfThoughtStepProps = ComponentProps<"div"> & {
|
||||||
icon?: LucideIcon | React.ReactElement;
|
icon?: LucideIcon | React.ReactElement;
|
||||||
label: ReactNode;
|
label: ReactNode;
|
||||||
|
action?: ReactNode;
|
||||||
description?: ReactNode;
|
description?: ReactNode;
|
||||||
status?: "complete" | "active" | "pending";
|
status?: "complete" | "active" | "pending";
|
||||||
};
|
};
|
||||||
|
|
@ -125,6 +126,7 @@ export const ChainOfThoughtStep = memo(
|
||||||
className,
|
className,
|
||||||
icon: Icon = DotIcon,
|
icon: Icon = DotIcon,
|
||||||
label,
|
label,
|
||||||
|
action,
|
||||||
description,
|
description,
|
||||||
status = "complete",
|
status = "complete",
|
||||||
children,
|
children,
|
||||||
|
|
@ -151,7 +153,10 @@ export const ChainOfThoughtStep = memo(
|
||||||
<div className="bg-border absolute top-7 bottom-0 left-1/2 -mx-px w-px" />
|
<div className="bg-border absolute top-7 bottom-0 left-1/2 -mx-px w-px" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 space-y-2 overflow-hidden">
|
<div className="flex-1 space-y-2 overflow-hidden">
|
||||||
<div>{label}</div>
|
<div className="flex items-start justify-between gap-2">
|
||||||
|
<div>{label}</div>
|
||||||
|
{action && <div className="shrink-0">{action}</div>}
|
||||||
|
</div>
|
||||||
{description && (
|
{description && (
|
||||||
<div className="text-muted-foreground text-xs">{description}</div>
|
<div className="text-muted-foreground text-xs">{description}</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,15 @@ import {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
|
type CSSProperties,
|
||||||
type ComponentProps,
|
type ComponentProps,
|
||||||
type HTMLAttributes,
|
type HTMLAttributes,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Streamdown } from "streamdown";
|
import { Streamdown } from "streamdown";
|
||||||
|
import * as XLSX from "xlsx";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Artifact,
|
Artifact,
|
||||||
|
|
@ -489,13 +492,22 @@ export function ArtifactFileDetail({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isCodeFile && (
|
{!isCodeFile && (
|
||||||
<PreviewIframe
|
isOfficePreviewKind(artifactPreviewKind) ? (
|
||||||
className="size-full border-0"
|
<ArtifactOfficePreview
|
||||||
containerClassName="h-full mb-[207px]"
|
className="h-full mb-[207px]"
|
||||||
srcDoc={artifactViewerSrcDoc}
|
kind={artifactPreviewKind}
|
||||||
sandbox="allow-same-origin allow-scripts allow-downloads"
|
artifactUrl={artifactUrl}
|
||||||
title={`Artifact preview: ${fileName}`}
|
fileName={fileName}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<PreviewIframe
|
||||||
|
className="size-full border-0"
|
||||||
|
containerClassName="h-full mb-[207px]"
|
||||||
|
srcDoc={artifactViewerSrcDoc}
|
||||||
|
sandbox="allow-same-origin allow-scripts allow-downloads"
|
||||||
|
title={`Artifact preview: ${fileName}`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</ArtifactContent>
|
</ArtifactContent>
|
||||||
</Artifact>
|
</Artifact>
|
||||||
|
|
@ -522,7 +534,7 @@ export function ArtifactFilePreview({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn("w-full bg-white mb-[207px] p-[20px]")}
|
className={cn("w-full bg-white mb-[207px] p-[20px]")}
|
||||||
style={{ "--zoom-scale": zoomScale } as React.CSSProperties}
|
style={{ "--zoom-scale": zoomScale } as CSSProperties}
|
||||||
>
|
>
|
||||||
<Streamdown
|
<Streamdown
|
||||||
className="w-full"
|
className="w-full"
|
||||||
|
|
@ -588,6 +600,270 @@ function PreviewIframe({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ArtifactOfficePreview({
|
||||||
|
className,
|
||||||
|
kind,
|
||||||
|
artifactUrl,
|
||||||
|
fileName,
|
||||||
|
}: {
|
||||||
|
className?: string;
|
||||||
|
kind: ArtifactPreviewKind;
|
||||||
|
artifactUrl: string;
|
||||||
|
fileName: string;
|
||||||
|
}) {
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [xlsxHtml, setXlsxHtml] = useState<string>("");
|
||||||
|
const [sheetNames, setSheetNames] = useState<string[]>([]);
|
||||||
|
const [activeSheet, setActiveSheet] = useState<string>("");
|
||||||
|
const docxContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const pptxContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const workbookRef = useRef<XLSX.WorkBook | null>(null);
|
||||||
|
|
||||||
|
const canRenderDocx = kind === "docx";
|
||||||
|
const canRenderXlsx = kind === "xlsx";
|
||||||
|
const canRenderPptx = kind === "pptx";
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let disposed = false;
|
||||||
|
|
||||||
|
async function renderDocx() {
|
||||||
|
if (!canRenderDocx || !artifactUrl || !docxContainerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsLoading(true);
|
||||||
|
setError(null);
|
||||||
|
try {
|
||||||
|
const response = await fetch(artifactUrl);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
const blob = await response.blob();
|
||||||
|
const { renderAsync } = await import("docx-preview");
|
||||||
|
if (disposed || !docxContainerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
docxContainerRef.current.innerHTML = "";
|
||||||
|
await renderAsync(blob, docxContainerRef.current, undefined, {
|
||||||
|
ignoreWidth: false,
|
||||||
|
ignoreHeight: false,
|
||||||
|
breakPages: true,
|
||||||
|
inWrapper: true,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to render docx preview:", err);
|
||||||
|
if (!disposed) {
|
||||||
|
setError("无法预览该 DOCX 文件。");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (!disposed) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderDocx();
|
||||||
|
return () => {
|
||||||
|
disposed = true;
|
||||||
|
};
|
||||||
|
}, [artifactUrl, canRenderDocx]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let disposed = false;
|
||||||
|
|
||||||
|
async function parseXlsx() {
|
||||||
|
if (!canRenderXlsx || !artifactUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsLoading(true);
|
||||||
|
setError(null);
|
||||||
|
workbookRef.current = null;
|
||||||
|
try {
|
||||||
|
const response = await fetch(artifactUrl);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
const bytes = await response.arrayBuffer();
|
||||||
|
const workbook = XLSX.read(bytes, { type: "array" });
|
||||||
|
workbookRef.current = workbook;
|
||||||
|
const names = workbook.SheetNames ?? [];
|
||||||
|
if (names.length === 0) {
|
||||||
|
throw new Error("Empty workbook");
|
||||||
|
}
|
||||||
|
if (disposed) return;
|
||||||
|
setSheetNames(names);
|
||||||
|
const first = names[0] ?? "";
|
||||||
|
setActiveSheet(first);
|
||||||
|
const sheet = workbook.Sheets[first];
|
||||||
|
const html = sheet
|
||||||
|
? XLSX.utils.sheet_to_html(sheet, { id: "artifact-xlsx-preview" })
|
||||||
|
: "";
|
||||||
|
setXlsxHtml(html);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to render xlsx preview:", err);
|
||||||
|
if (!disposed) {
|
||||||
|
setError("无法预览该 Excel 文件。");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (!disposed) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseXlsx();
|
||||||
|
return () => {
|
||||||
|
disposed = true;
|
||||||
|
};
|
||||||
|
}, [artifactUrl, canRenderXlsx]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!canRenderXlsx || !activeSheet || !workbookRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const sheet = workbookRef.current.Sheets[activeSheet];
|
||||||
|
if (!sheet) return;
|
||||||
|
setXlsxHtml(XLSX.utils.sheet_to_html(sheet, { id: "artifact-xlsx-preview" }));
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to switch xlsx sheet:", err);
|
||||||
|
setError("切换工作表失败。");
|
||||||
|
}
|
||||||
|
}, [activeSheet, canRenderXlsx]);
|
||||||
|
useEffect(() => {
|
||||||
|
let disposed = false;
|
||||||
|
|
||||||
|
type PptxPreviewModule = {
|
||||||
|
init: (
|
||||||
|
container: HTMLElement,
|
||||||
|
options: { width: number; height: number },
|
||||||
|
) => {
|
||||||
|
preview: (buffer: ArrayBuffer) => Promise<void> | void;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
async function renderPptx() {
|
||||||
|
if (!canRenderPptx || !artifactUrl || !pptxContainerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsLoading(true);
|
||||||
|
setError(null);
|
||||||
|
try {
|
||||||
|
const response = await fetch(artifactUrl);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
const bytes = await response.arrayBuffer();
|
||||||
|
const pptxModule = (await import("pptx-preview")) as unknown as PptxPreviewModule;
|
||||||
|
if (disposed || !pptxContainerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const container = pptxContainerRef.current;
|
||||||
|
container.innerHTML = "";
|
||||||
|
const previewer = pptxModule.init(container, { width: 960, height: 540 });
|
||||||
|
await Promise.resolve(previewer.preview(bytes));
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to render pptx preview:", err);
|
||||||
|
if (!disposed) {
|
||||||
|
setError("无法预览该 PPT 文件。");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (!disposed) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderPptx();
|
||||||
|
return () => {
|
||||||
|
disposed = true;
|
||||||
|
};
|
||||||
|
}, [artifactUrl, canRenderPptx]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn("relative h-full overflow-hidden bg-white", className)}>
|
||||||
|
{canRenderXlsx && sheetNames.length > 0 && (
|
||||||
|
<div className="border-border flex items-center gap-1 overflow-x-auto border-b p-2">
|
||||||
|
{sheetNames.map((sheetName) => (
|
||||||
|
<button
|
||||||
|
key={sheetName}
|
||||||
|
type="button"
|
||||||
|
className={cn(
|
||||||
|
"rounded px-2 py-1 text-xs whitespace-nowrap",
|
||||||
|
activeSheet === sheetName
|
||||||
|
? "bg-primary text-primary-foreground"
|
||||||
|
: "bg-muted text-muted-foreground hover:text-foreground",
|
||||||
|
)}
|
||||||
|
onClick={() => setActiveSheet(sheetName)}
|
||||||
|
>
|
||||||
|
{sheetName}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="h-full overflow-auto p-4">
|
||||||
|
{canRenderDocx && (
|
||||||
|
<div
|
||||||
|
ref={docxContainerRef}
|
||||||
|
className="docx-preview-wrap mx-auto max-w-5xl"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{canRenderXlsx && xlsxHtml && (
|
||||||
|
<div
|
||||||
|
className="artifact-xlsx-preview overflow-auto"
|
||||||
|
dangerouslySetInnerHTML={{ __html: xlsxHtml }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{canRenderPptx && (
|
||||||
|
<div
|
||||||
|
ref={pptxContainerRef}
|
||||||
|
className="pptx-preview-wrap mx-auto w-full overflow-auto"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<ArtifactPreviewFallback
|
||||||
|
fileName={fileName}
|
||||||
|
artifactUrl={artifactUrl}
|
||||||
|
message={error}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isLoading && (
|
||||||
|
<div className="absolute inset-0 z-10 flex items-center justify-center bg-white/85">
|
||||||
|
<LoaderIcon className="text-muted-foreground size-5 animate-spin" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ArtifactPreviewFallback({
|
||||||
|
message,
|
||||||
|
fileName,
|
||||||
|
artifactUrl,
|
||||||
|
}: {
|
||||||
|
message: string;
|
||||||
|
fileName: string;
|
||||||
|
artifactUrl: string;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="absolute inset-0 z-20 grid place-content-center bg-white p-6 text-center">
|
||||||
|
<p className="text-foreground mb-2 text-sm font-medium">{fileName}</p>
|
||||||
|
<p className="text-muted-foreground mb-3 text-xs">{message}</p>
|
||||||
|
<a
|
||||||
|
className="text-primary text-sm font-medium underline"
|
||||||
|
href={artifactUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
在新标签页打开
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function rewriteArtifactImagePaths(content: string, threadId?: string) {
|
function rewriteArtifactImagePaths(content: string, threadId?: string) {
|
||||||
if (!threadId || !/\/?mnt\/user-data\//.test(content)) {
|
if (!threadId || !/\/?mnt\/user-data\//.test(content)) {
|
||||||
return content;
|
return content;
|
||||||
|
|
@ -626,6 +902,9 @@ type ArtifactPreviewKind =
|
||||||
| "video"
|
| "video"
|
||||||
| "audio"
|
| "audio"
|
||||||
| "pdf"
|
| "pdf"
|
||||||
|
| "docx"
|
||||||
|
| "xlsx"
|
||||||
|
| "pptx"
|
||||||
| "other";
|
| "other";
|
||||||
|
|
||||||
function getArtifactPreviewKind(filepath: string): ArtifactPreviewKind {
|
function getArtifactPreviewKind(filepath: string): ArtifactPreviewKind {
|
||||||
|
|
@ -636,9 +915,22 @@ function getArtifactPreviewKind(filepath: string): ArtifactPreviewKind {
|
||||||
if (/\.(mp4|webm|ogg|mov|m4v)$/.test(lower)) return "video";
|
if (/\.(mp4|webm|ogg|mov|m4v)$/.test(lower)) return "video";
|
||||||
if (/\.(mp3|wav|ogg|m4a|aac|flac)$/.test(lower)) return "audio";
|
if (/\.(mp3|wav|ogg|m4a|aac|flac)$/.test(lower)) return "audio";
|
||||||
if (lower.endsWith(".pdf")) return "pdf";
|
if (lower.endsWith(".pdf")) return "pdf";
|
||||||
|
if (/\.(docx?)$/.test(lower)) return "docx";
|
||||||
|
if (/\.(xlsx?)$/.test(lower)) return "xlsx";
|
||||||
|
if (/\.(pptx?)$/.test(lower)) return "pptx";
|
||||||
return "other";
|
return "other";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const OFFICE_PREVIEW_KINDS = new Set<ArtifactPreviewKind>([
|
||||||
|
"docx",
|
||||||
|
"xlsx",
|
||||||
|
"pptx",
|
||||||
|
]);
|
||||||
|
|
||||||
|
function isOfficePreviewKind(kind: ArtifactPreviewKind) {
|
||||||
|
return OFFICE_PREVIEW_KINDS.has(kind);
|
||||||
|
}
|
||||||
|
|
||||||
function escapeHtml(value: string): string {
|
function escapeHtml(value: string): string {
|
||||||
return value
|
return value
|
||||||
.replaceAll("&", "&")
|
.replaceAll("&", "&")
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ import { Tooltip } from "../tooltip";
|
||||||
|
|
||||||
import { MarkdownContent } from "./markdown-content";
|
import { MarkdownContent } from "./markdown-content";
|
||||||
|
|
||||||
|
const TOOL_CONTENT_COLLAPSE_THRESHOLD = 320;
|
||||||
|
|
||||||
export function MessageGroup({
|
export function MessageGroup({
|
||||||
className,
|
className,
|
||||||
messages,
|
messages,
|
||||||
|
|
@ -212,6 +214,33 @@ function ToolCall({
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { setOpen, autoOpen, autoSelect, selectedArtifact, select } =
|
const { setOpen, autoOpen, autoSelect, selectedArtifact, select } =
|
||||||
useArtifacts();
|
useArtifacts();
|
||||||
|
const [isCommandExpanded, setIsCommandExpanded] = useState(false);
|
||||||
|
|
||||||
|
const ExpandableToolContent = ({
|
||||||
|
content,
|
||||||
|
language = "bash",
|
||||||
|
expanded = false,
|
||||||
|
}: {
|
||||||
|
content: string;
|
||||||
|
language?: string;
|
||||||
|
expanded?: boolean;
|
||||||
|
}) => {
|
||||||
|
const shouldCollapse = content.length > TOOL_CONTENT_COLLAPSE_THRESHOLD;
|
||||||
|
const shouldShowCodeBlock = !shouldCollapse || expanded;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-1">
|
||||||
|
{shouldShowCodeBlock && (
|
||||||
|
<CodeBlock
|
||||||
|
className="mx-0 cursor-pointer border-none px-0"
|
||||||
|
showLineNumbers={false}
|
||||||
|
language={language}
|
||||||
|
code={content}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if (name === "web_search") {
|
if (name === "web_search") {
|
||||||
let label: React.ReactNode = t.toolCalls.searchForRelatedInfo;
|
let label: React.ReactNode = t.toolCalls.searchForRelatedInfo;
|
||||||
|
|
@ -386,19 +415,31 @@ function ToolCall({
|
||||||
return t.toolCalls.executeCommand;
|
return t.toolCalls.executeCommand;
|
||||||
}
|
}
|
||||||
const command: string | undefined = (args as { command: string })?.command;
|
const command: string | undefined = (args as { command: string })?.command;
|
||||||
|
const shouldCollapse = !!command && command.length > TOOL_CONTENT_COLLAPSE_THRESHOLD;
|
||||||
return (
|
return (
|
||||||
<ChainOfThoughtStep
|
<ChainOfThoughtStep
|
||||||
key={id}
|
key={id}
|
||||||
label={description}
|
label={description}
|
||||||
icon={SquareTerminalIcon}
|
icon={SquareTerminalIcon}
|
||||||
|
action={shouldCollapse
|
||||||
|
? (
|
||||||
|
<Button
|
||||||
|
className="h-7 px-0 text-xs"
|
||||||
|
variant="ghost"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
setIsCommandExpanded((prev) => !prev);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isCommandExpanded
|
||||||
|
? t.toolCalls.collapseContent
|
||||||
|
: t.toolCalls.expandContent}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
: undefined}
|
||||||
>
|
>
|
||||||
{command && (
|
{command && (
|
||||||
<CodeBlock
|
<ExpandableToolContent content={command} expanded={isCommandExpanded} />
|
||||||
className="mx-0 cursor-pointer border-none px-0"
|
|
||||||
showLineNumbers={false}
|
|
||||||
language="bash"
|
|
||||||
code={command}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</ChainOfThoughtStep>
|
</ChainOfThoughtStep>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,8 @@ export const enUS: Translations = {
|
||||||
writeFile: "Write file",
|
writeFile: "Write file",
|
||||||
clickToViewContent: "Click to view file content",
|
clickToViewContent: "Click to view file content",
|
||||||
writeTodos: "Update to-do list",
|
writeTodos: "Update to-do list",
|
||||||
|
expandContent: "Expand",
|
||||||
|
collapseContent: "Collapse",
|
||||||
skillInstallTooltip: "Install skill and make it available to DeerFlow",
|
skillInstallTooltip: "Install skill and make it available to DeerFlow",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,8 @@ export interface Translations {
|
||||||
writeFile: string;
|
writeFile: string;
|
||||||
clickToViewContent: string;
|
clickToViewContent: string;
|
||||||
writeTodos: string;
|
writeTodos: string;
|
||||||
|
expandContent: string;
|
||||||
|
collapseContent: string;
|
||||||
skillInstallTooltip: string;
|
skillInstallTooltip: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,8 @@ export const zhCN: Translations = {
|
||||||
writeFile: "写入文件",
|
writeFile: "写入文件",
|
||||||
clickToViewContent: "点击查看文件内容",
|
clickToViewContent: "点击查看文件内容",
|
||||||
writeTodos: "更新 To-do 列表",
|
writeTodos: "更新 To-do 列表",
|
||||||
|
expandContent: "展开",
|
||||||
|
collapseContent: "收起",
|
||||||
skillInstallTooltip: "安装技能并使其可在 DeerFlow 中使用",
|
skillInstallTooltip: "安装技能并使其可在 DeerFlow 中使用",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -491,3 +491,11 @@ pre {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
contain: paint;
|
contain: paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pptx-preview-wrap {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pptx-preview-wrap .pptx-preview-wrapper {
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue