- Extract MultiCopyPopupContext to standalone context.ts file - Add Task type and improve type safety in BatchCloneModal - Use useRef/useCallback to stabilize batch clone handlers - Add cleanup effect for selectRules in RuleCheckCard on unmount Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
303 lines
9.8 KiB
TypeScript
303 lines
9.8 KiB
TypeScript
import {
|
|
type ProFormInstance,
|
|
StepsForm,
|
|
useBreakpoint,
|
|
} from '@ant-design/pro-components';
|
|
import { Button, Divider, Flex, Input, Modal, Space, Typography } from 'antd';
|
|
import { useMemo, useRef, useState } from 'react';
|
|
import useRichFormat from '@/hooks/useRichI18n';
|
|
import { $t } from '@/utils/i18n';
|
|
import '../style.less';
|
|
import { flushSync } from 'react-dom';
|
|
import { type SchemaType, schemaMap } from '../../ruleFormSchema';
|
|
import { handleEmptyValuesFunc } from '../../utils';
|
|
import BatchCloneModal from './comp/BatchCloneModal';
|
|
import Step1 from './comp/Step1';
|
|
import Step2 from './comp/Step2';
|
|
import { MultiCopyPopupContext } from './context';
|
|
|
|
const { Text, Title } = Typography;
|
|
type MultiCopyPopupProps = {
|
|
visible: boolean;
|
|
ruleMeta: Record<string, any>;
|
|
dataSourceList: API.DataSourceListItem[];
|
|
currentRuleType: number;
|
|
onDone: (refresh?: boolean) => void;
|
|
};
|
|
|
|
const MultiCopyPopup = ({
|
|
visible,
|
|
ruleMeta,
|
|
onDone,
|
|
currentRuleType,
|
|
dataSourceList,
|
|
}: MultiCopyPopupProps) => {
|
|
const { richFormat } = useRichFormat();
|
|
const screens = useBreakpoint();
|
|
|
|
const currentSchemaMap =
|
|
schemaMap[currentRuleType as unknown as SchemaType]?.({ richFormat }) || {};
|
|
const formMapRef = useRef<
|
|
React.RefObject<ProFormInstance<any> | undefined>[]
|
|
>([]);
|
|
const [targetDataSourceId, setTargetDataSourceId] = useState<
|
|
string | number | null
|
|
>(null);
|
|
const [selectRules, setSelectRules] = useState<API.RuleListItem[]>([]);
|
|
const [checkedIdsList, setCheckedIdsList] = useState<Array<string | number>>(
|
|
[],
|
|
);
|
|
const [inputValue, setInputValue] = useState('');
|
|
const [batchCloneModalVisible, setBatchCloneModalVisible] = useState(false);
|
|
const [selectedRows, setSelectedRows] = useState<Partial<API.RuleListItem>[]>(
|
|
[],
|
|
);
|
|
|
|
const submitRuleList = useMemo(() => {
|
|
return selectRules.filter((item) => checkedIdsList.includes(item.id));
|
|
}, [selectRules, checkedIdsList]);
|
|
|
|
const targetDataSource = useMemo(() => {
|
|
return dataSourceList.find((item) => item.id === targetDataSourceId);
|
|
}, [targetDataSourceId, dataSourceList]);
|
|
|
|
const handleCancel = () => {
|
|
setBatchCloneModalVisible(false);
|
|
setSelectedRows([]);
|
|
setSelectRules([]);
|
|
setCheckedIdsList([]);
|
|
setInputValue('');
|
|
setTargetDataSourceId(null);
|
|
};
|
|
|
|
return (
|
|
<Modal
|
|
width={['xl', 'xxl'].includes(screens || '') ? '50%' : '95%'}
|
|
open={visible}
|
|
centered
|
|
destroyOnHidden
|
|
onCancel={() => {
|
|
handleCancel();
|
|
onDone();
|
|
}}
|
|
title={$t('pages.clones.title')}
|
|
footer={null}
|
|
maskClosable={false}
|
|
styles={{
|
|
body: {
|
|
maxHeight: '90vh',
|
|
overflowY: 'auto',
|
|
overflowX: 'hidden',
|
|
marginRight: -10,
|
|
paddingRight: 8,
|
|
},
|
|
}}
|
|
>
|
|
<MultiCopyPopupContext.Provider
|
|
value={{
|
|
ruleMeta,
|
|
dataSourceList,
|
|
currentRuleType,
|
|
targetDataSourceId,
|
|
selectRules,
|
|
setSelectRules,
|
|
currentSchemaMap,
|
|
}}
|
|
>
|
|
<StepsForm
|
|
formMapRef={formMapRef}
|
|
onFinish={async (values) => {
|
|
const editNameRules = values?.step2 || {};
|
|
|
|
const submitValues = submitRuleList.map((item) => {
|
|
const tmpValues = handleEmptyValuesFunc(item);
|
|
const tmpValues2 =
|
|
currentSchemaMap?.transformSubmitValue?.(tmpValues) ||
|
|
tmpValues;
|
|
const submitValues = {
|
|
...tmpValues2,
|
|
dataSourceId: targetDataSourceId,
|
|
name:
|
|
editNameRules[item.id] ||
|
|
`${item.name || ruleMeta?.title || ''} - ${targetDataSource?.sourceName || ''}`,
|
|
id: void 0,
|
|
groupFilter: '',
|
|
};
|
|
|
|
if (currentSchemaMap?.symbolFormShow) {
|
|
submitValues.param2 = '';
|
|
}
|
|
if (currentSchemaMap?.assetFormShow) {
|
|
submitValues.param1 = '';
|
|
}
|
|
|
|
const tmp: Record<string, any> = {
|
|
companyId: submitValues.companyId,
|
|
dataSourceId: submitValues.dataSourceId,
|
|
groupFilter: submitValues.groupFilter,
|
|
name: submitValues.name,
|
|
type: submitValues.type,
|
|
};
|
|
for (const key in submitValues) {
|
|
if (key.indexOf('param') !== -1) {
|
|
tmp[key] = submitValues[key];
|
|
}
|
|
}
|
|
return tmp;
|
|
});
|
|
|
|
setSelectedRows(submitValues);
|
|
setBatchCloneModalVisible(true);
|
|
}}
|
|
submitter={{
|
|
render: (props) => {
|
|
if (props.step === 0) {
|
|
return [
|
|
<Button key="cancel" onClick={() => onDone()}>
|
|
{$t('pages.model.cancel')}
|
|
</Button>,
|
|
<Button
|
|
disabled={selectRules.length === 0}
|
|
key="goToTree"
|
|
type="primary"
|
|
onClick={() => props.onSubmit?.()}
|
|
>
|
|
{$t('pages.clones.step1.confirm')}
|
|
</Button>,
|
|
];
|
|
}
|
|
|
|
if (props.step === 1) {
|
|
return [
|
|
<Button key="pre" onClick={() => props.onPre?.()}>
|
|
← {$t('pages.clones.back')}
|
|
</Button>,
|
|
<Button
|
|
disabled={checkedIdsList.length === 0}
|
|
type="primary"
|
|
key="goToTree"
|
|
onClick={() => props.onSubmit?.()}
|
|
>
|
|
{$t('pages.clones.step2.confirm')}
|
|
</Button>,
|
|
];
|
|
}
|
|
|
|
return [
|
|
<Button
|
|
key="gotoTwo"
|
|
onClick={() => {
|
|
setInputValue('');
|
|
props.onPre?.();
|
|
}}
|
|
>
|
|
← {$t('pages.clones.backPreview')}
|
|
</Button>,
|
|
<Button
|
|
disabled={
|
|
submitRuleList.length === 0 ||
|
|
inputValue !== targetDataSource?.sourceName
|
|
}
|
|
variant="solid"
|
|
color="danger"
|
|
key="goToTree"
|
|
onClick={() => props.onSubmit?.()}
|
|
>
|
|
{$t('pages.clones.step3.confirm')}
|
|
</Button>,
|
|
];
|
|
},
|
|
}}
|
|
>
|
|
<StepsForm.StepForm
|
|
name="step1"
|
|
title={$t('pages.clones.step1.title')}
|
|
onValuesChange={({ sourceDataSourceId }) => {
|
|
if (sourceDataSourceId) {
|
|
const curFormRef = formMapRef?.current?.[0]?.current;
|
|
const curTargetId = curFormRef?.getFieldValue('targetDataSourceId');
|
|
const sourceItem = dataSourceList.find(
|
|
(item) => item.id === sourceDataSourceId,
|
|
);
|
|
const targetItem = dataSourceList.find(
|
|
(item) => item.id === curTargetId,
|
|
);
|
|
if (targetItem && sourceItem && targetItem.sourceType !== sourceItem.sourceType) {
|
|
const fallback =
|
|
dataSourceList.find(
|
|
(item) =>
|
|
item.id !== sourceDataSourceId &&
|
|
item.sourceType === sourceItem.sourceType,
|
|
)?.id || sourceDataSourceId;
|
|
curFormRef?.setFieldsValue({ targetDataSourceId: fallback });
|
|
setTargetDataSourceId(fallback);
|
|
}
|
|
}
|
|
}}
|
|
>
|
|
<Step1
|
|
formMapRef={formMapRef}
|
|
setTargetDataSourceId={setTargetDataSourceId}
|
|
/>
|
|
</StepsForm.StepForm>
|
|
<StepsForm.StepForm
|
|
name="step2"
|
|
title={$t('pages.clones.step2.title')}
|
|
>
|
|
<Step2 setCheckedIdsList={setCheckedIdsList} />
|
|
</StepsForm.StepForm>
|
|
<StepsForm.StepForm
|
|
name="time"
|
|
title={$t('pages.clones.step3.title')}
|
|
>
|
|
<div className="confirm-container">
|
|
<Flex className="confirm-space" align="center" justify="center">
|
|
<Space direction="vertical" align="center">
|
|
<Title level={5}>
|
|
{$t('pages.clones.step3.confirmTitle', {
|
|
cloneCount: checkedIdsList.length,
|
|
target: targetDataSource?.sourceName || '',
|
|
})}
|
|
</Title>
|
|
<Text type="secondary">
|
|
{$t('pages.clones.step3.confirmTips')}
|
|
</Text>
|
|
<Input
|
|
placeholder={targetDataSource?.sourceName || ''}
|
|
className="text-center"
|
|
size="large"
|
|
value={inputValue}
|
|
onChange={(e) => setInputValue(e.target.value)}
|
|
/>
|
|
<Text type="secondary">
|
|
{$t('pages.clones.step3.confirmTips2')}
|
|
</Text>
|
|
</Space>
|
|
</Flex>
|
|
</div>
|
|
<Divider style={{ margin: '16px 0' }} />
|
|
</StepsForm.StepForm>
|
|
</StepsForm>
|
|
</MultiCopyPopupContext.Provider>
|
|
|
|
<BatchCloneModal
|
|
visible={batchCloneModalVisible}
|
|
selectedRows={selectedRows}
|
|
onClose={(cb) => {
|
|
setBatchCloneModalVisible(false);
|
|
cb?.();
|
|
}}
|
|
onFinish={(cb) => {
|
|
flushSync(() => {
|
|
setBatchCloneModalVisible(false);
|
|
});
|
|
cb?.();
|
|
handleCancel();
|
|
onDone?.(true);
|
|
}}
|
|
/>
|
|
</Modal>
|
|
);
|
|
};
|
|
export default MultiCopyPopup;
|