@ai-group/chat-sdk 3.0.1-alpha.4 → 3.0.1-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/XAdkProvider/XAdkProvider.stories.js +1 -1
- package/dist/cjs/components/XAdkProvider/XAdkProvider.stories.js.map +1 -1
- package/dist/cjs/components/XAdkSender/FileGallery.js +148 -85
- package/dist/cjs/components/XAdkSender/FileGallery.js.map +3 -3
- package/dist/cjs/components/XAdkSender/index.d.ts +2 -2
- package/dist/cjs/components/XAdkSender/index.js +126 -94
- package/dist/cjs/components/XAdkSender/index.js.map +2 -2
- package/dist/esm/components/XAdkProvider/XAdkProvider.stories.js +1 -1
- package/dist/esm/components/XAdkProvider/XAdkProvider.stories.js.map +1 -1
- package/dist/esm/components/XAdkSender/FileGallery.js +225 -114
- package/dist/esm/components/XAdkSender/FileGallery.js.map +1 -1
- package/dist/esm/components/XAdkSender/index.d.ts +2 -2
- package/dist/esm/components/XAdkSender/index.js +44 -44
- package/dist/esm/components/XAdkSender/index.js.map +1 -1
- package/dist/umd/chat-sdk.min.js +1 -1
- package/package.json +1 -1
|
@@ -183,7 +183,7 @@ var 带会话列表 = {
|
|
|
183
183
|
},
|
|
184
184
|
args: {
|
|
185
185
|
url: "https://m-poc-dev.zaxline.com",
|
|
186
|
-
token: "eyJhbGciOiJSUzI1NiJ9.
|
|
186
|
+
token: "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8iLCJhdWQiOiJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8iLCJuYmYiOjE3NzM2NDk5MjIsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8iXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3MzY1NzEyMiwiaWF0IjoxNzczNjQ5OTIyLCJqdGkiOiI1NzY3Mjk3MC05ZmZlLTQzYmYtOTBmMy03ZDlmNDY4OTZjMGEiLCJjbGllbnRfaWQiOiJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8ifQ.ojer50ubE3oyBxPDW9JsZpQkzuvlbHYtLgl4jpdnUB1GSnlhNTPw9tShDuoLVjrKeeSVYsqfNTk-JN4xmYUxHs4cdy0-Sn6j2oLfbFYXI1p_8oQqOllhPKJWQA-JiOWMjm6iHpYOnotx14oGfgO6EKD2I9kLvRkje0DuEVKsj22s_XEimpfMCLtxCgn-lzmIVr90MU_1jt01q7MnPOA35rKTPlVLUg2Mw3a7JsmBPSvR25uDiX0x_ueG3riSko1cY37TXuSPIuBsD6N6aptv1RZ25-pGt6DjP3QOKnLfLc9N7_jIIcfbRzYYOOxp0Y4ond6fF5wWZI8S1wckZbBHiA",
|
|
187
187
|
config: {
|
|
188
188
|
appNo: "MFX5TxlheIKbekZHKoeOVNlo"
|
|
189
189
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/components/XAdkProvider/XAdkProvider.stories.tsx"],
|
|
4
|
-
"sourcesContent": ["import type { Meta, StoryObj } from \"@storybook/react-vite\";\nimport { Button, Space } from \"antd\";\nimport XAdkProvider from \"./index\";\nimport { useChatState, useChatActions } from \"./context\";\n\nconst meta: Meta<typeof XAdkProvider> = {\n title: \"AI组件/XAdkProvider 对话容器\",\n component: XAdkProvider,\n parameters: {\n layout: \"fullscreen\",\n docs: {\n description: {\n component: `\n# XAdkProvider - 新一代 Compound Components 架构\n\n基于 Compound Components 模式的 AI 聊天 SDK,提供完全可组合的聊天界面。\n\n## 核心特性\n\n- 🧩 **完全可组合**: 自由组合子组件,构建任意布局\n- 🪝 **Hooks 访问**: 通过 Hooks 轻松访问状态和方法\n- ⚡ **性能优化**: Context 三层分离,避免不必要的 rerender\n- 🔙 **向后兼容**: 旧 API 完全保留,平滑升级\n- 📘 **TypeScript**: 完整的类型支持\n\n## 可用组件\n\n- \\`XAdkProvider.DefaultLayout\\` - 默认布局 (类似 ChatGPT/DeepSeek)\n- \\`XAdkProvider.Chatbot\\` - 完整的聊天界面 (Messages + Sender)\n- \\`XAdkProvider.Messages\\` - 消息列表\n- \\`XAdkProvider.Sender\\` - 输入框\n- \\`XAdkProvider.Sidebar\\` - 会话列表\n- \\`XAdkProvider.Header\\` - 可选头部\n\n## 可用 Hooks\n\n- \\`useChatState()\\` - 访问聊天状态\n- \\`useChatActions()\\` - 访问聊天方法\n- \\`useSession()\\` - 访问会话管理\n\n## 配置说明\n\n请在使用前配置:\n- \\`url\\`: AI 服务地址 (默认: window.location.origin)\n- \\`token\\`: 认证令牌 (必填)\n- \\`config.appNo\\`: 应用编号 (必填)\n `,\n },\n },\n },\n tags: [\"autodocs\"],\n argTypes: {\n url: {\n description: \"AI 服务地址\",\n control: \"text\",\n },\n token: {\n description: \"认证令牌\",\n control: \"text\",\n },\n },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// ============================================\n// 示例 1: 默认布局 (类似 ChatGPT)\n// ============================================\nexport const 默认布局: Story = {\n render: (args) => (\n <div style={{ height: \"100vh\" }}>\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <XAdkProvider.DefaultLayout\n showSessionList={false}\n allowUpload={true}\n clearBtnShow={true}\n />\n </XAdkProvider>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n默认布局,类似 ChatGPT 的界面风格。\n\n\\`\\`\\`tsx\n<XAdkProvider url=\"...\" token=\"...\" config={{ appNo: 'xxx' }}>\n <XAdkProvider.DefaultLayout\n showSessionList={false}\n allowUpload={true}\n clearBtnShow={true}\n />\n</XAdkProvider>\n\\`\\`\\`\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ3VFhIOE5SZUQ2TkloV0tWZkJRQ3hXdlMiLCJhdWQiOiJ3VFhIOE5SZUQ2TkloV0tWZkJRQ3hXdlMiLCJuYmYiOjE3NzI3ODU3OTMsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyJ3VFhIOE5SZUQ2TkloV0tWZkJRQ3hXdlMiXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3Mjc5Mjk5MywiaWF0IjoxNzcyNzg1NzkzLCJqdGkiOiI4MmFjMGZmZS1lZDBlLTRiMjMtYWE3NS04NmUzZjA1OTQ2NmEiLCJjbGllbnRfaWQiOiJ3VFhIOE5SZUQ2TkloV0tWZkJRQ3hXdlMifQ.bBipIkOwu4BQqtH_ijT1V12yw5SnDpu7HAZhWrzjRSF7NUlqXr3m25f1VU_jiE9wyHO0Pj0VMMox1xVrE90JT9zgFL2sa4IDLpoHl6B2sr-3pY8WsvTLnk9PBSyTfOjmuSRwNDZyQYx0p4xJKd0yhf5Acfh5vuvH8pW7ksGpEXKvCLqc9tpeLytE1qZm_eSWt_rjTxDzvwMv33RAWO_fEigezoXfOe8ALtWpIDXEoza6cI--2buVM6-ZAFJHwe0CA_rx5E5H7QpmonUlZZhu9JVEL7HCc76MWLnuRP9TlNuicsR3JrYvkZ8nkG4oiBSWaHAgOVizGXaf2Elr7edTNA\",\n config: {\n appNo: \"wTXH8NReD6NIhWKVfBQCxWvS\",\n },\n },\n};\n\n// ============================================\n// 示例 2: 带会话列表 (类似 DeepSeek)\n// ============================================\nexport const 带会话列表: Story = {\n render: (args) => (\n <div style={{ height: \"100vh\" }}>\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <XAdkProvider.DefaultLayout\n header={<></>}\n showSessionList={true}\n allowUpload={true}\n clearBtnShow={false}\n showFnCallDetail={true}\n />\n </XAdkProvider>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n带会话列表的布局,类似 DeepSeek/元宝 的界面风格。\n\n左侧显示历史会话列表,右侧显示聊天区域。\n\n特点:\n- ✅ 左右布局: 左侧 280px 宽的会话列表,右侧聊天区域\n- ✅ 会话管理: 支持新建、切换、重命名、删除会话\n- ✅ 自动加载: 会话列表自动加载历史记录\n- ✅ 响应式: 窄屏自动切换到侧边栏模式\n\n\\`\\`\\`tsx\n<XAdkProvider\n url=\"...\"\n token=\"...\"\n config={{\n appNo: 'xxx',\n session: {\n showSessionList: true,\n }\n }}\n>\n <XAdkProvider.DefaultLayout\n showSessionList={true}\n allowUpload={true}\n />\n</XAdkProvider>\n\\`\\`\\`\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8iLCJhdWQiOiJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8iLCJuYmYiOjE3NzMyODI3NzMsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8iXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3MzI4OTk3MywiaWF0IjoxNzczMjgyNzczLCJqdGkiOiIwYmM4NmIzNS0xYzcxLTQ2NTAtYmU1Zi01Y2E2NDI0NDgxNTEiLCJjbGllbnRfaWQiOiJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8ifQ.WRUgp7RTNcGH-vh8eoOwvgwbWwdFCrxCcDOZiJ6t0vdhAothDkl2N8r1NgqpvC3jwMTjCMYbPY4ARlCBmvHq5dv65VYjA1nyEytzicVTMi2KHLigRlHq90CVYP8-c33Bv8ZTYsvzGwHhQjmVYHW9NCAUiVvCP-yMDNPeli6ts4sDUVzdZE5t8kpKG3DAhnWnaWl28UtdyduVy5j3K0BgTes-bzV-Ka2otwCljM4fvc2dVAtYNb20PTiX-dz-7SLAmwUNMb81g-CejWYUiKWS5MTRsnRfOOmPW_a2TSoRbHlvdAGGBVCdzK5b6CLmR7178RdVMU07nk7vD_szctMAcQ\",\n config: {\n appNo: \"MFX5TxlheIKbekZHKoeOVNlo\",\n },\n },\n};\n\n// ============================================\n// 示例 3: 自定义布局\n// ============================================\nexport const 自定义布局: Story = {\n render: (args) => (\n <div style={{ height: \"100vh\" }}>\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <div style={{ display: \"flex\", height: \"100%\" }}>\n {/* 左侧会话列表 */}\n {/* <div\n style={{\n width: 300,\n borderRight: \"1px solid #f0f0f0\",\n background: \"#fafafa\",\n }}\n >\n <XAdkProvider.Sidebar />\n </div> */}\n\n {/* 右侧聊天区 */}\n <div style={{ flex: 1, display: \"flex\", flexDirection: \"column\" }}>\n {/* 自定义头部 */}\n <div\n style={{\n padding: \"16px 24px\",\n background: \"linear-gradient(135deg, #667eea 0%, #764ba2 100%)\",\n color: \"white\",\n borderBottom: \"1px solid rgba(255,255,255,0.1)\",\n }}\n >\n <h2 style={{ margin: 0, fontSize: \"18px\" }}>🤖 AI 智能助手</h2>\n </div>\n\n {/* 消息区 */}\n <div style={{ flex: 1, overflow: \"hidden\", background: \"#f9fafb\" }}>\n <XAdkProvider.Messages />\n </div>\n\n {/* 输入区 */}\n <XAdkProvider.Sender allowUpload={true} clearBtnShow={true} />\n </div>\n </div>\n </XAdkProvider>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n完全自定义的布局,展示 Compound Components 的灵活性。\n\n可以任意组合 Sidebar、Messages、Sender 等组件。\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJhdWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJuYmYiOjE3NzMwNjI5MjUsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3MzA3MDEyNSwiaWF0IjoxNzczMDYyOTI1LCJqdGkiOiI0YmY3MjcxOS03NzNkLTRkZGYtOGYzNC01YjAwNjA5MWE3Y2IiLCJjbGllbnRfaWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08ifQ.AcWWnsWZVHvvpbT9IG64oo6mNNUFDKuaTMSCRMUvgiRyfn8f4Y64GBF_VR_XhgvNgNczXx5pXlU5AEXlvwA3RXv5Voy5Vl1dvyrLOtjZivnRJVeDVzn8Af57cXKE9QBZAS94bUMAtfmZmvqer4Lw6wuFNSg6G32BCpQH6ifR8zei3scf1Gcs0QXr00KcT3dFROmAzJscJC_KnXxGx_729BlQqupdJ05KEGHDIokqJNy5Ev_40IPmW-ZDJprXpEdReHfHnPuaUgGQRAJEW2yTf2OsyNenOwA9l0iKYK1ENDnBpsr08VUgMhJBKq-quzP5AE3eLIn-3KR0O-yT4lyBiQ\",\n config: {\n appNo: \"3jt2YbDjewVn2PHRKaDfJEgO\",\n },\n },\n};\n\n// ============================================\n// 示例 4: 使用 Hooks\n// ============================================\nconst CustomStatsBar = () => {\n const { messages, loading, appInfo } = useChatState();\n const { chat } = useChatActions();\n\n const quickQuestions = [\"介绍一下你自己\", \"你能帮我做什么?\", \"如何开始使用?\"];\n\n return (\n <div\n style={{\n padding: \"16px 20px\",\n background: \"white\",\n borderBottom: \"1px solid #f0f0f0\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"12px\",\n }}\n >\n <Space>\n <span style={{ fontSize: \"12px\", color: \"#999\" }}>\n 💬 消息数: <strong>{messages.length}</strong>\n </span>\n <span style={{ fontSize: \"12px\", color: \"#999\" }}>\n 🤖 {appInfo?.appName || \"加载中...\"}\n </span>\n </Space>\n <span\n style={{ fontSize: \"12px\", color: loading ? \"#1890ff\" : \"#52c41a\" }}\n >\n {loading ? \"● 生成中...\" : \"● 就绪\"}\n </span>\n </div>\n <div style={{ fontSize: \"12px\", color: \"#666\", marginBottom: \"8px\" }}>\n 💡 快捷问题:\n </div>\n <Space wrap>\n {quickQuestions.map((q, i) => (\n <Button\n key={i}\n size=\"small\"\n onClick={() => chat({ text: q })}\n disabled={loading}\n >\n {q}\n </Button>\n ))}\n </Space>\n </div>\n );\n};\n\nexport const 使用Hooks: Story = {\n render: (args) => (\n <div style={{ height: \"100vh\" }}>\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <div\n style={{ display: \"flex\", flexDirection: \"column\", height: \"100%\" }}\n >\n <CustomStatsBar />\n <div style={{ flex: 1 }}>\n <XAdkProvider.Chatbot />\n </div>\n </div>\n </XAdkProvider>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n使用 \\`useChatState\\` 和 \\`useChatActions\\` Hooks 访问状态和方法。\n\n可以在任意子组件中使用这些 Hooks 来访问聊天数据和操作。\n\n\\`\\`\\`tsx\nfunction CustomStatsBar() {\n const { messages, loading } = useChatState();\n const { chat } = useChatActions();\n\n return (\n <div>\n <p>消息数: {messages.length}</p>\n <button onClick={() => chat({ text: 'Hello' })}>\n 发送\n </button>\n </div>\n );\n}\n\\`\\`\\`\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJhdWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJuYmYiOjE3NzI3NjE1OTQsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3Mjc2ODc5NCwiaWF0IjoxNzcyNzYxNTk0LCJqdGkiOiI2M2IyMjRkNC1iODY3LTQzNjYtYTM5ZC1hZjNmOWQ0M2YyZmMiLCJjbGllbnRfaWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08ifQ.QNI4bD6MjIIvv-_SFxYEOiNv9304Ps5WF3b8_qmi3YIrqJQiaJ-iT1_fENpe9dD25RXcpgIv2Xnz9cI3Lz3gHfPKwoefijhrD7_Ye-9C5ztM2OI5pfoUurc1xPvjS7FGrTMZHNbpIFXyPoDAxtzGt-hLoQAEhBhLib8lLAbAQACmBOYy3KGwJg4sSFvbLkGWgqkH2aqC8MdH50ce35leybbEJu7ImithH3rj4E2oF6EqTb3vK181DFooEJ9E_LaC_hrw8zqGh9PSJah1rO3nxUDOPnz946RLKUi0xLOtz42l6qY2nUFsd9axYunGnk2ds5gg-PcBZN_X_aa-w7SLnw\",\n config: {\n appNo: \"3jt2YbDjewVn2PHRKaDfJEgO\",\n },\n },\n};\n\n// ============================================\n// 示例 5: 简化的 Chatbot\n// ============================================\nexport const 简化界面: Story = {\n render: (args) => (\n <div\n style={{\n height: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n background: \"#f5f5f5\",\n padding: \"40px\",\n }}\n >\n <div\n style={{\n width: \"100%\",\n maxWidth: \"900px\",\n height: \"700px\",\n background: \"white\",\n borderRadius: \"12px\",\n overflow: \"hidden\",\n boxShadow: \"0 8px 24px rgba(0,0,0,0.12)\",\n }}\n >\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <XAdkProvider.Chatbot />\n </XAdkProvider>\n </div>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n最简化的聊天界面,只包含消息列表和输入框。\n\n适合嵌入到其他页面或作为对话窗口使用。\n\n\\`\\`\\`tsx\n<XAdkProvider url=\"...\" token=\"...\" config={{ appNo: 'xxx' }}>\n <XAdkProvider.Chatbot />\n</XAdkProvider>\n\\`\\`\\`\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJhdWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJuYmYiOjE3NzI3NjE1OTQsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3Mjc2ODc5NCwiaWF0IjoxNzcyNzYxNTk0LCJqdGkiOiI2M2IyMjRkNC1iODY3LTQzNjYtYTM5ZC1hZjNmOWQ0M2YyZmMiLCJjbGllbnRfaWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08ifQ.QNI4bD6MjIIvv-_SFxYEOiNv9304Ps5WF3b8_qmi3YIrqJQiaJ-iT1_fENpe9dD25RXcpgIv2Xnz9cI3Lz3gHfPKwoefijhrD7_Ye-9C5ztM2OI5pfoUurc1xPvjS7FGrTMZHNbpIFXyPoDAxtzGt-hLoQAEhBhLib8lLAbAQACmBOYy3KGwJg4sSFvbLkGWgqkH2aqC8MdH50ce35leybbEJu7ImithH3rj4E2oF6EqTb3vK181DFooEJ9E_LaC_hrw8zqGh9PSJah1rO3nxUDOPnz946RLKUi0xLOtz42l6qY2nUFsd9axYunGnk2ds5gg-PcBZN_X_aa-w7SLnw\",\n config: {\n appNo: \"3jt2YbDjewVn2PHRKaDfJEgO\",\n },\n },\n};\n"],
|
|
4
|
+
"sourcesContent": ["import type { Meta, StoryObj } from \"@storybook/react-vite\";\nimport { Button, Space } from \"antd\";\nimport XAdkProvider from \"./index\";\nimport { useChatState, useChatActions } from \"./context\";\n\nconst meta: Meta<typeof XAdkProvider> = {\n title: \"AI组件/XAdkProvider 对话容器\",\n component: XAdkProvider,\n parameters: {\n layout: \"fullscreen\",\n docs: {\n description: {\n component: `\n# XAdkProvider - 新一代 Compound Components 架构\n\n基于 Compound Components 模式的 AI 聊天 SDK,提供完全可组合的聊天界面。\n\n## 核心特性\n\n- 🧩 **完全可组合**: 自由组合子组件,构建任意布局\n- 🪝 **Hooks 访问**: 通过 Hooks 轻松访问状态和方法\n- ⚡ **性能优化**: Context 三层分离,避免不必要的 rerender\n- 🔙 **向后兼容**: 旧 API 完全保留,平滑升级\n- 📘 **TypeScript**: 完整的类型支持\n\n## 可用组件\n\n- \\`XAdkProvider.DefaultLayout\\` - 默认布局 (类似 ChatGPT/DeepSeek)\n- \\`XAdkProvider.Chatbot\\` - 完整的聊天界面 (Messages + Sender)\n- \\`XAdkProvider.Messages\\` - 消息列表\n- \\`XAdkProvider.Sender\\` - 输入框\n- \\`XAdkProvider.Sidebar\\` - 会话列表\n- \\`XAdkProvider.Header\\` - 可选头部\n\n## 可用 Hooks\n\n- \\`useChatState()\\` - 访问聊天状态\n- \\`useChatActions()\\` - 访问聊天方法\n- \\`useSession()\\` - 访问会话管理\n\n## 配置说明\n\n请在使用前配置:\n- \\`url\\`: AI 服务地址 (默认: window.location.origin)\n- \\`token\\`: 认证令牌 (必填)\n- \\`config.appNo\\`: 应用编号 (必填)\n `,\n },\n },\n },\n tags: [\"autodocs\"],\n argTypes: {\n url: {\n description: \"AI 服务地址\",\n control: \"text\",\n },\n token: {\n description: \"认证令牌\",\n control: \"text\",\n },\n },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// ============================================\n// 示例 1: 默认布局 (类似 ChatGPT)\n// ============================================\nexport const 默认布局: Story = {\n render: (args) => (\n <div style={{ height: \"100vh\" }}>\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <XAdkProvider.DefaultLayout\n showSessionList={false}\n allowUpload={true}\n clearBtnShow={true}\n />\n </XAdkProvider>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n默认布局,类似 ChatGPT 的界面风格。\n\n\\`\\`\\`tsx\n<XAdkProvider url=\"...\" token=\"...\" config={{ appNo: 'xxx' }}>\n <XAdkProvider.DefaultLayout\n showSessionList={false}\n allowUpload={true}\n clearBtnShow={true}\n />\n</XAdkProvider>\n\\`\\`\\`\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ3VFhIOE5SZUQ2TkloV0tWZkJRQ3hXdlMiLCJhdWQiOiJ3VFhIOE5SZUQ2TkloV0tWZkJRQ3hXdlMiLCJuYmYiOjE3NzI3ODU3OTMsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyJ3VFhIOE5SZUQ2TkloV0tWZkJRQ3hXdlMiXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3Mjc5Mjk5MywiaWF0IjoxNzcyNzg1NzkzLCJqdGkiOiI4MmFjMGZmZS1lZDBlLTRiMjMtYWE3NS04NmUzZjA1OTQ2NmEiLCJjbGllbnRfaWQiOiJ3VFhIOE5SZUQ2TkloV0tWZkJRQ3hXdlMifQ.bBipIkOwu4BQqtH_ijT1V12yw5SnDpu7HAZhWrzjRSF7NUlqXr3m25f1VU_jiE9wyHO0Pj0VMMox1xVrE90JT9zgFL2sa4IDLpoHl6B2sr-3pY8WsvTLnk9PBSyTfOjmuSRwNDZyQYx0p4xJKd0yhf5Acfh5vuvH8pW7ksGpEXKvCLqc9tpeLytE1qZm_eSWt_rjTxDzvwMv33RAWO_fEigezoXfOe8ALtWpIDXEoza6cI--2buVM6-ZAFJHwe0CA_rx5E5H7QpmonUlZZhu9JVEL7HCc76MWLnuRP9TlNuicsR3JrYvkZ8nkG4oiBSWaHAgOVizGXaf2Elr7edTNA\",\n config: {\n appNo: \"wTXH8NReD6NIhWKVfBQCxWvS\",\n },\n },\n};\n\n// ============================================\n// 示例 2: 带会话列表 (类似 DeepSeek)\n// ============================================\nexport const 带会话列表: Story = {\n render: (args) => (\n <div style={{ height: \"100vh\" }}>\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <XAdkProvider.DefaultLayout\n header={<></>}\n showSessionList={true}\n allowUpload={true}\n clearBtnShow={false}\n showFnCallDetail={true}\n />\n </XAdkProvider>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n带会话列表的布局,类似 DeepSeek/元宝 的界面风格。\n\n左侧显示历史会话列表,右侧显示聊天区域。\n\n特点:\n- ✅ 左右布局: 左侧 280px 宽的会话列表,右侧聊天区域\n- ✅ 会话管理: 支持新建、切换、重命名、删除会话\n- ✅ 自动加载: 会话列表自动加载历史记录\n- ✅ 响应式: 窄屏自动切换到侧边栏模式\n\n\\`\\`\\`tsx\n<XAdkProvider\n url=\"...\"\n token=\"...\"\n config={{\n appNo: 'xxx',\n session: {\n showSessionList: true,\n }\n }}\n>\n <XAdkProvider.DefaultLayout\n showSessionList={true}\n allowUpload={true}\n />\n</XAdkProvider>\n\\`\\`\\`\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8iLCJhdWQiOiJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8iLCJuYmYiOjE3NzM2NDk5MjIsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8iXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3MzY1NzEyMiwiaWF0IjoxNzczNjQ5OTIyLCJqdGkiOiI1NzY3Mjk3MC05ZmZlLTQzYmYtOTBmMy03ZDlmNDY4OTZjMGEiLCJjbGllbnRfaWQiOiJNRlg1VHhsaGVJS2Jla1pIS29lT1ZObG8ifQ.ojer50ubE3oyBxPDW9JsZpQkzuvlbHYtLgl4jpdnUB1GSnlhNTPw9tShDuoLVjrKeeSVYsqfNTk-JN4xmYUxHs4cdy0-Sn6j2oLfbFYXI1p_8oQqOllhPKJWQA-JiOWMjm6iHpYOnotx14oGfgO6EKD2I9kLvRkje0DuEVKsj22s_XEimpfMCLtxCgn-lzmIVr90MU_1jt01q7MnPOA35rKTPlVLUg2Mw3a7JsmBPSvR25uDiX0x_ueG3riSko1cY37TXuSPIuBsD6N6aptv1RZ25-pGt6DjP3QOKnLfLc9N7_jIIcfbRzYYOOxp0Y4ond6fF5wWZI8S1wckZbBHiA\",\n config: {\n appNo: \"MFX5TxlheIKbekZHKoeOVNlo\",\n },\n },\n};\n\n// ============================================\n// 示例 3: 自定义布局\n// ============================================\nexport const 自定义布局: Story = {\n render: (args) => (\n <div style={{ height: \"100vh\" }}>\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <div style={{ display: \"flex\", height: \"100%\" }}>\n {/* 左侧会话列表 */}\n {/* <div\n style={{\n width: 300,\n borderRight: \"1px solid #f0f0f0\",\n background: \"#fafafa\",\n }}\n >\n <XAdkProvider.Sidebar />\n </div> */}\n\n {/* 右侧聊天区 */}\n <div style={{ flex: 1, display: \"flex\", flexDirection: \"column\" }}>\n {/* 自定义头部 */}\n <div\n style={{\n padding: \"16px 24px\",\n background: \"linear-gradient(135deg, #667eea 0%, #764ba2 100%)\",\n color: \"white\",\n borderBottom: \"1px solid rgba(255,255,255,0.1)\",\n }}\n >\n <h2 style={{ margin: 0, fontSize: \"18px\" }}>🤖 AI 智能助手</h2>\n </div>\n\n {/* 消息区 */}\n <div style={{ flex: 1, overflow: \"hidden\", background: \"#f9fafb\" }}>\n <XAdkProvider.Messages />\n </div>\n\n {/* 输入区 */}\n <XAdkProvider.Sender allowUpload={true} clearBtnShow={true} />\n </div>\n </div>\n </XAdkProvider>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n完全自定义的布局,展示 Compound Components 的灵活性。\n\n可以任意组合 Sidebar、Messages、Sender 等组件。\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJhdWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJuYmYiOjE3NzMwNjI5MjUsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3MzA3MDEyNSwiaWF0IjoxNzczMDYyOTI1LCJqdGkiOiI0YmY3MjcxOS03NzNkLTRkZGYtOGYzNC01YjAwNjA5MWE3Y2IiLCJjbGllbnRfaWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08ifQ.AcWWnsWZVHvvpbT9IG64oo6mNNUFDKuaTMSCRMUvgiRyfn8f4Y64GBF_VR_XhgvNgNczXx5pXlU5AEXlvwA3RXv5Voy5Vl1dvyrLOtjZivnRJVeDVzn8Af57cXKE9QBZAS94bUMAtfmZmvqer4Lw6wuFNSg6G32BCpQH6ifR8zei3scf1Gcs0QXr00KcT3dFROmAzJscJC_KnXxGx_729BlQqupdJ05KEGHDIokqJNy5Ev_40IPmW-ZDJprXpEdReHfHnPuaUgGQRAJEW2yTf2OsyNenOwA9l0iKYK1ENDnBpsr08VUgMhJBKq-quzP5AE3eLIn-3KR0O-yT4lyBiQ\",\n config: {\n appNo: \"3jt2YbDjewVn2PHRKaDfJEgO\",\n },\n },\n};\n\n// ============================================\n// 示例 4: 使用 Hooks\n// ============================================\nconst CustomStatsBar = () => {\n const { messages, loading, appInfo } = useChatState();\n const { chat } = useChatActions();\n\n const quickQuestions = [\"介绍一下你自己\", \"你能帮我做什么?\", \"如何开始使用?\"];\n\n return (\n <div\n style={{\n padding: \"16px 20px\",\n background: \"white\",\n borderBottom: \"1px solid #f0f0f0\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"12px\",\n }}\n >\n <Space>\n <span style={{ fontSize: \"12px\", color: \"#999\" }}>\n 💬 消息数: <strong>{messages.length}</strong>\n </span>\n <span style={{ fontSize: \"12px\", color: \"#999\" }}>\n 🤖 {appInfo?.appName || \"加载中...\"}\n </span>\n </Space>\n <span\n style={{ fontSize: \"12px\", color: loading ? \"#1890ff\" : \"#52c41a\" }}\n >\n {loading ? \"● 生成中...\" : \"● 就绪\"}\n </span>\n </div>\n <div style={{ fontSize: \"12px\", color: \"#666\", marginBottom: \"8px\" }}>\n 💡 快捷问题:\n </div>\n <Space wrap>\n {quickQuestions.map((q, i) => (\n <Button\n key={i}\n size=\"small\"\n onClick={() => chat({ text: q })}\n disabled={loading}\n >\n {q}\n </Button>\n ))}\n </Space>\n </div>\n );\n};\n\nexport const 使用Hooks: Story = {\n render: (args) => (\n <div style={{ height: \"100vh\" }}>\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <div\n style={{ display: \"flex\", flexDirection: \"column\", height: \"100%\" }}\n >\n <CustomStatsBar />\n <div style={{ flex: 1 }}>\n <XAdkProvider.Chatbot />\n </div>\n </div>\n </XAdkProvider>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n使用 \\`useChatState\\` 和 \\`useChatActions\\` Hooks 访问状态和方法。\n\n可以在任意子组件中使用这些 Hooks 来访问聊天数据和操作。\n\n\\`\\`\\`tsx\nfunction CustomStatsBar() {\n const { messages, loading } = useChatState();\n const { chat } = useChatActions();\n\n return (\n <div>\n <p>消息数: {messages.length}</p>\n <button onClick={() => chat({ text: 'Hello' })}>\n 发送\n </button>\n </div>\n );\n}\n\\`\\`\\`\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJhdWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJuYmYiOjE3NzI3NjE1OTQsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3Mjc2ODc5NCwiaWF0IjoxNzcyNzYxNTk0LCJqdGkiOiI2M2IyMjRkNC1iODY3LTQzNjYtYTM5ZC1hZjNmOWQ0M2YyZmMiLCJjbGllbnRfaWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08ifQ.QNI4bD6MjIIvv-_SFxYEOiNv9304Ps5WF3b8_qmi3YIrqJQiaJ-iT1_fENpe9dD25RXcpgIv2Xnz9cI3Lz3gHfPKwoefijhrD7_Ye-9C5ztM2OI5pfoUurc1xPvjS7FGrTMZHNbpIFXyPoDAxtzGt-hLoQAEhBhLib8lLAbAQACmBOYy3KGwJg4sSFvbLkGWgqkH2aqC8MdH50ce35leybbEJu7ImithH3rj4E2oF6EqTb3vK181DFooEJ9E_LaC_hrw8zqGh9PSJah1rO3nxUDOPnz946RLKUi0xLOtz42l6qY2nUFsd9axYunGnk2ds5gg-PcBZN_X_aa-w7SLnw\",\n config: {\n appNo: \"3jt2YbDjewVn2PHRKaDfJEgO\",\n },\n },\n};\n\n// ============================================\n// 示例 5: 简化的 Chatbot\n// ============================================\nexport const 简化界面: Story = {\n render: (args) => (\n <div\n style={{\n height: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n background: \"#f5f5f5\",\n padding: \"40px\",\n }}\n >\n <div\n style={{\n width: \"100%\",\n maxWidth: \"900px\",\n height: \"700px\",\n background: \"white\",\n borderRadius: \"12px\",\n overflow: \"hidden\",\n boxShadow: \"0 8px 24px rgba(0,0,0,0.12)\",\n }}\n >\n <XAdkProvider url={args.url} token={args.token} config={args.config}>\n <XAdkProvider.Chatbot />\n </XAdkProvider>\n </div>\n </div>\n ),\n parameters: {\n docs: {\n description: {\n story: `\n最简化的聊天界面,只包含消息列表和输入框。\n\n适合嵌入到其他页面或作为对话窗口使用。\n\n\\`\\`\\`tsx\n<XAdkProvider url=\"...\" token=\"...\" config={{ appNo: 'xxx' }}>\n <XAdkProvider.Chatbot />\n</XAdkProvider>\n\\`\\`\\`\n `,\n },\n },\n },\n args: {\n url: \"https://m-poc-dev.zaxline.com\",\n token:\n \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJhdWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iLCJuYmYiOjE3NzI3NjE1OTQsInVzZXJfaWQiOiJWNFNPSG1KbzNaZWE0Uk51ZzdYWDJBPT0iLCJzY29wZSI6WyIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08iXSwiaXNzIjoiaHR0cDovL2htLWF1dGgtc2VydmVyLnhsaW5lLWRldi50ZXN0LnhpbmtlLmJpeiIsImV4cCI6MTc3Mjc2ODc5NCwiaWF0IjoxNzcyNzYxNTk0LCJqdGkiOiI2M2IyMjRkNC1iODY3LTQzNjYtYTM5ZC1hZjNmOWQ0M2YyZmMiLCJjbGllbnRfaWQiOiIzanQyWWJEamV3Vm4yUEhSS2FEZkpFZ08ifQ.QNI4bD6MjIIvv-_SFxYEOiNv9304Ps5WF3b8_qmi3YIrqJQiaJ-iT1_fENpe9dD25RXcpgIv2Xnz9cI3Lz3gHfPKwoefijhrD7_Ye-9C5ztM2OI5pfoUurc1xPvjS7FGrTMZHNbpIFXyPoDAxtzGt-hLoQAEhBhLib8lLAbAQACmBOYy3KGwJg4sSFvbLkGWgqkH2aqC8MdH50ce35leybbEJu7ImithH3rj4E2oF6EqTb3vK181DFooEJ9E_LaC_hrw8zqGh9PSJah1rO3nxUDOPnz946RLKUi0xLOtz42l6qY2nUFsd9axYunGnk2ds5gg-PcBZN_X_aa-w7SLnw\",\n config: {\n appNo: \"3jt2YbDjewVn2PHRKaDfJEgO\",\n },\n },\n};\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["XAdkProvider"]
|
|
7
7
|
}
|
|
@@ -22,6 +22,7 @@ __export(FileGallery_exports, {
|
|
|
22
22
|
default: () => FileGallery_default
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(FileGallery_exports);
|
|
25
|
+
var import_react = require("react");
|
|
25
26
|
var import_antd = require("antd");
|
|
26
27
|
var import_icons = require("@ant-design/icons");
|
|
27
28
|
var import_css = require("@emotion/css");
|
|
@@ -35,6 +36,16 @@ var getFileExtension = (filename) => {
|
|
|
35
36
|
const ext = filename.split(".").pop();
|
|
36
37
|
return ext ? ext.toLowerCase() : "";
|
|
37
38
|
};
|
|
39
|
+
var isAudioFile = (file) => {
|
|
40
|
+
if (!file.type)
|
|
41
|
+
return false;
|
|
42
|
+
return file.type.startsWith("audio/");
|
|
43
|
+
};
|
|
44
|
+
var isVideoFile = (file) => {
|
|
45
|
+
if (!file.type)
|
|
46
|
+
return false;
|
|
47
|
+
return file.type.startsWith("video/");
|
|
48
|
+
};
|
|
38
49
|
var getFileIcon = (file) => {
|
|
39
50
|
const ext = getFileExtension(file.name);
|
|
40
51
|
if (ext === "pdf") {
|
|
@@ -49,6 +60,12 @@ var getFileIcon = (file) => {
|
|
|
49
60
|
if (["ppt", "pptx"].includes(ext)) {
|
|
50
61
|
return { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.FilePptOutlined, {}), color: "#ff6e31" };
|
|
51
62
|
}
|
|
63
|
+
if (["mp3", "wav", "m4a", "aac", "ogg", "flac"].includes(ext)) {
|
|
64
|
+
return { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.AudioOutlined, {}), color: "#722ed1" };
|
|
65
|
+
}
|
|
66
|
+
if (["mp4", "mov", "webm", "mkv", "avi"].includes(ext)) {
|
|
67
|
+
return { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.VideoCameraOutlined, {}), color: "#fa8c16" };
|
|
68
|
+
}
|
|
52
69
|
if (isImageFile(file)) {
|
|
53
70
|
return { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.FileImageOutlined, {}), color: "#8c8c8c" };
|
|
54
71
|
}
|
|
@@ -181,11 +198,11 @@ var styles = {
|
|
|
181
198
|
display: flex;
|
|
182
199
|
align-items: center;
|
|
183
200
|
gap: 10px;
|
|
184
|
-
padding:
|
|
201
|
+
padding: 6px 12px;
|
|
185
202
|
background: #fafafa;
|
|
186
203
|
border: 1px solid #f0f0f0;
|
|
187
204
|
border-radius: 8px;
|
|
188
|
-
min-width:
|
|
205
|
+
min-width: 260px;
|
|
189
206
|
max-width: 280px;
|
|
190
207
|
min-height: 64px;
|
|
191
208
|
transition: all 0.2s ease;
|
|
@@ -224,8 +241,8 @@ var styles = {
|
|
|
224
241
|
fileIcon: import_css.css`
|
|
225
242
|
font-size: 24px;
|
|
226
243
|
flex-shrink: 0;
|
|
227
|
-
width:
|
|
228
|
-
height:
|
|
244
|
+
width: 36px;
|
|
245
|
+
height: 36px;
|
|
229
246
|
display: flex;
|
|
230
247
|
align-items: center;
|
|
231
248
|
justify-content: center;
|
|
@@ -289,93 +306,139 @@ var styles = {
|
|
|
289
306
|
}
|
|
290
307
|
`
|
|
291
308
|
};
|
|
292
|
-
var
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
src: url
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
),
|
|
313
|
-
file.status === "uploading" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.imageOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
314
|
-
import_antd.Progress,
|
|
315
|
-
{
|
|
316
|
-
type: "circle",
|
|
317
|
-
percent: file.progress,
|
|
318
|
-
size: 30,
|
|
319
|
-
strokeColor: "#1677ff"
|
|
320
|
-
}
|
|
321
|
-
) })
|
|
322
|
-
] }),
|
|
323
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileInfo, children: [
|
|
324
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.Tooltip, { title: file.name, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileName, children: file.name.length > 15 ? `${file.name.substring(0, 15)}...` : file.name }) }),
|
|
325
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileSize, children: formatFileSize(file.size) })
|
|
326
|
-
] }),
|
|
309
|
+
var FileItem = ({ file, onRemove }) => {
|
|
310
|
+
var _a, _b;
|
|
311
|
+
const [objectUrl, setObjectUrl] = (0, import_react.useState)("");
|
|
312
|
+
(0, import_react.useEffect)(() => {
|
|
313
|
+
if (!file.file)
|
|
314
|
+
return;
|
|
315
|
+
const url2 = URL.createObjectURL(file.file);
|
|
316
|
+
setObjectUrl(url2);
|
|
317
|
+
return () => URL.revokeObjectURL(url2);
|
|
318
|
+
}, [file.file]);
|
|
319
|
+
const isImage = isImageFile(file);
|
|
320
|
+
const isAudio = isAudioFile(file);
|
|
321
|
+
const isVideo = isVideoFile(file);
|
|
322
|
+
const url = ((_a = file.response) == null ? void 0 : _a.fileUrl) || ((_b = file.response) == null ? void 0 : _b.tempUrl) || file.tempUrl || objectUrl;
|
|
323
|
+
if (isImage) {
|
|
324
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileCard, children: [
|
|
325
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.imageThumbnail, children: [
|
|
327
326
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
328
|
-
|
|
327
|
+
import_antd.Image,
|
|
329
328
|
{
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
)
|
|
337
|
-
] }, file.id);
|
|
338
|
-
} else {
|
|
339
|
-
const { icon, color } = getFileIcon(file);
|
|
340
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileCard, children: [
|
|
341
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileIcon, style: { color }, children: icon }),
|
|
342
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileInfo, children: [
|
|
343
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.Tooltip, { title: file.name, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileName, children: file.name.length > 15 ? `${file.name.substring(0, 15)}...` : file.name }) }),
|
|
344
|
-
file.status === "uploading" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
345
|
-
import_antd.Progress,
|
|
346
|
-
{
|
|
347
|
-
percent: file.progress,
|
|
348
|
-
size: "small",
|
|
349
|
-
showInfo: false,
|
|
350
|
-
strokeColor: "#1677ff",
|
|
351
|
-
className: styles.progress
|
|
329
|
+
src: url,
|
|
330
|
+
alt: file.name,
|
|
331
|
+
fallback: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
|
|
332
|
+
preview: {
|
|
333
|
+
src: url
|
|
352
334
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
367
|
-
|
|
335
|
+
}
|
|
336
|
+
),
|
|
337
|
+
file.status === "uploading" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.imageOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
338
|
+
import_antd.Progress,
|
|
339
|
+
{
|
|
340
|
+
type: "circle",
|
|
341
|
+
percent: file.progress,
|
|
342
|
+
size: 30,
|
|
343
|
+
strokeColor: "#1677ff"
|
|
344
|
+
}
|
|
345
|
+
) })
|
|
346
|
+
] }),
|
|
347
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileInfo, children: [
|
|
348
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.Tooltip, { title: file.name, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileName, children: file.name.length > 15 ? `${file.name.substring(0, 15)}...` : file.name }) }),
|
|
349
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileSize, children: formatFileSize(file.size) })
|
|
350
|
+
] }),
|
|
351
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
352
|
+
"button",
|
|
353
|
+
{
|
|
354
|
+
className: styles.fileRemoveBtn,
|
|
355
|
+
onClick: () => onRemove(file.id),
|
|
356
|
+
disabled: file.status === "uploading",
|
|
357
|
+
"aria-label": "删除文件",
|
|
358
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.CloseOutlined, {})
|
|
359
|
+
}
|
|
360
|
+
)
|
|
361
|
+
] }, file.id);
|
|
362
|
+
} else if (isAudio) {
|
|
363
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileCard, children: [
|
|
364
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileIcon, style: { color: "#722ed1" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.AudioOutlined, {}) }),
|
|
365
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileInfo, children: [
|
|
366
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.Tooltip, { title: file.name, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileName, children: file.name }) }),
|
|
367
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("audio", { src: url, controls: true, style: { width: "100%", height: 28 } })
|
|
368
|
+
] }),
|
|
369
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
370
|
+
"button",
|
|
371
|
+
{
|
|
372
|
+
className: styles.fileRemoveBtn,
|
|
373
|
+
onClick: () => onRemove(file.id),
|
|
374
|
+
disabled: file.status === "uploading",
|
|
375
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.CloseOutlined, {})
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
] }, file.id);
|
|
379
|
+
} else if (isVideo) {
|
|
380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileCard, children: [
|
|
381
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileIcon, style: { color: "#fa8c16" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.VideoCameraOutlined, {}) }),
|
|
382
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileInfo, children: [
|
|
383
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.Tooltip, { title: file.name, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileName, children: file.name }) }),
|
|
384
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("video", { src: url, controls: true, style: { width: "100%", height: 40 } })
|
|
385
|
+
] }),
|
|
386
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
387
|
+
"button",
|
|
388
|
+
{
|
|
389
|
+
className: styles.fileRemoveBtn,
|
|
390
|
+
onClick: () => onRemove(file.id),
|
|
391
|
+
disabled: file.status === "uploading",
|
|
392
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.CloseOutlined, {})
|
|
393
|
+
}
|
|
394
|
+
)
|
|
395
|
+
] }, file.id);
|
|
396
|
+
} else {
|
|
397
|
+
const { icon, color } = getFileIcon(file);
|
|
398
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileCard, children: [
|
|
399
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileIcon, style: { color }, children: icon }),
|
|
400
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.fileInfo, children: [
|
|
401
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.Tooltip, { title: file.name, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileName, children: file.name.length > 15 ? `${file.name.substring(0, 15)}...` : file.name }) }),
|
|
402
|
+
file.status === "uploading" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
403
|
+
import_antd.Progress,
|
|
368
404
|
{
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
405
|
+
percent: file.progress,
|
|
406
|
+
size: "small",
|
|
407
|
+
showInfo: false,
|
|
408
|
+
strokeColor: "#1677ff",
|
|
409
|
+
className: styles.progress
|
|
410
|
+
}
|
|
411
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileSize, children: formatFileSize(file.size) }),
|
|
412
|
+
file.status === "error" && file.errorMessage && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
413
|
+
"div",
|
|
414
|
+
{
|
|
415
|
+
style: {
|
|
416
|
+
fontSize: "11px",
|
|
417
|
+
color: "#ff4d4f",
|
|
418
|
+
marginTop: "2px"
|
|
419
|
+
},
|
|
420
|
+
children: file.errorMessage
|
|
374
421
|
}
|
|
375
422
|
)
|
|
376
|
-
] },
|
|
377
|
-
|
|
378
|
-
|
|
423
|
+
] }),
|
|
424
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
425
|
+
"button",
|
|
426
|
+
{
|
|
427
|
+
className: styles.fileRemoveBtn,
|
|
428
|
+
onClick: () => onRemove(file.id),
|
|
429
|
+
disabled: file.status === "uploading",
|
|
430
|
+
"aria-label": "删除文件",
|
|
431
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.CloseOutlined, {})
|
|
432
|
+
}
|
|
433
|
+
)
|
|
434
|
+
] }, file.id);
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
var FileGallery = ({ files, onRemove }) => {
|
|
438
|
+
if (files.length === 0)
|
|
439
|
+
return null;
|
|
440
|
+
const [objectUrl, setObjectUrl] = (0, import_react.useState)("");
|
|
441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.container, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.fileList, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.Image.PreviewGroup, { children: files.map((file) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileItem, { file, onRemove }, file.id)) }) }) });
|
|
379
442
|
};
|
|
380
443
|
var FileGallery_default = FileGallery;
|
|
381
444
|
//# sourceMappingURL=FileGallery.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/components/XAdkSender/FileGallery.tsx"],
|
|
4
|
-
"sourcesContent": ["import React from \"react\";\nimport { Image, Tooltip, Progress } from \"antd\";\nimport {\n FileOutlined,\n FilePdfOutlined,\n FileWordOutlined,\n FileExcelOutlined,\n FilePptOutlined,\n FileImageOutlined,\n CloseOutlined,\n} from \"@ant-design/icons\";\nimport { LocalFile } from \"../../types/XAdkSender\";\nimport { css } from \"@emotion/css\";\n\ninterface FileGalleryProps {\n files: LocalFile[];\n onRemove: (id: string) => void;\n}\n\n// 判断是否是图片文件\nconst isImageFile = (file: LocalFile): boolean => {\n if (!file.type) return false;\n return file.type.startsWith(\"image/\");\n};\n\n// 获取文件扩展名\nconst getFileExtension = (filename: string): string => {\n const ext = filename.split(\".\").pop();\n return ext ? ext.toLowerCase() : \"\";\n};\n\n// 获取文件图标和颜色\nconst getFileIcon = (\n file: LocalFile,\n): { icon: React.ReactNode; color: string } => {\n const ext = getFileExtension(file.name);\n\n // PDF\n if (ext === \"pdf\") {\n return { icon: <FilePdfOutlined />, color: \"#ff4d4f\" };\n }\n\n // Word\n if ([\"doc\", \"docx\"].includes(ext)) {\n return { icon: <FileWordOutlined />, color: \"#1677ff\" };\n }\n\n // Excel\n if ([\"xls\", \"xlsx\", \"csv\"].includes(ext)) {\n return { icon: <FileExcelOutlined />, color: \"#22b35e\" };\n }\n\n // PPT\n if ([\"ppt\", \"pptx\"].includes(ext)) {\n return { icon: <FilePptOutlined />, color: \"#ff6e31\" };\n }\n\n // 图片\n if (isImageFile(file)) {\n return { icon: <FileImageOutlined />, color: \"#8c8c8c\" };\n }\n\n // 默认\n return { icon: <FileOutlined />, color: \"#8c8c8c\" };\n};\n\n// 格式化文件大小\nconst formatFileSize = (bytes: number): string => {\n if (bytes < 1024) return bytes + \" B\";\n if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + \" KB\";\n return (bytes / (1024 * 1024)).toFixed(1) + \" MB\";\n};\n\nconst styles = {\n container: css`\n padding: 12px 0;\n display: flex;\n flex-direction: column;\n gap: 12px;\n `,\n\n // 图片九宫格容器\n imageGrid: css`\n display: grid;\n gap: 8px;\n width: fit-content;\n min-width: 80px;\n max-width: 100%;\n /* 默认3列布局 */\n grid-template-columns: repeat(3, 1fr);\n\n /* 单张图 */\n &[data-count=\"1\"] {\n grid-template-columns: 1fr;\n min-width: 100px;\n max-width: 200px;\n }\n\n /* 2张、4张 -> 2列 */\n &[data-count=\"2\"],\n &[data-count=\"4\"] {\n grid-template-columns: repeat(2, 1fr);\n min-width: 180px;\n max-width: 240px;\n }\n\n /* 3张、5-9张 -> 3列 */\n &[data-count=\"3\"],\n &[data-count=\"5\"],\n &[data-count=\"6\"],\n &[data-count=\"7\"],\n &[data-count=\"8\"],\n &[data-count=\"9\"] {\n grid-template-columns: repeat(3, 1fr);\n min-width: 260px;\n max-width: 320px;\n }\n `,\n\n imageItem: css`\n position: relative;\n width: 100%;\n min-width: 80px;\n padding-top: 100%; /* 1:1 正方形 */\n height: 0;\n overflow: hidden;\n border-radius: 8px;\n background-color: #f5f5f5;\n border: 1px solid rgba(0, 0, 0, 0.06);\n\n .ant-image {\n position: absolute !important;\n top: 0;\n left: 0;\n width: 100% !important;\n height: 100% !important;\n display: flex !important;\n justify-content: center;\n align-items: center;\n }\n\n img {\n width: 100% !important;\n height: 100% !important;\n object-fit: cover !important;\n display: block !important;\n }\n `,\n\n imageOverlay: css`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.05);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n `,\n\n removeBtn: css`\n position: absolute;\n top: 4px;\n right: 4px;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: 20;\n padding: 0;\n font-size: 10px;\n transition: all 0.2s ease;\n\n &:hover {\n background: rgba(0, 0, 0, 0.8);\n transform: scale(1.1);\n }\n `,\n\n // 文件列表\n fileList: css`\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n `,\n\n fileCard: css`\n position: relative;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n background: #fafafa;\n border: 1px solid #f0f0f0;\n border-radius: 8px;\n min-width: 200px;\n max-width: 280px;\n min-height: 64px;\n transition: all 0.2s ease;\n\n &:hover {\n background: #f5f5f5;\n border-color: #e0e0e0;\n }\n `,\n\n // 图片缩略图容器\n imageThumbnail: css`\n position: relative;\n width: 44px;\n height: 44px;\n flex-shrink: 0;\n border-radius: 4px;\n overflow: hidden;\n background-color: #f5f5f5;\n border: 1px solid rgba(0, 0, 0, 0.06);\n\n .ant-image {\n width: 100% !important;\n height: 100% !important;\n display: flex !important;\n justify-content: center;\n align-items: center;\n }\n\n img {\n width: 100% !important;\n height: 100% !important;\n object-fit: cover !important;\n display: block !important;\n }\n `,\n\n fileIcon: css`\n font-size: 24px;\n flex-shrink: 0;\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n `,\n\n fileInfo: css`\n flex: 1;\n min-width: 0;\n overflow: hidden;\n `,\n\n fileName: css`\n font-size: 13px;\n font-weight: 500;\n color: #262626;\n margin-bottom: 4px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n `,\n\n fileSize: css`\n font-size: 11px;\n color: #8c8c8c;\n `,\n\n progress: css`\n margin-top: 4px;\n\n .ant-progress-inner {\n height: 4px !important;\n }\n\n .ant-progress-bg {\n height: 4px !important;\n }\n `,\n\n fileRemoveBtn: css`\n position: absolute;\n top: -6px;\n right: -6px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.75);\n color: #fff;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: 1;\n padding: 0;\n font-size: 10px;\n transition: all 0.2s ease;\n\n &:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: scale(1.1);\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n `,\n};\n\nconst FileGallery: React.FC<FileGalleryProps> = ({ files, onRemove }) => {\n if (files.length === 0) return null;\n\n // 调试日志\n // if (process.env.NODE_ENV === \"development\") {\n // console.log(\n // \"[FileGallery] Rendering files:\",\n // files.map((f) => ({\n // id: f.id,\n // name: f.name,\n // type: f.type,\n // status: f.status,\n // hasFile: !!f.file,\n // response: f.response,\n // })),\n // );\n // }\n\n return (\n <div className={styles.container}>\n {/* 统一的文件列表 */}\n <div className={styles.fileList}>\n <Image.PreviewGroup>\n {files.map((file) => {\n const isImage = isImageFile(file);\n\n if (isImage) {\n // 图片卡片\n const url =\n file.response?.fileUrl ||\n file.response?.tempUrl ||\n file.tempUrl ||\n (file.file ? URL.createObjectURL(file.file) : \"\");\n\n // if (process.env.NODE_ENV === 'development') {\n // console.log('[FileGallery] Image URL for', file.name, ':', {\n // url,\n // 'response.fileUrl': file.response?.fileUrl,\n // 'response.tempUrl': file.response?.tempUrl,\n // 'tempUrl': file.tempUrl,\n // 'hasFile': !!file.file,\n // });\n // }\n\n return (\n <div key={file.id} className={styles.fileCard}>\n {/* 图片缩略图 */}\n <div className={styles.imageThumbnail}>\n <Image\n src={url}\n alt={file.name}\n fallback=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==\"\n preview={{\n src: url,\n }}\n />\n\n {/* 上传进度遮罩 */}\n {file.status === \"uploading\" && (\n <div className={styles.imageOverlay}>\n <Progress\n type=\"circle\"\n percent={file.progress}\n size={30}\n strokeColor=\"#1677ff\"\n />\n </div>\n )}\n </div>\n\n {/* 文件信息 */}\n <div className={styles.fileInfo}>\n <Tooltip title={file.name}>\n <div className={styles.fileName}>\n {file.name.length > 15\n ? `${file.name.substring(0, 15)}...`\n : file.name}\n </div>\n </Tooltip>\n <div className={styles.fileSize}>\n {formatFileSize(file.size)}\n </div>\n </div>\n\n {/* 删除按钮 */}\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(file.id)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n </div>\n );\n } else {\n // 文件卡片\n const { icon, color } = getFileIcon(file);\n\n return (\n <div key={file.id} className={styles.fileCard}>\n <div className={styles.fileIcon} style={{ color }}>\n {icon}\n </div>\n\n <div className={styles.fileInfo}>\n <Tooltip title={file.name}>\n <div className={styles.fileName}>\n {file.name.length > 15\n ? `${file.name.substring(0, 15)}...`\n : file.name}\n </div>\n </Tooltip>\n\n {file.status === \"uploading\" ? (\n <Progress\n percent={file.progress}\n size=\"small\"\n showInfo={false}\n strokeColor=\"#1677ff\"\n className={styles.progress}\n />\n ) : (\n <div className={styles.fileSize}>\n {formatFileSize(file.size)}\n </div>\n )}\n\n {file.status === \"error\" && file.errorMessage && (\n <div\n style={{\n fontSize: \"11px\",\n color: \"#ff4d4f\",\n marginTop: \"2px\",\n }}\n >\n {file.errorMessage}\n </div>\n )}\n </div>\n\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(file.id)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n </div>\n );\n }\n })}\n </Image.PreviewGroup>\n </div>\n </div>\n );\n};\n\nexport default FileGallery;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import React, { useState, useEffect } from \"react\";\nimport { Image, Tooltip, Progress } from \"antd\";\nimport {\n FileOutlined,\n FilePdfOutlined,\n FileWordOutlined,\n FileExcelOutlined,\n FilePptOutlined,\n FileImageOutlined,\n CloseOutlined,\n AudioOutlined,\n VideoCameraOutlined,\n} from \"@ant-design/icons\";\nimport { LocalFile } from \"../../types/XAdkSender\";\nimport { css } from \"@emotion/css\";\n\ninterface FileGalleryProps {\n files: LocalFile[];\n onRemove: (id: string) => void;\n}\n\ninterface FileItemProps {\n file: LocalFile;\n onRemove: (id: string) => void;\n}\n\n// 判断是否是图片文件\nconst isImageFile = (file: LocalFile): boolean => {\n if (!file.type) return false;\n return file.type.startsWith(\"image/\");\n};\n\n// 获取文件扩展名\nconst getFileExtension = (filename: string): string => {\n const ext = filename.split(\".\").pop();\n return ext ? ext.toLowerCase() : \"\";\n};\n\n// 判断是否是音频文件\nconst isAudioFile = (file: LocalFile): boolean => {\n if (!file.type) return false;\n return file.type.startsWith(\"audio/\");\n};\n\n// 判断是否是视频文件\nconst isVideoFile = (file: LocalFile): boolean => {\n if (!file.type) return false;\n return file.type.startsWith(\"video/\");\n};\n\n// 获取文件图标和颜色\nconst getFileIcon = (\n file: LocalFile,\n): { icon: React.ReactNode; color: string } => {\n const ext = getFileExtension(file.name);\n\n // PDF\n if (ext === \"pdf\") {\n return { icon: <FilePdfOutlined />, color: \"#ff4d4f\" };\n }\n\n // Word\n if ([\"doc\", \"docx\"].includes(ext)) {\n return { icon: <FileWordOutlined />, color: \"#1677ff\" };\n }\n\n // Excel\n if ([\"xls\", \"xlsx\", \"csv\"].includes(ext)) {\n return { icon: <FileExcelOutlined />, color: \"#22b35e\" };\n }\n\n // PPT\n if ([\"ppt\", \"pptx\"].includes(ext)) {\n return { icon: <FilePptOutlined />, color: \"#ff6e31\" };\n }\n\n // Audio\n if ([\"mp3\", \"wav\", \"m4a\", \"aac\", \"ogg\", \"flac\"].includes(ext)) {\n return { icon: <AudioOutlined />, color: \"#722ed1\" };\n }\n\n // Video\n if ([\"mp4\", \"mov\", \"webm\", \"mkv\", \"avi\"].includes(ext)) {\n return { icon: <VideoCameraOutlined />, color: \"#fa8c16\" };\n }\n\n // 图片\n if (isImageFile(file)) {\n return { icon: <FileImageOutlined />, color: \"#8c8c8c\" };\n }\n\n // 默认\n return { icon: <FileOutlined />, color: \"#8c8c8c\" };\n};\n\n// 格式化文件大小\nconst formatFileSize = (bytes: number): string => {\n if (bytes < 1024) return bytes + \" B\";\n if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + \" KB\";\n return (bytes / (1024 * 1024)).toFixed(1) + \" MB\";\n};\n\nconst styles = {\n container: css`\n padding: 12px 0;\n display: flex;\n flex-direction: column;\n gap: 12px;\n `,\n\n // 图片九宫格容器\n imageGrid: css`\n display: grid;\n gap: 8px;\n width: fit-content;\n min-width: 80px;\n max-width: 100%;\n /* 默认3列布局 */\n grid-template-columns: repeat(3, 1fr);\n\n /* 单张图 */\n &[data-count=\"1\"] {\n grid-template-columns: 1fr;\n min-width: 100px;\n max-width: 200px;\n }\n\n /* 2张、4张 -> 2列 */\n &[data-count=\"2\"],\n &[data-count=\"4\"] {\n grid-template-columns: repeat(2, 1fr);\n min-width: 180px;\n max-width: 240px;\n }\n\n /* 3张、5-9张 -> 3列 */\n &[data-count=\"3\"],\n &[data-count=\"5\"],\n &[data-count=\"6\"],\n &[data-count=\"7\"],\n &[data-count=\"8\"],\n &[data-count=\"9\"] {\n grid-template-columns: repeat(3, 1fr);\n min-width: 260px;\n max-width: 320px;\n }\n `,\n\n imageItem: css`\n position: relative;\n width: 100%;\n min-width: 80px;\n padding-top: 100%; /* 1:1 正方形 */\n height: 0;\n overflow: hidden;\n border-radius: 8px;\n background-color: #f5f5f5;\n border: 1px solid rgba(0, 0, 0, 0.06);\n\n .ant-image {\n position: absolute !important;\n top: 0;\n left: 0;\n width: 100% !important;\n height: 100% !important;\n display: flex !important;\n justify-content: center;\n align-items: center;\n }\n\n img {\n width: 100% !important;\n height: 100% !important;\n object-fit: cover !important;\n display: block !important;\n }\n `,\n\n imageOverlay: css`\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.05);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n `,\n\n removeBtn: css`\n position: absolute;\n top: 4px;\n right: 4px;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: 20;\n padding: 0;\n font-size: 10px;\n transition: all 0.2s ease;\n\n &:hover {\n background: rgba(0, 0, 0, 0.8);\n transform: scale(1.1);\n }\n `,\n\n // 文件列表\n fileList: css`\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n `,\n\n fileCard: css`\n position: relative;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 6px 12px;\n background: #fafafa;\n border: 1px solid #f0f0f0;\n border-radius: 8px;\n min-width: 260px;\n max-width: 280px;\n min-height: 64px;\n transition: all 0.2s ease;\n\n &:hover {\n background: #f5f5f5;\n border-color: #e0e0e0;\n }\n `,\n\n // 图片缩略图容器\n imageThumbnail: css`\n position: relative;\n width: 44px;\n height: 44px;\n flex-shrink: 0;\n border-radius: 4px;\n overflow: hidden;\n background-color: #f5f5f5;\n border: 1px solid rgba(0, 0, 0, 0.06);\n\n .ant-image {\n width: 100% !important;\n height: 100% !important;\n display: flex !important;\n justify-content: center;\n align-items: center;\n }\n\n img {\n width: 100% !important;\n height: 100% !important;\n object-fit: cover !important;\n display: block !important;\n }\n `,\n\n fileIcon: css`\n font-size: 24px;\n flex-shrink: 0;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n `,\n\n fileInfo: css`\n flex: 1;\n min-width: 0;\n overflow: hidden;\n `,\n\n fileName: css`\n font-size: 13px;\n font-weight: 500;\n color: #262626;\n margin-bottom: 4px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n `,\n\n fileSize: css`\n font-size: 11px;\n color: #8c8c8c;\n `,\n\n progress: css`\n margin-top: 4px;\n\n .ant-progress-inner {\n height: 4px !important;\n }\n\n .ant-progress-bg {\n height: 4px !important;\n }\n `,\n\n fileRemoveBtn: css`\n position: absolute;\n top: -6px;\n right: -6px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.75);\n color: #fff;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: 1;\n padding: 0;\n font-size: 10px;\n transition: all 0.2s ease;\n\n &:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: scale(1.1);\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n `,\n};\n\nconst FileItem: React.FC<FileItemProps> = ({ file, onRemove }) => {\n const [objectUrl, setObjectUrl] = useState(\"\");\n\n useEffect(() => {\n if (!file.file) return;\n\n const url = URL.createObjectURL(file.file);\n setObjectUrl(url);\n\n return () => URL.revokeObjectURL(url);\n }, [file.file]);\n\n const isImage = isImageFile(file);\n const isAudio = isAudioFile(file);\n const isVideo = isVideoFile(file);\n\n const url =\n file.response?.fileUrl ||\n file.response?.tempUrl ||\n file.tempUrl ||\n objectUrl;\n\n if (isImage) {\n // 图片卡片\n return (\n <div key={file.id} className={styles.fileCard}>\n {/* 图片缩略图 */}\n <div className={styles.imageThumbnail}>\n <Image\n src={url}\n alt={file.name}\n fallback=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==\"\n preview={{\n src: url,\n }}\n />\n\n {/* 上传进度遮罩 */}\n {file.status === \"uploading\" && (\n <div className={styles.imageOverlay}>\n <Progress\n type=\"circle\"\n percent={file.progress}\n size={30}\n strokeColor=\"#1677ff\"\n />\n </div>\n )}\n </div>\n\n {/* 文件信息 */}\n <div className={styles.fileInfo}>\n <Tooltip title={file.name}>\n <div className={styles.fileName}>\n {file.name.length > 15\n ? `${file.name.substring(0, 15)}...`\n : file.name}\n </div>\n </Tooltip>\n <div className={styles.fileSize}>{formatFileSize(file.size)}</div>\n </div>\n\n {/* 删除按钮 */}\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(file.id)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n </div>\n );\n } else if (isAudio) {\n return (\n <div key={file.id} className={styles.fileCard}>\n <div className={styles.fileIcon} style={{ color: \"#722ed1\" }}>\n <AudioOutlined />\n </div>\n\n <div className={styles.fileInfo}>\n <Tooltip title={file.name}>\n <div className={styles.fileName}>{file.name}</div>\n </Tooltip>\n\n <audio src={url} controls style={{ width: \"100%\", height: 28 }} />\n </div>\n\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(file.id)}\n disabled={file.status === \"uploading\"}\n >\n <CloseOutlined />\n </button>\n </div>\n );\n } else if (isVideo) {\n return (\n <div key={file.id} className={styles.fileCard}>\n <div className={styles.fileIcon} style={{ color: \"#fa8c16\" }}>\n <VideoCameraOutlined />\n </div>\n\n <div className={styles.fileInfo}>\n <Tooltip title={file.name}>\n <div className={styles.fileName}>{file.name}</div>\n </Tooltip>\n\n <video src={url} controls style={{ width: \"100%\", height: 40 }} />\n </div>\n\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(file.id)}\n disabled={file.status === \"uploading\"}\n >\n <CloseOutlined />\n </button>\n </div>\n );\n } else {\n // 文件卡片\n const { icon, color } = getFileIcon(file);\n\n return (\n <div key={file.id} className={styles.fileCard}>\n <div className={styles.fileIcon} style={{ color }}>\n {icon}\n </div>\n\n <div className={styles.fileInfo}>\n <Tooltip title={file.name}>\n <div className={styles.fileName}>\n {file.name.length > 15\n ? `${file.name.substring(0, 15)}...`\n : file.name}\n </div>\n </Tooltip>\n\n {file.status === \"uploading\" ? (\n <Progress\n percent={file.progress}\n size=\"small\"\n showInfo={false}\n strokeColor=\"#1677ff\"\n className={styles.progress}\n />\n ) : (\n <div className={styles.fileSize}>{formatFileSize(file.size)}</div>\n )}\n\n {file.status === \"error\" && file.errorMessage && (\n <div\n style={{\n fontSize: \"11px\",\n color: \"#ff4d4f\",\n marginTop: \"2px\",\n }}\n >\n {file.errorMessage}\n </div>\n )}\n </div>\n\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(file.id)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n </div>\n );\n }\n};\n\nconst FileGallery: React.FC<FileGalleryProps> = ({ files, onRemove }) => {\n if (files.length === 0) return null;\n const [objectUrl, setObjectUrl] = useState(\"\");\n // 调试日志\n // if (process.env.NODE_ENV === \"development\") {\n // console.log(\n // \"[FileGallery] Rendering files:\",\n // files.map((f) => ({\n // id: f.id,\n // name: f.name,\n // type: f.type,\n // status: f.status,\n // hasFile: !!f.file,\n // response: f.response,\n // })),\n // );\n // }\n\n return (\n <div className={styles.container}>\n {/* 统一的文件列表 */}\n <div className={styles.fileList}>\n <Image.PreviewGroup>\n {files.map((file) => (\n <FileItem key={file.id} file={file} onRemove={onRemove} />\n ))}\n </Image.PreviewGroup>\n </div>\n </div>\n );\n};\n\nexport default FileGallery;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA2C;AAC3C,kBAAyC;AACzC,mBAUO;AAEP,iBAAoB;AA4CD;AA/BnB,IAAM,cAAc,CAAC,SAA6B;AAChD,MAAI,CAAC,KAAK;AAAM,WAAO;AACvB,SAAO,KAAK,KAAK,WAAW,QAAQ;AACtC;AAGA,IAAM,mBAAmB,CAAC,aAA6B;AACrD,QAAM,MAAM,SAAS,MAAM,GAAG,EAAE,IAAI;AACpC,SAAO,MAAM,IAAI,YAAY,IAAI;AACnC;AAGA,IAAM,cAAc,CAAC,SAA6B;AAChD,MAAI,CAAC,KAAK;AAAM,WAAO;AACvB,SAAO,KAAK,KAAK,WAAW,QAAQ;AACtC;AAGA,IAAM,cAAc,CAAC,SAA6B;AAChD,MAAI,CAAC,KAAK;AAAM,WAAO;AACvB,SAAO,KAAK,KAAK,WAAW,QAAQ;AACtC;AAGA,IAAM,cAAc,CAClB,SAC6C;AAC7C,QAAM,MAAM,iBAAiB,KAAK,IAAI;AAGtC,MAAI,QAAQ,OAAO;AACjB,WAAO,EAAE,MAAM,4CAAC,gCAAgB,GAAI,OAAO,UAAU;AAAA,EACvD;AAGA,MAAI,CAAC,OAAO,MAAM,EAAE,SAAS,GAAG,GAAG;AACjC,WAAO,EAAE,MAAM,4CAAC,iCAAiB,GAAI,OAAO,UAAU;AAAA,EACxD;AAGA,MAAI,CAAC,OAAO,QAAQ,KAAK,EAAE,SAAS,GAAG,GAAG;AACxC,WAAO,EAAE,MAAM,4CAAC,kCAAkB,GAAI,OAAO,UAAU;AAAA,EACzD;AAGA,MAAI,CAAC,OAAO,MAAM,EAAE,SAAS,GAAG,GAAG;AACjC,WAAO,EAAE,MAAM,4CAAC,gCAAgB,GAAI,OAAO,UAAU;AAAA,EACvD;AAGA,MAAI,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM,EAAE,SAAS,GAAG,GAAG;AAC7D,WAAO,EAAE,MAAM,4CAAC,8BAAc,GAAI,OAAO,UAAU;AAAA,EACrD;AAGA,MAAI,CAAC,OAAO,OAAO,QAAQ,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACtD,WAAO,EAAE,MAAM,4CAAC,oCAAoB,GAAI,OAAO,UAAU;AAAA,EAC3D;AAGA,MAAI,YAAY,IAAI,GAAG;AACrB,WAAO,EAAE,MAAM,4CAAC,kCAAkB,GAAI,OAAO,UAAU;AAAA,EACzD;AAGA,SAAO,EAAE,MAAM,4CAAC,6BAAa,GAAI,OAAO,UAAU;AACpD;AAGA,IAAM,iBAAiB,CAAC,UAA0B;AAChD,MAAI,QAAQ;AAAM,WAAO,QAAQ;AACjC,MAAI,QAAQ,OAAO;AAAM,YAAQ,QAAQ,MAAM,QAAQ,CAAC,IAAI;AAC5D,UAAQ,SAAS,OAAO,OAAO,QAAQ,CAAC,IAAI;AAC9C;AAEA,IAAM,SAAS;AAAA,EACb,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQX,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqCX,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BX,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAad,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BX,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAMV,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBV,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BhB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUV,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAMV,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUV,UAAU;AAAA;AAAA;AAAA;AAAA,EAKV,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYV,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BjB;AAEA,IAAM,WAAoC,CAAC,EAAE,MAAM,SAAS,MAAM;AAxVlE;AAyVE,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,EAAE;AAE7C,8BAAU,MAAM;AACd,QAAI,CAAC,KAAK;AAAM;AAEhB,UAAMA,OAAM,IAAI,gBAAgB,KAAK,IAAI;AACzC,iBAAaA,IAAG;AAEhB,WAAO,MAAM,IAAI,gBAAgBA,IAAG;AAAA,EACtC,GAAG,CAAC,KAAK,IAAI,CAAC;AAEd,QAAM,UAAU,YAAY,IAAI;AAChC,QAAM,UAAU,YAAY,IAAI;AAChC,QAAM,UAAU,YAAY,IAAI;AAEhC,QAAM,QACJ,UAAK,aAAL,mBAAe,cACf,UAAK,aAAL,mBAAe,YACf,KAAK,WACL;AAEF,MAAI,SAAS;AAEX,WACE,6CAAC,SAAkB,WAAW,OAAO,UAEnC;AAAA,mDAAC,SAAI,WAAW,OAAO,gBACrB;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK,KAAK;AAAA,YACV,UAAS;AAAA,YACT,SAAS;AAAA,cACP,KAAK;AAAA,YACP;AAAA;AAAA,QACF;AAAA,QAGC,KAAK,WAAW,eACf,4CAAC,SAAI,WAAW,OAAO,cACrB;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,KAAK;AAAA,YACd,MAAM;AAAA,YACN,aAAY;AAAA;AAAA,QACd,GACF;AAAA,SAEJ;AAAA,MAGA,6CAAC,SAAI,WAAW,OAAO,UACrB;AAAA,oDAAC,uBAAQ,OAAO,KAAK,MACnB,sDAAC,SAAI,WAAW,OAAO,UACpB,eAAK,KAAK,SAAS,KAChB,GAAG,KAAK,KAAK,UAAU,GAAG,EAAE,SAC5B,KAAK,MACX,GACF;AAAA,QACA,4CAAC,SAAI,WAAW,OAAO,UAAW,yBAAe,KAAK,IAAI,GAAE;AAAA,SAC9D;AAAA,MAGA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,UAC/B,UAAU,KAAK,WAAW;AAAA,UAC1B,cAAW;AAAA,UAEX,sDAAC,8BAAc;AAAA;AAAA,MACjB;AAAA,SA7CQ,KAAK,EA8Cf;AAAA,EAEJ,WAAW,SAAS;AAClB,WACE,6CAAC,SAAkB,WAAW,OAAO,UACnC;AAAA,kDAAC,SAAI,WAAW,OAAO,UAAU,OAAO,EAAE,OAAO,UAAU,GACzD,sDAAC,8BAAc,GACjB;AAAA,MAEA,6CAAC,SAAI,WAAW,OAAO,UACrB;AAAA,oDAAC,uBAAQ,OAAO,KAAK,MACnB,sDAAC,SAAI,WAAW,OAAO,UAAW,eAAK,MAAK,GAC9C;AAAA,QAEA,4CAAC,WAAM,KAAK,KAAK,UAAQ,MAAC,OAAO,EAAE,OAAO,QAAQ,QAAQ,GAAG,GAAG;AAAA,SAClE;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,UAC/B,UAAU,KAAK,WAAW;AAAA,UAE1B,sDAAC,8BAAc;AAAA;AAAA,MACjB;AAAA,SAnBQ,KAAK,EAoBf;AAAA,EAEJ,WAAW,SAAS;AAClB,WACE,6CAAC,SAAkB,WAAW,OAAO,UACnC;AAAA,kDAAC,SAAI,WAAW,OAAO,UAAU,OAAO,EAAE,OAAO,UAAU,GACzD,sDAAC,oCAAoB,GACvB;AAAA,MAEA,6CAAC,SAAI,WAAW,OAAO,UACrB;AAAA,oDAAC,uBAAQ,OAAO,KAAK,MACnB,sDAAC,SAAI,WAAW,OAAO,UAAW,eAAK,MAAK,GAC9C;AAAA,QAEA,4CAAC,WAAM,KAAK,KAAK,UAAQ,MAAC,OAAO,EAAE,OAAO,QAAQ,QAAQ,GAAG,GAAG;AAAA,SAClE;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,UAC/B,UAAU,KAAK,WAAW;AAAA,UAE1B,sDAAC,8BAAc;AAAA;AAAA,MACjB;AAAA,SAnBQ,KAAK,EAoBf;AAAA,EAEJ,OAAO;AAEL,UAAM,EAAE,MAAM,MAAM,IAAI,YAAY,IAAI;AAExC,WACE,6CAAC,SAAkB,WAAW,OAAO,UACnC;AAAA,kDAAC,SAAI,WAAW,OAAO,UAAU,OAAO,EAAE,MAAM,GAC7C,gBACH;AAAA,MAEA,6CAAC,SAAI,WAAW,OAAO,UACrB;AAAA,oDAAC,uBAAQ,OAAO,KAAK,MACnB,sDAAC,SAAI,WAAW,OAAO,UACpB,eAAK,KAAK,SAAS,KAChB,GAAG,KAAK,KAAK,UAAU,GAAG,EAAE,SAC5B,KAAK,MACX,GACF;AAAA,QAEC,KAAK,WAAW,cACf;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,KAAK;AAAA,YACd,MAAK;AAAA,YACL,UAAU;AAAA,YACV,aAAY;AAAA,YACZ,WAAW,OAAO;AAAA;AAAA,QACpB,IAEA,4CAAC,SAAI,WAAW,OAAO,UAAW,yBAAe,KAAK,IAAI,GAAE;AAAA,QAG7D,KAAK,WAAW,WAAW,KAAK,gBAC/B;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU;AAAA,cACV,OAAO;AAAA,cACP,WAAW;AAAA,YACb;AAAA,YAEC,eAAK;AAAA;AAAA,QACR;AAAA,SAEJ;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,UAC/B,UAAU,KAAK,WAAW;AAAA,UAC1B,cAAW;AAAA,UAEX,sDAAC,8BAAc;AAAA;AAAA,MACjB;AAAA,SA9CQ,KAAK,EA+Cf;AAAA,EAEJ;AACF;AAEA,IAAM,cAA0C,CAAC,EAAE,OAAO,SAAS,MAAM;AACvE,MAAI,MAAM,WAAW;AAAG,WAAO;AAC/B,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,EAAE;AAgB7C,SACE,4CAAC,SAAI,WAAW,OAAO,WAErB,sDAAC,SAAI,WAAW,OAAO,UACrB,sDAAC,kBAAM,cAAN,EACE,gBAAM,IAAI,CAAC,SACV,4CAAC,YAAuB,MAAY,YAArB,KAAK,EAAoC,CACzD,GACH,GACF,GACF;AAEJ;AAEA,IAAO,sBAAQ;",
|
|
6
|
+
"names": ["url"]
|
|
7
7
|
}
|