@spacecorexdev/core 0.0.2 → 0.0.5
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/package.json +20 -38
- package/public/cmaps/78-EUC-H.bcmap +0 -0
- package/public/cmaps/78-EUC-V.bcmap +0 -0
- package/public/cmaps/78-H.bcmap +0 -0
- package/public/cmaps/78-RKSJ-H.bcmap +0 -0
- package/public/cmaps/78-RKSJ-V.bcmap +0 -0
- package/public/cmaps/78-V.bcmap +0 -0
- package/public/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/public/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/public/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/public/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/public/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/public/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/public/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/public/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/public/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/public/cmaps/Add-H.bcmap +0 -0
- package/public/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/public/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/public/cmaps/Add-V.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/public/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/public/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/public/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/public/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/public/cmaps/B5-H.bcmap +0 -0
- package/public/cmaps/B5-V.bcmap +0 -0
- package/public/cmaps/B5pc-H.bcmap +0 -0
- package/public/cmaps/B5pc-V.bcmap +0 -0
- package/public/cmaps/CNS-EUC-H.bcmap +0 -0
- package/public/cmaps/CNS-EUC-V.bcmap +0 -0
- package/public/cmaps/CNS1-H.bcmap +0 -0
- package/public/cmaps/CNS1-V.bcmap +0 -0
- package/public/cmaps/CNS2-H.bcmap +0 -0
- package/public/cmaps/CNS2-V.bcmap +3 -0
- package/public/cmaps/ETHK-B5-H.bcmap +0 -0
- package/public/cmaps/ETHK-B5-V.bcmap +0 -0
- package/public/cmaps/ETen-B5-H.bcmap +0 -0
- package/public/cmaps/ETen-B5-V.bcmap +0 -0
- package/public/cmaps/ETenms-B5-H.bcmap +3 -0
- package/public/cmaps/ETenms-B5-V.bcmap +0 -0
- package/public/cmaps/EUC-H.bcmap +0 -0
- package/public/cmaps/EUC-V.bcmap +0 -0
- package/public/cmaps/Ext-H.bcmap +0 -0
- package/public/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/public/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/public/cmaps/Ext-V.bcmap +0 -0
- package/public/cmaps/GB-EUC-H.bcmap +0 -0
- package/public/cmaps/GB-EUC-V.bcmap +0 -0
- package/public/cmaps/GB-H.bcmap +4 -0
- package/public/cmaps/GB-V.bcmap +0 -0
- package/public/cmaps/GBK-EUC-H.bcmap +0 -0
- package/public/cmaps/GBK-EUC-V.bcmap +0 -0
- package/public/cmaps/GBK2K-H.bcmap +0 -0
- package/public/cmaps/GBK2K-V.bcmap +0 -0
- package/public/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/public/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/public/cmaps/GBT-EUC-H.bcmap +0 -0
- package/public/cmaps/GBT-EUC-V.bcmap +0 -0
- package/public/cmaps/GBT-H.bcmap +0 -0
- package/public/cmaps/GBT-V.bcmap +0 -0
- package/public/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/public/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/public/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/public/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/public/cmaps/H.bcmap +0 -0
- package/public/cmaps/HKdla-B5-H.bcmap +0 -0
- package/public/cmaps/HKdla-B5-V.bcmap +0 -0
- package/public/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/public/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/public/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/public/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/public/cmaps/HKm314-B5-H.bcmap +0 -0
- package/public/cmaps/HKm314-B5-V.bcmap +0 -0
- package/public/cmaps/HKm471-B5-H.bcmap +0 -0
- package/public/cmaps/HKm471-B5-V.bcmap +0 -0
- package/public/cmaps/HKscs-B5-H.bcmap +0 -0
- package/public/cmaps/HKscs-B5-V.bcmap +0 -0
- package/public/cmaps/Hankaku.bcmap +0 -0
- package/public/cmaps/Hiragana.bcmap +0 -0
- package/public/cmaps/KSC-EUC-H.bcmap +0 -0
- package/public/cmaps/KSC-EUC-V.bcmap +0 -0
- package/public/cmaps/KSC-H.bcmap +0 -0
- package/public/cmaps/KSC-Johab-H.bcmap +0 -0
- package/public/cmaps/KSC-Johab-V.bcmap +0 -0
- package/public/cmaps/KSC-V.bcmap +0 -0
- package/public/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/public/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/public/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/public/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/public/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/public/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/public/cmaps/Katakana.bcmap +0 -0
- package/public/cmaps/LICENSE +36 -0
- package/public/cmaps/NWP-H.bcmap +0 -0
- package/public/cmaps/NWP-V.bcmap +0 -0
- package/public/cmaps/RKSJ-H.bcmap +0 -0
- package/public/cmaps/RKSJ-V.bcmap +0 -0
- package/public/cmaps/Roman.bcmap +0 -0
- package/public/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/public/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/public/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/public/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/public/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/public/cmaps/V.bcmap +0 -0
- package/public/cmaps/WP-Symbol.bcmap +0 -0
- package/public/polyfills/polyfills.js +802 -0
- package/public/vendor/docx/docx.worker.js +5 -0
- package/public/vendor/docx/jszip.min.js +13 -0
- package/public/vendor/libarchive/libarchive.wasm +0 -0
- package/public/vendor/libarchive/worker-bundle.js +6 -0
- package/public/vendor/pptx/pptx.worker.js +26 -0
- package/public/wasm/cad/0.8.2/dwfv-render.wasm +0 -0
- package/public/wasm/cad/0.8.2/dwg-worker.js +24 -0
- package/public/wasm/cad/0.8.2/dwg-worker.js.map +1 -0
- package/public/wasm/cad/0.8.2/libredwg-web.js +2 -0
- package/public/wasm/cad/0.8.2/libredwg-web.wasm +0 -0
- package/public/wasm/cad/dwfv-render.wasm +0 -0
- package/public/wasm/cad/dwg-worker.js +24 -0
- package/public/wasm/cad/dwg-worker.js.map +1 -0
- package/public/wasm/cad/libredwg-web.js +2 -0
- package/public/wasm/cad/libredwg-web.wasm +0 -0
- package/public/wasm/data/sql-wasm.wasm +0 -0
- package/public/wasm/hdiff.wasm +0 -0
- package/public/wasm/model/LICENSE.occt-import-js.txt +504 -0
- package/public/wasm/model/LICENSE.occt.txt +502 -0
- package/public/wasm/model/occt-import-js.js +19 -0
- package/public/wasm/model/occt-import-js.wasm +0 -0
- package/public/wasm/model/occt-worker.js +83 -0
- package/public/wasm/typst/fonts/DejaVuSansMono-Bold.ttf +0 -0
- package/public/wasm/typst/fonts/DejaVuSansMono-BoldOblique.ttf +0 -0
- package/public/wasm/typst/fonts/DejaVuSansMono-Oblique.ttf +0 -0
- package/public/wasm/typst/fonts/DejaVuSansMono.ttf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-Bold.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-BoldItalic.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-Italic.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-Regular.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-Semibold.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-SemiboldItalic.otf +0 -0
- package/public/wasm/typst/fonts/NewCM10-Bold.otf +0 -0
- package/public/wasm/typst/fonts/NewCM10-BoldItalic.otf +0 -0
- package/public/wasm/typst/fonts/NewCM10-Italic.otf +0 -0
- package/public/wasm/typst/fonts/NewCM10-Regular.otf +0 -0
- package/public/wasm/typst/fonts/NewCMMath-Bold.otf +0 -0
- package/public/wasm/typst/fonts/NewCMMath-Book.otf +0 -0
- package/public/wasm/typst/fonts/NewCMMath-Regular.otf +0 -0
- package/public/wasm/typst/fonts/README.md +7 -0
- package/public/wasm/typst/typst_ts_renderer_bg.wasm +0 -0
- package/public/wasm/typst/typst_ts_web_compiler_bg.wasm +0 -0
- package/scripts/patch-docx-grid.cjs +412 -0
- package/src/api/_base.ts +243 -0
- package/src/api/index.ts +17 -0
- package/src/api/project.ts +1345 -0
- package/src/api/user.ts +1174 -0
- package/src/contract.ts +50 -0
- package/src/hooks/index.ts +2 -0
- package/{dist/hooks/index.js → src/hooks/useLongPress.ts} +53 -49
- package/src/hooks/useOnlineStatus.ts +22 -0
- package/src/index.ts +14 -0
- package/src/types/id.ts +2 -0
- package/src/types/index.ts +5 -0
- package/src/types/project/base.ts +63 -0
- package/src/types/project/contract.ts +79 -0
- package/src/types/project/contractStatus.tsx +15 -0
- package/src/types/project/index.ts +5 -0
- package/src/types/project/member.ts +46 -0
- package/src/types/project/progress.ts +43 -0
- package/src/types/projectRole.ts +17 -0
- package/src/types/theme.ts +1 -0
- package/src/types/user/index.ts +1 -0
- package/src/types/user/role.ts +7 -0
- package/src/ui/CommentTimeline/index.tsx +330 -0
- package/src/ui/FileManager/FileContextMenu.tsx +628 -0
- package/src/ui/FileManager/FileGridView.tsx +529 -0
- package/src/ui/FileManager/FileTableView.tsx +405 -0
- package/src/ui/FileManager/FileToolbar.tsx +119 -0
- package/src/ui/FileManager/FileVersionHistoryModal.tsx +175 -0
- package/src/ui/FileManager/MoveCopyToProjectModal.tsx +119 -0
- package/src/ui/FileManager/ShareToWechatModal.tsx +419 -0
- package/src/ui/FileManager/hooks/useFileManagerActions.ts +2532 -0
- package/src/ui/FileManager/hooks/useFileManagerState.ts +419 -0
- package/src/ui/FileManager/index.tsx +580 -0
- package/src/ui/FileManager/projectFileManagerApi.ts +57 -0
- package/src/ui/FileManager/types.ts +184 -0
- package/src/ui/FileManager/utils/fileDeltaWorker.ts +193 -0
- package/src/ui/FileManager/utils/fileTree.ts +178 -0
- package/src/ui/FileManager/utils/fileUpload.ts +714 -0
- package/src/ui/FileManager/utils/fileUtils.ts +65 -0
- package/src/ui/InvoiceRecordsList/index.tsx +813 -0
- package/src/ui/MyFileSelectorModal.tsx +261 -0
- package/src/ui/ProjectSelector/index.tsx +472 -0
- package/src/ui/ProjectSelector/projectCache.ts +40 -0
- package/src/ui/RoleSelector/index.tsx +473 -0
- package/src/ui/RoleSelector/roleCache.ts +40 -0
- package/src/ui/UIAlert.tsx +399 -0
- package/src/ui/UIAlertExample.tsx +129 -0
- package/src/ui/UIConfirm.tsx +335 -0
- package/src/ui/UIConfirmExample.tsx +165 -0
- package/src/ui/UIDatePicker.tsx +146 -0
- package/src/ui/UIDateRangePicker.tsx +38 -0
- package/src/ui/UIFilePreview/ExcelEditor/index.tsx +617 -0
- package/src/ui/UIFilePreview/ExcelEditor/types.ts +24 -0
- package/src/ui/UIFilePreview/ExportDropdown.css +85 -0
- package/src/ui/UIFilePreview/ExportDropdown.tsx +109 -0
- package/src/ui/UIFilePreview/IndexedDBUtils.ts +564 -0
- package/src/ui/UIFilePreview/MarkdownEditor/exportMarkdownPdf.ts +576 -0
- package/src/ui/UIFilePreview/MarkdownEditor/index.tsx +677 -0
- package/src/ui/UIFilePreview/MarkdownEditor/markdownEditor.css +1005 -0
- package/src/ui/UIFilePreview/MarkdownEditor/types.ts +15 -0
- package/src/ui/UIFilePreview/PPTXEditor/index.tsx +602 -0
- package/src/ui/UIFilePreview/RichDocEditor/exportRDocMarkdown.ts +77 -0
- package/src/ui/UIFilePreview/RichDocEditor/exportRDocPdf.ts +374 -0
- package/src/ui/UIFilePreview/RichDocEditor/index.tsx +730 -0
- package/src/ui/UIFilePreview/RichDocEditor/richdoc-editor.css +59 -0
- package/src/ui/UIFilePreview/UIFilePreview.tsx +611 -0
- package/src/ui/UIFilePreview/WordEditor/index.tsx +3933 -0
- package/src/ui/UIFilePreview/WordEditor/style.ts +1213 -0
- package/src/ui/UIFilePreview/WordEditor/word-editor.css +999 -0
- package/src/ui/UIFilePreview/filePreview.css +193 -0
- package/src/ui/UIFilePreview/filetypes/archive.tsx +66 -0
- package/src/ui/UIFilePreview/filetypes/cad.tsx +287 -0
- package/src/ui/UIFilePreview/filetypes/excel.tsx +355 -0
- package/src/ui/UIFilePreview/filetypes/image.tsx +20 -0
- package/src/ui/UIFilePreview/filetypes/imageLoader.ts +63 -0
- package/src/ui/UIFilePreview/filetypes/pdf.tsx +156 -0
- package/src/ui/UIFilePreview/filetypes/ppt.tsx +535 -0
- package/src/ui/UIFilePreview/filetypes/pptExportPdf.ts +523 -0
- package/src/ui/UIFilePreview/filetypes/video.tsx +482 -0
- package/src/ui/UIFilePreview/filetypes/word.tsx +245 -0
- package/src/ui/UIFilePreview/filetypes/wordExportMarkdown.ts +86 -0
- package/src/ui/UIFilePreview/filetypes/wordExportPdf.tsx +427 -0
- package/src/ui/UIFilePreview/index.ts +35 -0
- package/src/ui/UIFilePreview/pdfPagination.ts +143 -0
- package/src/ui/UIFilePreview/previewUtils.tsx +531 -0
- package/src/ui/UIFileUpload.tsx +382 -0
- package/src/ui/UIImageUpload.tsx +195 -0
- package/src/ui/UILoading.tsx +255 -0
- package/src/ui/UILoadingExample.tsx +139 -0
- package/src/ui/UISelect.tsx +105 -0
- package/src/ui/UIToast.tsx +381 -0
- package/src/ui/UIToastExample.tsx +69 -0
- package/src/ui/UIToastSingle.tsx +279 -0
- package/src/ui/UIViewToggle.tsx +64 -0
- package/src/ui/UserSelector/index.tsx +583 -0
- package/src/ui/index.ts +84 -0
- package/src/ui/upload/image.ts +135 -0
- package/src/ui/upload/index.ts +73 -0
- package/src/ui/upload/submitFile.ts +106 -0
- package/src/ui/upload/submitForm.ts +124 -0
- package/src/ui/upload/upload.err.ts +15 -0
- package/src/ui/upload/upload.ts +250 -0
- package/src/utils/CacheDepartmentInfo.ts +372 -0
- package/src/utils/CacheFileContent.ts +315 -0
- package/src/utils/CachePermissionInfo.ts +235 -0
- package/src/utils/CacheRoleInfo.ts +303 -0
- package/src/utils/CacheUserInfo.ts +818 -0
- package/src/utils/CacheViewToggleInfo.ts +182 -0
- package/src/utils/MessageContentUtils.ts +268 -0
- package/src/utils/clipboard.ts +70 -0
- package/src/utils/companyEmail.ts +19 -0
- package/src/utils/forbidDebugger.ts +59 -0
- package/src/utils/formatters.ts +94 -0
- package/src/utils/htmlUtils.tsx +59 -0
- package/src/utils/index.ts +18 -0
- package/src/utils/keyboard.ts +114 -0
- package/src/utils/mammothApi.ts +16 -0
- package/src/utils/polyfills.ts +928 -0
- package/src/utils/regex.ts +14 -0
- package/src/utils/storage.ts +95 -0
- package/src/utils/workerBootstrap.ts +87 -0
- package/dist/api/index.js +0 -1553
- package/dist/contract.js +0 -5
- package/dist/index.js +0 -4492
- package/dist/types/index.js +0 -49
- package/dist/ui/index.css +0 -1876
- package/dist/ui/index.js +0 -22245
- package/dist/utils/index.js +0 -4296
- /package/{dist → src}/styles/ant-modal.css +0 -0
- /package/{dist → src}/styles/ant-spin.css +0 -0
- /package/{dist → src}/styles/ant-table.css +0 -0
- /package/{dist → src}/styles/index.css +0 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/* eslint-disable react-refresh/only-export-components */
|
|
2
|
+
/**
|
|
3
|
+
* UIConfirm - 全局确认对话框组件
|
|
4
|
+
*
|
|
5
|
+
* 使用示例:
|
|
6
|
+
*
|
|
7
|
+
* 1. 直接调用 API(推荐):
|
|
8
|
+
* import uiConfirm from './UIConfirm';
|
|
9
|
+
*
|
|
10
|
+
* // 简单确认
|
|
11
|
+
* uiConfirm.confirm('确定要删除吗?').then((confirmed) => {
|
|
12
|
+
* if (confirmed) {
|
|
13
|
+
* // 用户点击了确定
|
|
14
|
+
* } else {
|
|
15
|
+
* // 用户点击了取消
|
|
16
|
+
* }
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // 完整配置
|
|
20
|
+
* uiConfirm.confirm({
|
|
21
|
+
* title: '警告',
|
|
22
|
+
* content: '此操作不可恢复,确定要继续吗?',
|
|
23
|
+
* okText: '继续',
|
|
24
|
+
* cancelText: '取消',
|
|
25
|
+
* okType: 'danger',
|
|
26
|
+
* onOk: async () => {
|
|
27
|
+
* // 执行异步操作
|
|
28
|
+
* await fetch('/api/delete');
|
|
29
|
+
* },
|
|
30
|
+
* onCancel: () => {
|
|
31
|
+
* console.log('用户取消了操作');
|
|
32
|
+
* }
|
|
33
|
+
* }).then((confirmed) => {
|
|
34
|
+
* console.log('操作结果:', confirmed);
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* // 警告对话框
|
|
38
|
+
* uiConfirm.warning('这是一个警告信息');
|
|
39
|
+
*
|
|
40
|
+
* // 信息对话框
|
|
41
|
+
* uiConfirm.info('这是一个提示信息');
|
|
42
|
+
*
|
|
43
|
+
* // 错误对话框
|
|
44
|
+
* uiConfirm.error('操作失败');
|
|
45
|
+
*
|
|
46
|
+
* 特点:
|
|
47
|
+
* - 返回 Promise,可以 await 或使用 then
|
|
48
|
+
* - 支持同步和异步 onOk
|
|
49
|
+
* - 自定义按钮文字和样式
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
import React from 'react';
|
|
53
|
+
import { Modal, Button, Space } from 'antd';
|
|
54
|
+
import { ExclamationCircleFilled, InfoCircleFilled, QuestionCircleFilled, WarningFilled } from '@ant-design/icons';
|
|
55
|
+
import { createRoot, Root } from 'react-dom/client';
|
|
56
|
+
import type { ButtonProps } from 'antd/es/button';
|
|
57
|
+
import { title } from 'process';
|
|
58
|
+
|
|
59
|
+
// Confirm类型定义
|
|
60
|
+
export type UIConfirmType = 'confirm' | 'warning' | 'info' | 'error';
|
|
61
|
+
|
|
62
|
+
// Confirm选项接口
|
|
63
|
+
export interface UIConfirmOptions {
|
|
64
|
+
type?: UIConfirmType;
|
|
65
|
+
title?: React.ReactNode;
|
|
66
|
+
content?: React.ReactNode;
|
|
67
|
+
width?: number | string;
|
|
68
|
+
centered?: boolean;
|
|
69
|
+
closable?: boolean;
|
|
70
|
+
maskClosable?: boolean;
|
|
71
|
+
okText?: string;
|
|
72
|
+
okType?: ButtonProps['type'];
|
|
73
|
+
cancelText?: string;
|
|
74
|
+
cancelButtonProps?: ButtonProps;
|
|
75
|
+
okButtonProps?: ButtonProps;
|
|
76
|
+
onOk?: () => void | Promise<void>;
|
|
77
|
+
onCancel?: () => void;
|
|
78
|
+
afterClose?: () => void;
|
|
79
|
+
className?: string;
|
|
80
|
+
showIcon?: boolean;
|
|
81
|
+
zIndex?: number;
|
|
82
|
+
keyboard?: boolean; // 是否支持键盘 esc 关闭
|
|
83
|
+
autoFocusButton?: 'ok' | 'cancel' | null; // 自动聚焦按钮
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 默认选项
|
|
87
|
+
const defaultOptions: UIConfirmOptions = {
|
|
88
|
+
type: 'confirm',
|
|
89
|
+
title: '确认',
|
|
90
|
+
content: '',
|
|
91
|
+
width: 420,
|
|
92
|
+
centered: true,
|
|
93
|
+
closable: true,
|
|
94
|
+
maskClosable: false, // 默认点击遮罩层不关闭
|
|
95
|
+
okText: '确定',
|
|
96
|
+
okType: 'primary',
|
|
97
|
+
cancelText: '取消',
|
|
98
|
+
showIcon: false,
|
|
99
|
+
keyboard: true,
|
|
100
|
+
autoFocusButton: 'ok',
|
|
101
|
+
zIndex: 20000,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// 单例管理
|
|
105
|
+
let confirmInstance: HTMLDivElement | null = null;
|
|
106
|
+
let rootInstance: Root | null = null;
|
|
107
|
+
|
|
108
|
+
// Confirm组件
|
|
109
|
+
const ConfirmComponent: React.FC<UIConfirmOptions & { open: boolean; onClose: (confirmed: boolean) => void }> = (props) => {
|
|
110
|
+
const {
|
|
111
|
+
type = 'confirm',
|
|
112
|
+
title,
|
|
113
|
+
content,
|
|
114
|
+
width,
|
|
115
|
+
centered,
|
|
116
|
+
closable,
|
|
117
|
+
maskClosable,
|
|
118
|
+
okText,
|
|
119
|
+
okType,
|
|
120
|
+
cancelText,
|
|
121
|
+
okButtonProps,
|
|
122
|
+
cancelButtonProps,
|
|
123
|
+
onOk,
|
|
124
|
+
onCancel,
|
|
125
|
+
open,
|
|
126
|
+
onClose,
|
|
127
|
+
className,
|
|
128
|
+
showIcon,
|
|
129
|
+
zIndex,
|
|
130
|
+
keyboard,
|
|
131
|
+
autoFocusButton
|
|
132
|
+
} = props;
|
|
133
|
+
|
|
134
|
+
// 图标映射
|
|
135
|
+
const iconMap = {
|
|
136
|
+
confirm: <QuestionCircleFilled style={{ color: '#1677ff', fontSize: 22, marginRight: 12 }} />,
|
|
137
|
+
warning: <ExclamationCircleFilled style={{ color: '#faad14', fontSize: 22, marginRight: 12 }} />,
|
|
138
|
+
info: <InfoCircleFilled style={{ color: '#1677ff', fontSize: 22, marginRight: 12 }} />,
|
|
139
|
+
error: <WarningFilled style={{ color: '#ff4d4f', fontSize: 22, marginRight: 12 }} />
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// 处理确定按钮点击
|
|
143
|
+
const handleOk = async () => {
|
|
144
|
+
try {
|
|
145
|
+
if (onOk) {
|
|
146
|
+
const result = onOk();
|
|
147
|
+
if (result instanceof Promise) {
|
|
148
|
+
await result;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
onClose(true);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.error('Confirm onOk error:', error);
|
|
154
|
+
// 错误时不关闭对话框
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// 处理取消按钮点击
|
|
159
|
+
const handleCancel = () => {
|
|
160
|
+
if (onCancel) {
|
|
161
|
+
onCancel();
|
|
162
|
+
}
|
|
163
|
+
onClose(false);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// 渲染标题
|
|
167
|
+
const renderTitle = () => {
|
|
168
|
+
if (!title) return null;
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<div style={{ display: 'flex', alignItems: 'center' }}>
|
|
172
|
+
{showIcon && iconMap[type]}
|
|
173
|
+
<span>{title}</span>
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<Modal
|
|
180
|
+
title={renderTitle()}
|
|
181
|
+
open={open}
|
|
182
|
+
width={width}
|
|
183
|
+
centered={centered}
|
|
184
|
+
closable={closable}
|
|
185
|
+
maskClosable={maskClosable}
|
|
186
|
+
onCancel={handleCancel}
|
|
187
|
+
className={className ? className + ' ant-modal-nofull' : 'ant-modal-nofull'}
|
|
188
|
+
zIndex={zIndex}
|
|
189
|
+
keyboard={keyboard}
|
|
190
|
+
footer={(
|
|
191
|
+
<Space>
|
|
192
|
+
<Button
|
|
193
|
+
onClick={handleCancel}
|
|
194
|
+
{...cancelButtonProps}
|
|
195
|
+
autoFocus={autoFocusButton === 'cancel'}
|
|
196
|
+
>
|
|
197
|
+
{cancelText}
|
|
198
|
+
</Button>
|
|
199
|
+
<Button
|
|
200
|
+
type={okType}
|
|
201
|
+
onClick={handleOk}
|
|
202
|
+
{...okButtonProps}
|
|
203
|
+
autoFocus={autoFocusButton === 'ok'}
|
|
204
|
+
>
|
|
205
|
+
{okText}
|
|
206
|
+
</Button>
|
|
207
|
+
</Space>
|
|
208
|
+
)}
|
|
209
|
+
>
|
|
210
|
+
<div style={{ marginLeft: showIcon ? 34 : 0 }}>
|
|
211
|
+
{content}
|
|
212
|
+
</div>
|
|
213
|
+
</Modal>
|
|
214
|
+
);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// 创建Confirm实例,返回Promise
|
|
218
|
+
const createConfirmInstance = (options: UIConfirmOptions): Promise<boolean> => {
|
|
219
|
+
// 合并选项
|
|
220
|
+
const mergedOptions = { ...defaultOptions, ...options };
|
|
221
|
+
|
|
222
|
+
// 关闭已存在的实例
|
|
223
|
+
if (confirmInstance && rootInstance) {
|
|
224
|
+
rootInstance.unmount();
|
|
225
|
+
document.body.removeChild(confirmInstance);
|
|
226
|
+
confirmInstance = null;
|
|
227
|
+
rootInstance = null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// 返回Promise
|
|
231
|
+
return new Promise((resolve) => {
|
|
232
|
+
// 关闭Confirm的方法
|
|
233
|
+
const closeConfirm = (confirmed: boolean) => {
|
|
234
|
+
if (confirmInstance && rootInstance) {
|
|
235
|
+
rootInstance.render(
|
|
236
|
+
<ConfirmComponent
|
|
237
|
+
{...mergedOptions}
|
|
238
|
+
open={false}
|
|
239
|
+
onClose={(confirmed) => {
|
|
240
|
+
if (mergedOptions.afterClose) {
|
|
241
|
+
mergedOptions.afterClose();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
setTimeout(() => {
|
|
245
|
+
if (confirmInstance && rootInstance) {
|
|
246
|
+
rootInstance.unmount();
|
|
247
|
+
document.body.removeChild(confirmInstance);
|
|
248
|
+
confirmInstance = null;
|
|
249
|
+
rootInstance = null;
|
|
250
|
+
}
|
|
251
|
+
resolve(confirmed);
|
|
252
|
+
}, 300); // 等待动画结束
|
|
253
|
+
}}
|
|
254
|
+
/>
|
|
255
|
+
);
|
|
256
|
+
resolve(confirmed);
|
|
257
|
+
} else {
|
|
258
|
+
resolve(confirmed);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// 创建新实例
|
|
263
|
+
confirmInstance = document.createElement('div');
|
|
264
|
+
document.body.appendChild(confirmInstance);
|
|
265
|
+
rootInstance = createRoot(confirmInstance);
|
|
266
|
+
rootInstance.render(
|
|
267
|
+
<ConfirmComponent
|
|
268
|
+
{...mergedOptions}
|
|
269
|
+
open={true}
|
|
270
|
+
onClose={closeConfirm}
|
|
271
|
+
/>
|
|
272
|
+
);
|
|
273
|
+
});
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// 全局Confirm API
|
|
277
|
+
const uiConfirm = {
|
|
278
|
+
// 基本确认对话框
|
|
279
|
+
confirm: (options: string | UIConfirmOptions): Promise<boolean> => {
|
|
280
|
+
const config = typeof options === 'string'
|
|
281
|
+
? { content: options, showIcon: false, title: '' }
|
|
282
|
+
: options;
|
|
283
|
+
|
|
284
|
+
return createConfirmInstance({
|
|
285
|
+
...config,
|
|
286
|
+
type: 'confirm',
|
|
287
|
+
});
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
// 警告确认对话框
|
|
291
|
+
warning: (options: string | UIConfirmOptions): Promise<boolean> => {
|
|
292
|
+
const config = typeof options === 'string'
|
|
293
|
+
? { content: options }
|
|
294
|
+
: options;
|
|
295
|
+
|
|
296
|
+
return createConfirmInstance({
|
|
297
|
+
...config,
|
|
298
|
+
type: 'warning',
|
|
299
|
+
title: config.title || '警告',
|
|
300
|
+
});
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
// 信息确认对话框
|
|
304
|
+
info: (options: string | UIConfirmOptions): Promise<boolean> => {
|
|
305
|
+
const config = typeof options === 'string'
|
|
306
|
+
? { content: options }
|
|
307
|
+
: options;
|
|
308
|
+
|
|
309
|
+
return createConfirmInstance({
|
|
310
|
+
...config,
|
|
311
|
+
type: 'info',
|
|
312
|
+
title: config.title || '信息',
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
// 错误确认对话框
|
|
317
|
+
error: (options: string | UIConfirmOptions): Promise<boolean> => {
|
|
318
|
+
const config = typeof options === 'string'
|
|
319
|
+
? { content: options }
|
|
320
|
+
: options;
|
|
321
|
+
|
|
322
|
+
return createConfirmInstance({
|
|
323
|
+
...config,
|
|
324
|
+
type: 'error',
|
|
325
|
+
title: config.title || '错误',
|
|
326
|
+
});
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
// 自定义确认对话框
|
|
330
|
+
custom: (options: UIConfirmOptions): Promise<boolean> => {
|
|
331
|
+
return createConfirmInstance(options);
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
export default uiConfirm;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Button, Space, Card, Divider, message } from 'antd';
|
|
3
|
+
import uiConfirm from './UIConfirm';
|
|
4
|
+
|
|
5
|
+
const ConfirmExample: React.FC = () => {
|
|
6
|
+
const [result, setResult] = useState<string>('未操作');
|
|
7
|
+
|
|
8
|
+
// 基本确认对话框
|
|
9
|
+
const showBasicConfirm = async () => {
|
|
10
|
+
const confirmed = await uiConfirm.confirm('您确定要执行此操作吗?');
|
|
11
|
+
setResult(confirmed ? '用户点击了确定' : '用户点击了取消');
|
|
12
|
+
|
|
13
|
+
if (confirmed) {
|
|
14
|
+
message.success('操作已确认');
|
|
15
|
+
} else {
|
|
16
|
+
message.info('操作已取消');
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// 警告确认对话框
|
|
21
|
+
const showWarningConfirm = async () => {
|
|
22
|
+
const confirmed = await uiConfirm.warning({
|
|
23
|
+
title: '删除警告',
|
|
24
|
+
content: '此操作将永久删除所选数据,确定要继续吗?',
|
|
25
|
+
okText: '删除',
|
|
26
|
+
okType: 'primary',
|
|
27
|
+
okButtonProps: { danger: true },
|
|
28
|
+
cancelText: '取消',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
setResult(confirmed ? '用户确认删除' : '用户取消删除');
|
|
32
|
+
|
|
33
|
+
if (confirmed) {
|
|
34
|
+
message.success('数据已删除');
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// 信息确认对话框
|
|
39
|
+
const showInfoConfirm = async () => {
|
|
40
|
+
const confirmed = await uiConfirm.info({
|
|
41
|
+
title: '保存提醒',
|
|
42
|
+
content: '您有未保存的更改,是否保存后继续?',
|
|
43
|
+
okText: '保存',
|
|
44
|
+
cancelText: '不保存',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
setResult(confirmed ? '用户选择保存' : '用户选择不保存');
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// 错误确认对话框
|
|
51
|
+
const showErrorConfirm = async () => {
|
|
52
|
+
const confirmed = await uiConfirm.error({
|
|
53
|
+
title: '连接错误',
|
|
54
|
+
content: '服务器连接失败,是否重新尝试连接?',
|
|
55
|
+
okText: '重试',
|
|
56
|
+
cancelText: '取消',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
setResult(confirmed ? '用户选择重试' : '用户选择取消');
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// 带有异步操作的确认对话框
|
|
63
|
+
const showAsyncConfirm = async () => {
|
|
64
|
+
const confirmed = await uiConfirm.confirm({
|
|
65
|
+
title: '异步操作确认',
|
|
66
|
+
content: '确认后将执行一个异步操作(模拟3秒)',
|
|
67
|
+
onOk: async () => {
|
|
68
|
+
// 返回Promise将会阻止对话框关闭,直到Promise完成
|
|
69
|
+
return new Promise<void>((resolve) => {
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
resolve();
|
|
72
|
+
}, 3000);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
setResult(confirmed ? '异步操作完成并确认' : '用户取消操作');
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// 自定义焦点的确认对话框
|
|
81
|
+
const showFocusConfirm = async () => {
|
|
82
|
+
const confirmed = await uiConfirm.custom({
|
|
83
|
+
type: 'warning',
|
|
84
|
+
title: '危险操作',
|
|
85
|
+
content: '此操作有风险,默认焦点设置在取消按钮上',
|
|
86
|
+
autoFocusButton: 'cancel', // 自动聚焦到取消按钮
|
|
87
|
+
okType: 'primary',
|
|
88
|
+
okButtonProps: { danger: true },
|
|
89
|
+
cancelButtonProps: { type: 'primary' },
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
setResult(confirmed ? '用户确认风险操作' : '用户取消风险操作');
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// 自定义宽度的确认对话框
|
|
96
|
+
const showWideConfirm = async () => {
|
|
97
|
+
const confirmed = await uiConfirm.custom({
|
|
98
|
+
type: 'info',
|
|
99
|
+
title: '详细信息确认',
|
|
100
|
+
content: (
|
|
101
|
+
<div>
|
|
102
|
+
<p>请查看以下详细信息,并确认是否继续:</p>
|
|
103
|
+
<ul>
|
|
104
|
+
<li>项目名称:示例项目</li>
|
|
105
|
+
<li>创建时间:2023-06-15</li>
|
|
106
|
+
<li>项目状态:待审核</li>
|
|
107
|
+
<li>提交人:管理员</li>
|
|
108
|
+
<li>备注:这是一个展示宽对话框的示例</li>
|
|
109
|
+
</ul>
|
|
110
|
+
<p>确认后将自动提交审核。</p>
|
|
111
|
+
</div>
|
|
112
|
+
),
|
|
113
|
+
width: 600,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
setResult(confirmed ? '用户确认提交' : '用户取消提交');
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<Card title="Confirm 确认对话框示例" style={{ width: '100%', maxWidth: 600, margin: '20px auto' }}>
|
|
121
|
+
<Space direction="vertical" style={{ width: '100%' }}>
|
|
122
|
+
<div style={{ marginBottom: 16 }}>
|
|
123
|
+
<h3>操作结果:</h3>
|
|
124
|
+
<div style={{ background: '#f0f0f0', padding: 10, borderRadius: 4 }}>
|
|
125
|
+
{result}
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<Divider>基本用法</Divider>
|
|
130
|
+
|
|
131
|
+
<Button type="primary" block onClick={showBasicConfirm}>
|
|
132
|
+
基本确认对话框
|
|
133
|
+
</Button>
|
|
134
|
+
|
|
135
|
+
<Button danger block onClick={showWarningConfirm}>
|
|
136
|
+
警告确认对话框
|
|
137
|
+
</Button>
|
|
138
|
+
|
|
139
|
+
<Button type="dashed" block onClick={showInfoConfirm}>
|
|
140
|
+
信息确认对话框
|
|
141
|
+
</Button>
|
|
142
|
+
|
|
143
|
+
<Button type="default" block onClick={showErrorConfirm}>
|
|
144
|
+
错误确认对话框
|
|
145
|
+
</Button>
|
|
146
|
+
|
|
147
|
+
<Divider>高级用法</Divider>
|
|
148
|
+
|
|
149
|
+
<Button type="primary" ghost block onClick={showAsyncConfirm}>
|
|
150
|
+
异步操作确认对话框
|
|
151
|
+
</Button>
|
|
152
|
+
|
|
153
|
+
<Button block onClick={showFocusConfirm}>
|
|
154
|
+
自定义焦点确认对话框
|
|
155
|
+
</Button>
|
|
156
|
+
|
|
157
|
+
<Button type="default" block onClick={showWideConfirm}>
|
|
158
|
+
自定义宽度确认对话框
|
|
159
|
+
</Button>
|
|
160
|
+
</Space>
|
|
161
|
+
</Card>
|
|
162
|
+
);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export default ConfirmExample;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
2
|
+
import { Calendar, ChevronLeft, ChevronRight } from 'lucide-react';
|
|
3
|
+
import { Button } from 'antd';
|
|
4
|
+
|
|
5
|
+
interface UIDatePickerProps {
|
|
6
|
+
value: string;
|
|
7
|
+
onChange: (value: string) => void;
|
|
8
|
+
type?: 'date' | 'month';
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function UIDatePicker({
|
|
14
|
+
value,
|
|
15
|
+
onChange,
|
|
16
|
+
type = 'date',
|
|
17
|
+
placeholder = '选择日期',
|
|
18
|
+
className = ''
|
|
19
|
+
}: UIDatePickerProps) {
|
|
20
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
21
|
+
const datePickerRef = useRef<HTMLDivElement>(null);
|
|
22
|
+
|
|
23
|
+
const formattedValue = value ? formatDisplayDate(value, type) : '';
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
function handleClickOutside(event: MouseEvent) {
|
|
27
|
+
if (datePickerRef.current && !datePickerRef.current.contains(event.target as Node)) {
|
|
28
|
+
setIsOpen(false);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
33
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
function formatDisplayDate(dateString: string, type: 'date' | 'month'): string {
|
|
37
|
+
if (!dateString) return '';
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
if (type === 'month') {
|
|
41
|
+
const [year, month] = dateString.split('-');
|
|
42
|
+
return `${year}年${month}月`;
|
|
43
|
+
} else {
|
|
44
|
+
const date = new Date(dateString);
|
|
45
|
+
return date.toLocaleDateString('zh-CN', {
|
|
46
|
+
year: 'numeric',
|
|
47
|
+
month: 'long',
|
|
48
|
+
day: 'numeric'
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
} catch (e) {
|
|
52
|
+
return dateString;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Handle direct input change
|
|
57
|
+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
58
|
+
onChange(e.target.value);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Handle click on input to open the custom date picker
|
|
62
|
+
const handleInputClick = () => {
|
|
63
|
+
setIsOpen(!isOpen);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div className={`relative ${className}`} ref={datePickerRef}>
|
|
68
|
+
<div className="relative cursor-pointer">
|
|
69
|
+
<input
|
|
70
|
+
type={type}
|
|
71
|
+
value={value}
|
|
72
|
+
onChange={handleInputChange}
|
|
73
|
+
onClick={handleInputClick}
|
|
74
|
+
className="w-full bg-white border border-ios-gray-200 rounded-ios py-2.5 pl-3 pr-10 text-sm text-ios-gray-700 shadow-ios focus:outline-none focus:ring-2 focus:ring-ios-blue-400 focus:border-transparent transition-all duration-200 hover:border-ios-blue-300 cursor-pointer"
|
|
75
|
+
placeholder={placeholder}
|
|
76
|
+
/>
|
|
77
|
+
<div className="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
|
|
78
|
+
<Calendar className="h-4 w-4 text-ios-gray-400" />
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
{isOpen && (
|
|
83
|
+
<div className="absolute z-10 mt-1 bg-white rounded-ios shadow-ios-md p-4 ring-1 ring-ios-gray-200 ring-opacity-5">
|
|
84
|
+
<div className="flex justify-between items-center mb-4">
|
|
85
|
+
<Button
|
|
86
|
+
type="text"
|
|
87
|
+
className="p-1.5 hover:bg-ios-gray-100 rounded-full transition-colors duration-150"
|
|
88
|
+
icon={<ChevronLeft className="h-4 w-4 text-ios-gray-600" />}
|
|
89
|
+
>
|
|
90
|
+
</Button>
|
|
91
|
+
<span className="text-sm font-medium text-ios-gray-700">2024年5月</span>
|
|
92
|
+
<Button
|
|
93
|
+
type="text"
|
|
94
|
+
className="p-1.5 hover:bg-ios-gray-100 rounded-full transition-colors duration-150"
|
|
95
|
+
icon={<ChevronRight className="h-4 w-4 text-ios-gray-600" />}
|
|
96
|
+
>
|
|
97
|
+
</Button>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div className="grid grid-cols-7 gap-1 text-center text-xs">
|
|
101
|
+
<div className="text-ios-gray-500 font-medium">日</div>
|
|
102
|
+
<div className="text-ios-gray-500 font-medium">一</div>
|
|
103
|
+
<div className="text-ios-gray-500 font-medium">二</div>
|
|
104
|
+
<div className="text-ios-gray-500 font-medium">三</div>
|
|
105
|
+
<div className="text-ios-gray-500 font-medium">四</div>
|
|
106
|
+
<div className="text-ios-gray-500 font-medium">五</div>
|
|
107
|
+
<div className="text-ios-gray-500 font-medium">六</div>
|
|
108
|
+
|
|
109
|
+
{/* Empty cells for days from previous month */}
|
|
110
|
+
<div className="text-ios-gray-300 py-1.5">30</div>
|
|
111
|
+
<div className="text-ios-gray-300 py-1.5">31</div>
|
|
112
|
+
|
|
113
|
+
{/* Current month days */}
|
|
114
|
+
{Array.from({ length: 30 }).map((_, i) => (
|
|
115
|
+
<div
|
|
116
|
+
key={i}
|
|
117
|
+
className={`py-1.5 hover:bg-ios-blue-50 rounded-full cursor-pointer transition-colors duration-150 ${
|
|
118
|
+
i === 14 ? 'bg-ios-blue-500 text-white' : 'text-ios-gray-700'
|
|
119
|
+
}`}
|
|
120
|
+
onClick={() => {
|
|
121
|
+
// In a real implementation, this would set the actual date
|
|
122
|
+
const day = i + 1;
|
|
123
|
+
const dateStr = `2024-05-${day < 10 ? '0' + day : day}`;
|
|
124
|
+
onChange(dateStr);
|
|
125
|
+
setIsOpen(false);
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
{i + 1}
|
|
129
|
+
</div>
|
|
130
|
+
))}
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div className="mt-4 flex justify-end">
|
|
134
|
+
<Button
|
|
135
|
+
type="text"
|
|
136
|
+
className="px-4 py-1.5 text-sm text-ios-blue-500 hover:bg-ios-blue-50 rounded-ios transition-colors duration-150"
|
|
137
|
+
onClick={() => setIsOpen(false)}
|
|
138
|
+
>
|
|
139
|
+
确定
|
|
140
|
+
</Button>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
)}
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { UIDatePicker } from './UIDatePicker';
|
|
3
|
+
|
|
4
|
+
interface UIDateRangePickerProps {
|
|
5
|
+
startDate: string;
|
|
6
|
+
endDate: string;
|
|
7
|
+
onStartDateChange: (date: string) => void;
|
|
8
|
+
onEndDateChange: (date: string) => void;
|
|
9
|
+
type?: 'date' | 'month';
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function UIDateRangePicker({
|
|
14
|
+
startDate,
|
|
15
|
+
endDate,
|
|
16
|
+
onStartDateChange,
|
|
17
|
+
onEndDateChange,
|
|
18
|
+
type = 'date',
|
|
19
|
+
className = ''
|
|
20
|
+
}: UIDateRangePickerProps) {
|
|
21
|
+
return (
|
|
22
|
+
<div className={`flex items-center space-x-2 ${className}`}>
|
|
23
|
+
<UIDatePicker
|
|
24
|
+
value={startDate}
|
|
25
|
+
onChange={onStartDateChange}
|
|
26
|
+
type={type}
|
|
27
|
+
placeholder="开始日期"
|
|
28
|
+
/>
|
|
29
|
+
<span className="text-gray-500">至</span>
|
|
30
|
+
<UIDatePicker
|
|
31
|
+
value={endDate}
|
|
32
|
+
onChange={onEndDateChange}
|
|
33
|
+
type={type}
|
|
34
|
+
placeholder="结束日期"
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|