From baf8c53a9d798861451a68620cdb946083d5c8a1 Mon Sep 17 00:00:00 2001
From: luxiaotao1123 <t1341870251@163.com>
Date: 星期四, 19 九月 2024 10:31:04 +0800
Subject: [PATCH] #
---
zy-acs-flow/src/page/components/ImportModal.jsx | 21 +++----
zy-acs-flow/package.json | 1
zy-acs-flow/src/page/code/useCodeImport.jsx | 14 ++++
zy-acs-flow/package-lock.json | 6 ++
zy-acs-flow/src/page/code/importTemp.csv | 4 +
zy-acs-flow/src/page/components/usePapaParse.jsx | 103 ++++++++++++++++++++++++++++++++++
zy-acs-flow/src/page/code/CodeList.jsx | 7 +
zy-acs-flow/src/page/components/ImportButton.jsx | 8 +-
8 files changed, 146 insertions(+), 18 deletions(-)
diff --git a/zy-acs-flow/package-lock.json b/zy-acs-flow/package-lock.json
index 1b7cb5d..ac0b674 100644
--- a/zy-acs-flow/package-lock.json
+++ b/zy-acs-flow/package-lock.json
@@ -12,6 +12,7 @@
"@mui/x-tree-view": "^7.16.0",
"axios": "^1.7.4",
"date-fns": "^3.6.0",
+ "papaparse": "^5.4.1",
"pixi.js": "^7.4.0",
"react": "^18.3.0",
"react-admin": "^5.1.0",
@@ -4818,6 +4819,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/papaparse": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmmirror.com/papaparse/-/papaparse-5.4.1.tgz",
+ "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw=="
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz",
diff --git a/zy-acs-flow/package.json b/zy-acs-flow/package.json
index 67a49cf..4d0229e 100644
--- a/zy-acs-flow/package.json
+++ b/zy-acs-flow/package.json
@@ -17,6 +17,7 @@
"axios": "^1.7.4",
"date-fns": "^3.6.0",
"pixi.js": "^7.4.0",
+ "papaparse": "^5.4.1",
"react": "^18.3.0",
"react-admin": "^5.1.0",
"react-dom": "^18.3.0",
diff --git a/zy-acs-flow/src/page/code/CodeList.jsx b/zy-acs-flow/src/page/code/CodeList.jsx
index 2187341..30f4095 100644
--- a/zy-acs-flow/src/page/code/CodeList.jsx
+++ b/zy-acs-flow/src/page/code/CodeList.jsx
@@ -42,7 +42,10 @@
import MyField from "../components/MyField";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE } from '@/config/setting';
import * as Common from '@/utils/common';
-import { ImportButton } from './ImportButton'
+import { ImportButton } from '../components/ImportButton'
+import { useCodeImport } from './useCodeImport';
+
+import * as sampleCsv from './importTemp.csv?raw';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
'& .css-1vooibu-MuiSvgIcon-root': {
@@ -112,7 +115,7 @@
<FilterButton />
<MyCreateButton onClick={() => { setCreateDialog(true) }} />
<SelectColumnsButton preferenceKey='code' />
- <ImportButton />
+ <ImportButton sampleCsv={sampleCsv} useCodeImport={useCodeImport} />
<MyExportButton />
</TopToolbar>
)}
diff --git a/zy-acs-flow/src/page/code/importTemp.csv b/zy-acs-flow/src/page/code/importTemp.csv
new file mode 100644
index 0000000..9fccf29
--- /dev/null
+++ b/zy-acs-flow/src/page/code/importTemp.csv
@@ -0,0 +1,4 @@
+first_name,last_name,gender,title,company,email,phone_1_number,phone_1_type,phone_2_number,phone_2_type,background,first_seen,last_seen,has_newsletter,status,tags,linkedin_url
+John,Doe,male,Sales Executive,Acme,john@doe.example,659-980-2015,work,740.645.3807,home,,2024-07-01,2024-07-01T11:54:49.950Z,FALSE,in-contract,"influencer, developer",https://www.linkedin.com/in/johndoe
+Jane,Doe,female,Designer,Acme,jane@doe.example,659-980-2020,work,740.647.3802,home,,2024-07-01,2024-07-01T11:54:49.950Z,FALSE,in-contract,"UI, design",https://www.linkedin.com/in/janedoe
+Camille,Brown,nonbinary,Accountant,Atomic Corp,person@doe.example,659-910-3010,work,740.698.3752,home,,2024-07-01,2024-07-01T11:54:49.950Z,FALSE,in-contract,"payroll, accountant",,
\ No newline at end of file
diff --git a/zy-acs-flow/src/page/code/useCodeImport.jsx b/zy-acs-flow/src/page/code/useCodeImport.jsx
new file mode 100644
index 0000000..b53286c
--- /dev/null
+++ b/zy-acs-flow/src/page/code/useCodeImport.jsx
@@ -0,0 +1,14 @@
+import { useCallback, useMemo } from 'react';
+import { useDataProvider, useGetIdentity } from 'react-admin';
+
+export function useCodeImport() {
+
+ const processBatch = useCallback(async (batch) => {
+ console.log(batch);
+
+ }, []);
+
+ return {
+ processBatch,
+ };
+}
diff --git a/zy-acs-flow/src/page/code/ImportButton.jsx b/zy-acs-flow/src/page/components/ImportButton.jsx
similarity index 75%
rename from zy-acs-flow/src/page/code/ImportButton.jsx
rename to zy-acs-flow/src/page/components/ImportButton.jsx
index e23c474..cf21f69 100644
--- a/zy-acs-flow/src/page/code/ImportButton.jsx
+++ b/zy-acs-flow/src/page/components/ImportButton.jsx
@@ -1,9 +1,9 @@
import UploadIcon from '@mui/icons-material/Upload';
import { useState } from 'react';
import { Button } from 'react-admin';
-// import { ImportModal } from './ImportModal';
+import { ImportModal } from './ImportModal';
-export const ImportButton = () => {
+export const ImportButton = (props) => {
const [modalOpen, setModalOpen] = useState(false);
const handleOpenModal = () => {
@@ -13,7 +13,7 @@
const handleCloseModal = () => {
setModalOpen(false);
};
-
+
return (
<>
<Button
@@ -22,7 +22,7 @@
onClick={handleOpenModal}
/>
- {/* <ImportModal open={modalOpen} onClose={handleCloseModal} /> */}
+ <ImportModal open={modalOpen} onClose={handleCloseModal} {...props} />
</>
);
};
diff --git a/zy-acs-flow/src/page/code/ImportModal.jsx b/zy-acs-flow/src/page/components/ImportModal.jsx
similarity index 92%
rename from zy-acs-flow/src/page/code/ImportModal.jsx
rename to zy-acs-flow/src/page/components/ImportModal.jsx
index bab07e9..309ee86 100644
--- a/zy-acs-flow/src/page/code/ImportModal.jsx
+++ b/zy-acs-flow/src/page/components/ImportModal.jsx
@@ -1,3 +1,4 @@
+import { useEffect, useState } from 'react';
import { Box, CircularProgress, Stack, Typography } from '@mui/material';
import Alert from '@mui/material/Alert';
import Dialog from '@mui/material/Dialog';
@@ -14,20 +15,16 @@
useRefresh,
} from 'react-admin';
import { Link } from 'react-router-dom';
-import { DialogCloseButton } from '../misc/DialogCloseButton';
-import { usePapaParse } from '../misc/usePapaParse';
-import { ContactImportSchema, useContactImport } from './useContactImport';
+import DialogCloseButton from './DialogCloseButton';
+import { usePapaParse } from './usePapaParse';
-import { MouseEvent, useEffect, useState } from 'react';
-import * as sampleCsv from './contacts_export.csv?raw';
-
-const SAMPLE_URL = `data:text/csv;name=crm_contacts_sample.csv;charset=utf-8,${encodeURIComponent(sampleCsv.default)}`;
-
-
-export function ImportModal({ open, onClose }) {
+export function ImportModal({ open, onClose, sampleCsv, useCodeImport }) {
const refresh = useRefresh();
- const { processBatch } = useContactImport();
- const { importer, parseCsv, reset } = usePapaParse<ContactImportSchema>({
+
+ const SAMPLE_URL = `data:text/csv;name=crm_contacts_sample.csv;charset=utf-8,${encodeURIComponent(sampleCsv.default)}`;
+
+ const { processBatch } = useCodeImport();
+ const { importer, parseCsv, reset } = usePapaParse({
batchSize: 10,
processBatch,
});
diff --git a/zy-acs-flow/src/page/components/usePapaParse.jsx b/zy-acs-flow/src/page/components/usePapaParse.jsx
new file mode 100644
index 0000000..a38c68e
--- /dev/null
+++ b/zy-acs-flow/src/page/components/usePapaParse.jsx
@@ -0,0 +1,103 @@
+import * as Papa from 'papaparse';
+import { useCallback, useMemo, useRef, useState } from 'react';
+
+export function usePapaParse({ batchSize = 10, processBatch }) {
+ const importIdRef = useRef(0);
+
+ const [importer, setImporter] = useState({
+ state: 'idle',
+ });
+
+ const reset = useCallback(() => {
+ setImporter({
+ state: 'idle',
+ });
+ importIdRef.current += 1;
+ }, []);
+
+ const parseCsv = useCallback((file) => {
+ setImporter({
+ state: 'parsing',
+ });
+
+ const importId = importIdRef.current;
+ Papa.parse(file, {
+ header: true,
+ skipEmptyLines: true,
+ async complete(results) {
+ if (importIdRef.current !== importId) {
+ return;
+ }
+
+ setImporter({
+ state: 'running',
+ rowCount: results.data.length,
+ errorCount: results.errors.length,
+ importCount: 0,
+ remainingTime: null,
+ });
+
+ let totalTime = 0;
+ for (let i = 0; i < results.data.length; i += batchSize) {
+ if (importIdRef.current !== importId) {
+ return;
+ }
+
+ const batch = results.data.slice(i, i + batchSize);
+ try {
+ const start = Date.now();
+ await processBatch(batch);
+ totalTime += Date.now() - start;
+
+ const meanTime = totalTime / (i + batch.length);
+ setImporter(previous => {
+ if (previous.state === 'running') {
+ const importCount =
+ previous.importCount + batch.length;
+ return {
+ ...previous,
+ importCount,
+ remainingTime:
+ meanTime *
+ (results.data.length - importCount),
+ };
+ }
+ return previous;
+ });
+ } catch (error) {
+ console.error('Failed to import batch', error);
+ setImporter(previous =>
+ previous.state === 'running'
+ ? {
+ ...previous,
+ errorCount:
+ previous.errorCount +
+ batch.length,
+ }
+ : previous
+ );
+ }
+ }
+
+ setImporter(previous =>
+ previous.state === 'running'
+ ? {
+ ...previous,
+ state: 'complete',
+ remainingTime: null,
+ }
+ : previous
+ );
+ },
+ error(error) {
+ setImporter({
+ state: 'error',
+ error,
+ });
+ },
+ dynamicTyping: true,
+ });
+ }, [batchSize, processBatch]);
+
+ return useMemo(() => ({ importer, parseCsv, reset, }), [importer, parseCsv, reset]);
+}
--
Gitblit v1.9.1