diff --git a/.gitignore b/.gitignore index 85673872e..960df7d52 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,8 @@ dist /build /packages/icons-svg/es/* /packages/icons-svg/lib/* +/packages/dms-kit/lib/* +/packages/dms-kit/.dumi/tmp* # misc .DS_Store diff --git a/.npmrc b/.npmrc index 7549542d7..5e775f322 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ registry=https://registry.npmmirror.com +@actiontech:registry=http://10.186.18.19:4873/ \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 9cb972fd1..ed151ea47 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,4 @@ *.snap -*.md \ No newline at end of file +*.md +**/demo/** +**/demos/** \ No newline at end of file diff --git a/DumiHeaderExtraSlots/index.tsx b/DumiHeaderExtraSlots/index.tsx new file mode 100644 index 000000000..bed54c844 --- /dev/null +++ b/DumiHeaderExtraSlots/index.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import Select from 'antd/es/select'; +import { HeaderExtraStyleWrapper } from './style'; + +// 该值取自 /packages/**/.dumirc.ts的define字段 +declare const VERSION: string; + +const HeaderExtra: React.FC<{ pkg?: 'dms-kit' | 'icons' }> = ({ + pkg = 'dms-kit' +}) => { + const curVersion = Number(VERSION.split('.')[0]); + const historyVersions = new Array(curVersion) + .fill(0) + .map((_, idx) => `v${idx}`) + .reverse(); + const options = [VERSION, ...historyVersions].map((item) => ({ + value: item, + label: item + })); + + const handleVersionChange = (version: string) => { + window.location.href = `/doc/${pkg}-${version}`; + }; + + return ( + + + + + +
+
+ SQL工作台 +
+
+ 为数据分析师和开发者提供,用于数据查询与操作。 +
+
+
+ + + + + + 您可以随时在「个人中心」-「登录设置」中修改此配置。 + +
+ +
+ + + + + + + +`; diff --git a/packages/base/src/page/Nav/UserGuideModal/__tests__/__snapshots__/index.test.tsx.snap b/packages/base/src/page/Nav/UserGuideModal/__tests__/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000..953a293e8 --- /dev/null +++ b/packages/base/src/page/Nav/UserGuideModal/__tests__/__snapshots__/index.test.tsx.snap @@ -0,0 +1,147 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UserGuide should render modal when location not form ODC 1`] = ` + +
+
+
+
+
+ +
+ +`; diff --git a/packages/base/src/page/Nav/UserGuideModal/__tests__/index.test.tsx b/packages/base/src/page/Nav/UserGuideModal/__tests__/index.test.tsx new file mode 100644 index 000000000..f8eb2eb33 --- /dev/null +++ b/packages/base/src/page/Nav/UserGuideModal/__tests__/index.test.tsx @@ -0,0 +1,61 @@ +import { screen } from '@testing-library/react'; +import { superRender } from '@actiontech/shared/lib/testUtil/superRender'; +import { + mockUseCurrentUser, + baseMockApi +} from '@actiontech/shared/lib/testUtil'; +import { useDispatch, useSelector } from 'react-redux'; +import UserGuide from '../index'; +import { mockUseRecentlySelectedZone } from '../../../../testUtils/mockHooks/mockUseRecentlySelectedZone'; +import { + SQL_WORKBENCH_FROM_PARAM_NAME, + ODC_WORKBENCH_NAME +} from '@actiontech/dms-kit'; + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useDispatch: jest.fn(), + useSelector: jest.fn() +})); + +describe('UserGuide', () => { + const mockDispatch = jest.fn(); + + beforeEach(() => { + mockUseCurrentUser({ systemPreference: undefined }); + baseMockApi.cloudBeaver.getSqlQueryUrl(); + baseMockApi.userCenter.updateCurrentUser(); + (useDispatch as jest.Mock).mockImplementation(() => mockDispatch); + (useSelector as jest.Mock).mockImplementation((selector) => { + return selector({ + availabilityZone: { + availabilityZoneTips: [] + } + }); + }); + mockUseRecentlySelectedZone(); + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + jest.clearAllMocks(); + }); + + it('should render modal when location not form ODC', async () => { + const { baseElement } = superRender(); + expect(baseElement).toMatchSnapshot(); + expect(screen.getByText('请选择默认进入的页面')).toBeInTheDocument(); + }); + + it('should render null when location form ODC', async () => { + Object.defineProperty(window, 'location', { + value: { + search: `?${SQL_WORKBENCH_FROM_PARAM_NAME}=${ODC_WORKBENCH_NAME}` + }, + writable: true + }); + superRender(); + expect(screen.queryByText('请选择默认进入的页面')).not.toBeInTheDocument(); + }); +}); diff --git a/packages/base/src/page/Nav/UserGuideModal/data.ts b/packages/base/src/page/Nav/UserGuideModal/data.ts new file mode 100644 index 000000000..741f47800 --- /dev/null +++ b/packages/base/src/page/Nav/UserGuideModal/data.ts @@ -0,0 +1,7 @@ +import { GetUserSystemEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; +import { t } from '../../../locale'; + +export const systemDictionary = { + [GetUserSystemEnum.WORKBENCH]: t('dmsMenu.userGuide.sqlWorkbench.label'), + [GetUserSystemEnum.MANAGEMENT]: t('dmsMenu.userGuide.adminPanel.label') +}; diff --git a/packages/base/src/page/Nav/UserGuideModal/index.tsx b/packages/base/src/page/Nav/UserGuideModal/index.tsx new file mode 100644 index 000000000..6f9d48ec3 --- /dev/null +++ b/packages/base/src/page/Nav/UserGuideModal/index.tsx @@ -0,0 +1,24 @@ +import { useMemo } from 'react'; +import UserGuideModal from './UserGuideModal'; +import queryString from 'query-string'; +import { + EmptyBox, + SQL_WORKBENCH_FROM_PARAM_NAME, + ODC_WORKBENCH_NAME +} from '@actiontech/dms-kit'; + +const UserGuide = () => { + const isNotFormODC = useMemo(() => { + const parsedQuery = queryString.parse(location.search); + + return parsedQuery[SQL_WORKBENCH_FROM_PARAM_NAME] !== ODC_WORKBENCH_NAME; + }, []); + + return ( + + + + ); +}; + +export default UserGuide; diff --git a/packages/base/src/page/Nav/UserGuideModal/style.ts b/packages/base/src/page/Nav/UserGuideModal/style.ts new file mode 100644 index 000000000..e66334e4a --- /dev/null +++ b/packages/base/src/page/Nav/UserGuideModal/style.ts @@ -0,0 +1,65 @@ +import { styled } from '@mui/material/styles'; + +export const UserGuideModalStyleWrapper = styled('div')` + margin-bottom: 32px; + + & .ant-radio-group.radio-group { + width: 100%; + display: flex; + flex-direction: column; + gap: 12px; + + .radio-option { + display: flex; + align-items: flex-start; + width: 100%; + padding: 16px; + margin: 0; + border: 1px solid ${({ theme }) => theme.sharedTheme.uiToken.colorBorder}; + border-radius: 8px; + background: ${({ theme }) => theme.sharedTheme.uiToken.colorBgBase}; + + &:hover { + border-color: ${({ theme }) => theme.sharedTheme.uiToken.colorPrimary}; + } + + &.ant-radio-wrapper-checked { + border-color: ${({ theme }) => theme.sharedTheme.uiToken.colorPrimary}; + background: ${({ theme }) => + theme.sharedTheme.basic.colorPrimaryBgActive}; + } + + .ant-radio { + margin-top: 2px; + } + + .ant-radio + span { + margin-left: 12px; + flex: 1; + } + } + } + + .option-content { + width: 100%; + } + + .option-label { + font-weight: 500; + font-size: 14px; + color: ${({ theme }) => theme.sharedTheme.uiToken.colorTextBase}; + margin-bottom: 4px; + } + + .option-description { + font-size: 12px; + color: ${({ theme }) => theme.sharedTheme.uiToken.colorTextSecondary}; + line-height: 1.4; + } +`; + +export const UserGuideModalButtonContainer = styled('div')` + display: flex; + justify-content: center; + margin-top: 16px; +`; diff --git a/packages/base/src/page/Nav/index.tsx b/packages/base/src/page/Nav/index.tsx index c64ff6aff..e85c6ff99 100644 --- a/packages/base/src/page/Nav/index.tsx +++ b/packages/base/src/page/Nav/index.tsx @@ -1,6 +1,7 @@ import { ReactNode } from 'react'; -import { LayoutStyleWrapper } from '@actiontech/shared/lib/styleWrapper/nav'; +import { LayoutStyleWrapper } from '@actiontech/dms-kit'; import useBrowserVersionTips from '../../hooks/useBrowserVersionTips'; +import UserGuideModal from './UserGuideModal'; // #if [ee] import EESideMenu from './SideMenu'; @@ -29,6 +30,8 @@ const Nav: React.FC<{ children?: ReactNode }> = (props) => { {/* #endif */}
+ + ); }; diff --git a/packages/base/src/page/NotFoundPage/index.tsx b/packages/base/src/page/NotFoundPage/index.tsx index c1aa2c2e1..281d74b2d 100644 --- a/packages/base/src/page/NotFoundPage/index.tsx +++ b/packages/base/src/page/NotFoundPage/index.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { Typography, Space, Spin } from 'antd'; -import { BasicButton, useTypedNavigate, BasicResult } from '@actiontech/shared'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import { BasicButton, BasicResult, ROUTE_PATHS } from '@actiontech/dms-kit'; +import { useTypedNavigate } from '@actiontech/shared'; import { SuggestionList } from './style'; import { DmsApi } from '@actiontech/shared/lib/api'; import { useRequest } from 'ahooks'; diff --git a/packages/base/src/page/Project/BatchImportDataSource/ConnectableErrorModal/index.tsx b/packages/base/src/page/Project/BatchImportDataSource/ConnectableErrorModal/index.tsx index acb7b911c..f7e762bff 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/ConnectableErrorModal/index.tsx +++ b/packages/base/src/page/Project/BatchImportDataSource/ConnectableErrorModal/index.tsx @@ -1,8 +1,10 @@ -import { BasicButton } from '@actiontech/shared/lib/components/BasicButton'; -import { BasicModal } from '@actiontech/shared/lib/components'; +import { + BasicButton, + BasicModal, + ReminderInformation +} from '@actiontech/dms-kit'; import { useTranslation } from 'react-i18next'; import { Space } from 'antd'; -import { ReminderInformation } from '@actiontech/shared/lib/components/ReminderInformation'; import { ConnectableInfoModalWrapper } from '../style'; interface IConnectableErrorModalProps { diff --git a/packages/base/src/page/Project/BatchImportDataSource/UploadForm/FileUpload.tsx b/packages/base/src/page/Project/BatchImportDataSource/UploadForm/FileUpload.tsx index 8a6396a83..36c29fdda 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/UploadForm/FileUpload.tsx +++ b/packages/base/src/page/Project/BatchImportDataSource/UploadForm/FileUpload.tsx @@ -1,25 +1,27 @@ import { Upload, UploadProps, Button, Space } from 'antd'; -import { BasicButton, ReminderInformation, EmptyBox } from '@actiontech/shared'; +import { + BasicButton, + ReminderInformation, + EmptyBox +} from '@actiontech/dms-kit'; import { useTranslation } from 'react-i18next'; import { ImportProjectUploadFileFieldWrapper } from '../../style'; import Project from '@actiontech/shared/lib/api/base/service/Project'; import { useBoolean } from 'ahooks'; import { FileUploadCheckStatusType } from '../index.type'; - const FileUpload: React.FC< - UploadProps & { uploadCheckStatus: FileUploadCheckStatusType } + UploadProps & { + uploadCheckStatus: FileUploadCheckStatusType; + } > = ({ uploadCheckStatus, ...props }) => { const { t } = useTranslation(); - const [loading, { setTrue: setPending, setFalse: setDone }] = useBoolean(); - const onDownload = () => { setPending(); - Project.GetImportDBServicesTemplate({ responseType: 'blob' }).finally(() => - setDone() - ); + Project.GetImportDBServicesTemplate({ + responseType: 'blob' + }).finally(() => setDone()); }; - return ( @@ -45,5 +47,4 @@ const FileUpload: React.FC< ); }; - export default FileUpload; diff --git a/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.tsx b/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.tsx index 61d898b45..3f726ebef 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.tsx +++ b/packages/base/src/page/Project/BatchImportDataSource/UploadForm/index.tsx @@ -3,13 +3,10 @@ import { FormAreaBlockStyleWrapper, FormStyleWrapper, formItemLayout -} from '@actiontech/shared/lib/components/CustomForm/style'; -import { - FormItemBigTitle, - FormItemLabel -} from '@actiontech/shared/lib/components/CustomForm'; +} from '@actiontech/dms-kit/es/components/CustomForm/style'; +import { FormItemBigTitle, FormItemLabel } from '@actiontech/dms-kit'; import Icon from '@ant-design/icons'; -import { getFileFromUploadChangeEvent } from '@actiontech/shared/lib/utils/Common'; +import { getFileFromUploadChangeEvent } from '@actiontech/dms-kit'; import { BatchImportDataSourceFormType, FileUploadCheckStatusType diff --git a/packages/base/src/page/Project/BatchImportDataSource/hooks/useBatchCheckConnectable.ts b/packages/base/src/page/Project/BatchImportDataSource/hooks/useBatchCheckConnectable.ts index a382a7813..f99cd4394 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/hooks/useBatchCheckConnectable.ts +++ b/packages/base/src/page/Project/BatchImportDataSource/hooks/useBatchCheckConnectable.ts @@ -1,6 +1,6 @@ import { useRequest } from 'ahooks'; import { DmsApi } from '@actiontech/shared/lib/api'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { IImportDBServiceV2 } from '@actiontech/shared/lib/api/base/service/common'; import { useBoolean } from 'ahooks'; import { diff --git a/packages/base/src/page/Project/BatchImportDataSource/hooks/useBatchImportDataSource.ts b/packages/base/src/page/Project/BatchImportDataSource/hooks/useBatchImportDataSource.ts index 47ea8ffae..61f2784a4 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/hooks/useBatchImportDataSource.ts +++ b/packages/base/src/page/Project/BatchImportDataSource/hooks/useBatchImportDataSource.ts @@ -4,13 +4,10 @@ import { BatchImportDataSourceFormValueType, FileUploadCheckStatusType } from '../index.type'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; -import { jsonParse } from '@actiontech/shared/lib/utils/Common'; -import { - MIMETypeEnum, - ResponseBlobJsonType -} from '@actiontech/shared/lib/enum'; -import { isExportFileResponse } from '@actiontech/shared/lib/utils/Common'; +import { ResponseCode } from '@actiontech/dms-kit'; +import { jsonParse } from '@actiontech/dms-kit'; +import { MIMETypeEnum, ResponseBlobJsonType } from '@actiontech/dms-kit'; +import { isExportFileResponse } from '@actiontech/dms-kit'; import { AxiosResponse } from 'axios'; import { useTranslation } from 'react-i18next'; import { IImportDBServiceV2 } from '@actiontech/shared/lib/api/base/service/common'; diff --git a/packages/base/src/page/Project/BatchImportDataSource/index.tsx b/packages/base/src/page/Project/BatchImportDataSource/index.tsx index 3256794c6..8669e26de 100644 --- a/packages/base/src/page/Project/BatchImportDataSource/index.tsx +++ b/packages/base/src/page/Project/BatchImportDataSource/index.tsx @@ -2,24 +2,22 @@ import { BasicButton, PageHeader, EmptyBox, - BasicResult, - TypedLink -} from '@actiontech/shared'; + BasicResult +} from '@actiontech/dms-kit'; +import { TypedLink } from '@actiontech/shared'; import { useTranslation } from 'react-i18next'; import BatchImportDataSourceForm from './UploadForm'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import useBatchImportDataSource from './hooks/useBatchImportDataSource'; import { UploadProps } from 'antd'; import { useCallback } from 'react'; import { LeftArrowOutlined } from '@actiontech/icons'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import { ROUTE_PATHS } from '@actiontech/dms-kit'; import { DmsApi } from '@actiontech/shared/lib/api'; import useBatchCheckConnectable from './hooks/useBatchCheckConnectable'; import ConnectableErrorModal from './ConnectableErrorModal'; - const BatchImportDataSource = () => { const { t } = useTranslation(); - const { importLoading, setImportPending, @@ -34,7 +32,6 @@ const BatchImportDataSource = () => { uploadCheckStatus, clearUploadCheckStatus } = useBatchImportDataSource(); - const { batchCheckConnectable, batchCheckConnectableLoading, @@ -43,7 +40,6 @@ const BatchImportDataSource = () => { hideConnectErrorModal, connectableInfo } = useBatchCheckConnectable(); - const onSubmit = async () => { setImportPending(); DmsApi.ProjectService.ImportDBServicesOfProjectsV2({ @@ -59,10 +55,8 @@ const BatchImportDataSource = () => { hideConnectErrorModal(); }); }; - const onCheckConnectableBeforeSubmit = async () => { await form.validateFields(); - batchCheckConnectable(dbServices ?? []).then((res) => { if (res?.isConnectable) { onSubmit(); @@ -71,7 +65,6 @@ const BatchImportDataSource = () => { } }); }; - const onUploadCustomRequest = useCallback< Required['customRequest'] >( @@ -79,8 +72,12 @@ const BatchImportDataSource = () => { setDBservices([]); clearUploadCheckStatus(); DmsApi.ProjectService.ImportDBServicesOfProjectsCheckV2( - { db_services_file: option.file }, - { responseType: 'blob' } + { + db_services_file: option.file + }, + { + responseType: 'blob' + } ) .then((res) => { importServicesCheck(res); @@ -92,7 +89,6 @@ const BatchImportDataSource = () => { }, [importServicesCheck, setDBservices, clearUploadCheckStatus] ); - return ( <> { ); }; - export default BatchImportDataSource; diff --git a/packages/base/src/page/Project/Detail/NotFoundRecentlyProject/ProjectSelectorModal.tsx b/packages/base/src/page/Project/Detail/NotFoundRecentlyProject/ProjectSelectorModal.tsx index 5fcdc65c8..3d3ea9a09 100644 --- a/packages/base/src/page/Project/Detail/NotFoundRecentlyProject/ProjectSelectorModal.tsx +++ b/packages/base/src/page/Project/Detail/NotFoundRecentlyProject/ProjectSelectorModal.tsx @@ -1,13 +1,12 @@ import { InputRef, SelectProps, Space } from 'antd'; -import { BasicButton, BasicModal } from '@actiontech/shared'; +import { BasicButton, BasicModal } from '@actiontech/dms-kit'; import { useTranslation } from 'react-i18next'; import { SelectProjectModalContentStyleWrapper } from './style'; import ProjectSelector from '../../../Nav/SideMenu/ProjectSelector'; import { ProjectSelectorPopupMenuStyleWrapper } from '../../../Nav/SideMenu/ProjectSelector/style'; import { ProjectSelectorModalProps } from './index.type'; -import CustomSelectSearchInput from '@actiontech/shared/lib/components/CustomSelect/CustomSelectSearchInput'; import { useRef, useState } from 'react'; - +import CustomSelectSearchInput from '@actiontech/dms-kit/es/components/CustomSelect/CustomSelectSearchInput'; const ProjectSelectorModal: React.FC = ({ onModalOk, open, @@ -19,7 +18,6 @@ const ProjectSelectorModal: React.FC = ({ const { t } = useTranslation(); const searchInputRef = useRef(null); const [searchValue, setSearchValue] = useState(''); - const renderDropdown: SelectProps['dropdownRender'] = (menu) => { return ( @@ -37,7 +35,6 @@ const ProjectSelectorModal: React.FC = ({ ); }; - return ( = ({ ); }; - export default ProjectSelectorModal; diff --git a/packages/base/src/page/Project/Detail/index.ce.tsx b/packages/base/src/page/Project/Detail/index.ce.tsx index 6e66719fb..4ddaa053c 100644 --- a/packages/base/src/page/Project/Detail/index.ce.tsx +++ b/packages/base/src/page/Project/Detail/index.ce.tsx @@ -1,13 +1,13 @@ -import { DEFAULT_PROJECT_ID } from '@actiontech/shared/lib/data/common'; +import { DEFAULT_PROJECT_ID } from '@actiontech/dms-kit'; import { useCurrentUser } from '@actiontech/shared/lib/features'; import { useEffect } from 'react'; import { Outlet, useLocation } from 'react-router-dom'; import useFetchPermissionData from '../../../hooks/useFetchPermissionData'; import { useDispatch } from 'react-redux'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { updateUserOperationPermissions } from '../../../store/permission'; import { useTypedNavigate } from '@actiontech/shared'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import { ROUTE_PATHS } from '@actiontech/dms-kit'; const CEIndexProjectDetail: React.FC = () => { const location = useLocation(); diff --git a/packages/base/src/page/Project/Detail/index.ee.tsx b/packages/base/src/page/Project/Detail/index.ee.tsx index 8e408dc29..e76c75c9f 100644 --- a/packages/base/src/page/Project/Detail/index.ee.tsx +++ b/packages/base/src/page/Project/Detail/index.ee.tsx @@ -7,7 +7,7 @@ import { Outlet } from 'react-router-dom'; import useRecentlyOpenedProjects from '../../Nav/SideMenu/useRecentlyOpenedProjects'; import NotFoundRecentlyProject from './NotFoundRecentlyProject'; import useFetchPermissionData from '../../../hooks/useFetchPermissionData'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { useDispatch } from 'react-redux'; import { updateUserOperationPermissions } from '../../../store/permission'; diff --git a/packages/base/src/page/Project/Drawer/AddProject.tsx b/packages/base/src/page/Project/Drawer/AddProject.tsx index 0ac4be1b1..f87e6ec51 100644 --- a/packages/base/src/page/Project/Drawer/AddProject.tsx +++ b/packages/base/src/page/Project/Drawer/AddProject.tsx @@ -9,27 +9,21 @@ import { IReduxState } from '../../../store'; import { updateProjectModalStatus } from '../../../store/project'; import EventEmitter from '../../../utils/EventEmitter'; import ProjectForm from './ProjectForm/ProjectForm'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { ProjectFormFields } from './ProjectForm'; import { IAddProjectV2Params } from '@actiontech/shared/lib/api/base/service/Project/index.d'; import { DmsApi } from '@actiontech/shared/lib/api'; -import { BasicButton, BasicDrawer } from '@actiontech/shared'; - +import { BasicButton, BasicDrawer } from '@actiontech/dms-kit'; const AddProject: React.FC = () => { const { t } = useTranslation(); const dispatch = useDispatch(); - const [messageApi, contextHolder] = message.useMessage(); - const [form] = useForm(); - const [submitLoading, { setFalse: submitFinish, setTrue: startSubmit }] = useBoolean(); - const visible = useSelector( (state: IReduxState) => state.project.modalStatus[ModalName.DMS_Add_Project] ); - const closeDrawer = () => { form.resetFields(); dispatch( @@ -39,7 +33,6 @@ const AddProject: React.FC = () => { }) ); }; - const submit = async () => { const values = await form.validateFields(); const params: IAddProjectV2Params = { @@ -69,7 +62,6 @@ const AddProject: React.FC = () => { submitFinish(); }); }; - return ( <> { ); }; - export default AddProject; diff --git a/packages/base/src/page/Project/Drawer/ProjectForm/BusinessField/index.tsx b/packages/base/src/page/Project/Drawer/ProjectForm/BusinessField/index.tsx index bb4a78e70..162aaeaa5 100644 --- a/packages/base/src/page/Project/Drawer/ProjectForm/BusinessField/index.tsx +++ b/packages/base/src/page/Project/Drawer/ProjectForm/BusinessField/index.tsx @@ -1,36 +1,27 @@ -import { - EditableSelect, - EditableSelectValue, - EditableSelectOption -} from '@actiontech/shared'; +import { EditableSelect } from '@actiontech/dms-kit'; +import { EditableSelectValue, EditableSelectOption } from '@actiontech/dms-kit'; import { useTranslation } from 'react-i18next'; import { DmsApi } from '@actiontech/shared/lib/api'; import { useRequest } from 'ahooks'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { message } from 'antd'; import { useState } from 'react'; import { IListProjectV2 } from '@actiontech/shared/lib/api/base/service/common'; import { useBoolean } from 'ahooks'; - interface BusinessSelectorProps { value?: EditableSelectValue; onChange?: (value: EditableSelectValue) => void; } - const BusinessField = (props: BusinessSelectorProps) => { const { t } = useTranslation(); - const [messageApi, contextHolder] = message.useMessage(); - const [boundProjectList, setBoundProjectList] = useState( [] ); - const [ operationLoading, { setTrue: startOperationLoading, setFalse: stopOperationLoading } ] = useBoolean(); - const { data: businessList, refresh, @@ -48,7 +39,6 @@ const BusinessField = (props: BusinessSelectorProps) => { } }) ); - const onAddBusiness = (v: string) => { startOperationLoading(); DmsApi.ProjectService.CreateBusinessTag({ @@ -66,7 +56,6 @@ const BusinessField = (props: BusinessSelectorProps) => { stopOperationLoading(); }); }; - const deleteBusinessTag = (id: string) => { startOperationLoading(); DmsApi.ProjectService.DeleteBusinessTag({ @@ -82,7 +71,6 @@ const BusinessField = (props: BusinessSelectorProps) => { stopOperationLoading(); }); }; - const onDelete = (item: EditableSelectOption) => { startOperationLoading(); DmsApi.ProjectService.ListProjectsV2({ @@ -101,7 +89,6 @@ const BusinessField = (props: BusinessSelectorProps) => { stopOperationLoading(); }); }; - const onUpdate = (item: EditableSelectOption) => { startOperationLoading(); DmsApi.ProjectService.UpdateBusinessTag({ @@ -120,7 +107,6 @@ const BusinessField = (props: BusinessSelectorProps) => { stopOperationLoading(); }); }; - return ( <> {contextHolder} @@ -146,5 +132,4 @@ const BusinessField = (props: BusinessSelectorProps) => { ); }; - export default BusinessField; diff --git a/packages/base/src/page/Project/Drawer/ProjectForm/ProjectForm.tsx b/packages/base/src/page/Project/Drawer/ProjectForm/ProjectForm.tsx index 368d219c9..a30139322 100644 --- a/packages/base/src/page/Project/Drawer/ProjectForm/ProjectForm.tsx +++ b/packages/base/src/page/Project/Drawer/ProjectForm/ProjectForm.tsx @@ -1,17 +1,15 @@ import { Form } from 'antd'; import { useTranslation } from 'react-i18next'; import { ProjectFormFields, ProjectFormProps } from '.'; -import { nameRule } from '@actiontech/shared/lib/utils/FormRule'; -import { BasicInput, BasicSelect } from '@actiontech/shared'; +import { nameRule } from '@actiontech/dms-kit'; +import { BasicInput, BasicSelect } from '@actiontech/dms-kit'; import { ProjectPriorityOptions } from 'sqle/src/page/GlobalDashboard/index.data'; import BusinessField from './BusinessField'; - const ProjectForm: React.FC = ({ form, isUpdate = false }) => { const { t } = useTranslation(); - return ( form={form} colon={false} layout="vertical"> = ({ ); }; - export default ProjectForm; diff --git a/packages/base/src/page/Project/Drawer/UpdateProject.tsx b/packages/base/src/page/Project/Drawer/UpdateProject.tsx index 0dadc90a0..e98c0e746 100644 --- a/packages/base/src/page/Project/Drawer/UpdateProject.tsx +++ b/packages/base/src/page/Project/Drawer/UpdateProject.tsx @@ -4,7 +4,7 @@ import { useForm } from 'antd/es/form/Form'; import { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import EmitterKey from '../../../data/EmitterKey'; import { ModalName } from '../../../data/ModalName'; import { IReduxState } from '../../../store'; @@ -14,28 +14,22 @@ import ProjectForm from './ProjectForm/ProjectForm'; import { updateProjectModalStatus } from '../../../store/project'; import { IUpdateProjectV2Params } from '@actiontech/shared/lib/api/base/service/Project/index.d'; import { DmsApi } from '@actiontech/shared/lib/api'; -import { BasicButton, BasicDrawer } from '@actiontech/shared'; +import { BasicButton, BasicDrawer } from '@actiontech/dms-kit'; import { ProjectV2ProjectPriorityEnum, UpdateProjectV2ProjectPriorityEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; - const UpdateProject: React.FC = () => { const { t } = useTranslation(); const dispatch = useDispatch(); - const [messageApi, contextHolder] = message.useMessage(); - const [form] = useForm(); - const [submitLoading, { setFalse: submitFinish, setTrue: startSubmit }] = useBoolean(); - const { visible, selectProjectItem } = useSelector((state: IReduxState) => ({ visible: state.project.modalStatus[ModalName.DMS_Update_Project], selectProjectItem: state.project.selectProject ?? undefined })); - const closeDrawer = () => { form.resetFields(); dispatch( @@ -45,7 +39,6 @@ const UpdateProject: React.FC = () => { }) ); }; - const submit = async () => { const values = await form.validateFields(); const params: IUpdateProjectV2Params = { @@ -76,7 +69,6 @@ const UpdateProject: React.FC = () => { submitFinish(); }); }; - useEffect(() => { if (visible) { form.setFieldsValue({ @@ -88,7 +80,6 @@ const UpdateProject: React.FC = () => { }); } }, [form, visible, selectProjectItem]); - return ( <> { ); }; - export default UpdateProject; diff --git a/packages/base/src/page/Project/Drawer/__tests__/AddProject.test.tsx b/packages/base/src/page/Project/Drawer/__tests__/AddProject.test.tsx index be16a63cc..bc0a34c10 100644 --- a/packages/base/src/page/Project/Drawer/__tests__/AddProject.test.tsx +++ b/packages/base/src/page/Project/Drawer/__tests__/AddProject.test.tsx @@ -11,7 +11,7 @@ import { getBySelector } from '@actiontech/shared/lib/testUtil/customQuery'; import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser'; -import { SupportLanguage } from '@actiontech/shared/lib/enum'; +import { SupportLanguage } from '@actiontech/dms-kit'; jest.mock('react-redux', () => { return { diff --git a/packages/base/src/page/Project/ImportProject/FileUpload/index.tsx b/packages/base/src/page/Project/ImportProject/FileUpload/index.tsx index cded2656d..61398b15e 100644 --- a/packages/base/src/page/Project/ImportProject/FileUpload/index.tsx +++ b/packages/base/src/page/Project/ImportProject/FileUpload/index.tsx @@ -1,22 +1,18 @@ import { Upload, UploadProps, Button } from 'antd'; -import { BasicButton } from '@actiontech/shared'; +import { BasicButton } from '@actiontech/dms-kit'; import { useTranslation } from 'react-i18next'; import { ImportProjectUploadFileFieldWrapper } from '../../style'; import Project from '@actiontech/shared/lib/api/base/service/Project'; import { useBoolean } from 'ahooks'; - const FileUpload: React.FC = (props) => { const { t } = useTranslation(); - const [loading, { setTrue: setPending, setFalse: setDone }] = useBoolean(); - const onDownload = () => { setPending(); - Project.GetImportProjectsTemplate({ responseType: 'blob' }).finally(() => - setDone() - ); + Project.GetImportProjectsTemplate({ + responseType: 'blob' + }).finally(() => setDone()); }; - return ( @@ -28,5 +24,4 @@ const FileUpload: React.FC = (props) => { ); }; - export default FileUpload; diff --git a/packages/base/src/page/Project/ImportProject/column.tsx b/packages/base/src/page/Project/ImportProject/column.tsx index 9bafc92a9..08bfa8df5 100644 --- a/packages/base/src/page/Project/ImportProject/column.tsx +++ b/packages/base/src/page/Project/ImportProject/column.tsx @@ -1,4 +1,4 @@ -import { ActiontechTableColumn } from '@actiontech/shared/lib/components/ActiontechTable'; +import { ActiontechTableColumn } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { IPreviewImportProjectsV2 } from '@actiontech/shared/lib/api/base/service/common'; import { BasicTypographyEllipsis } from '@actiontech/shared'; import { t } from '../../../locale'; diff --git a/packages/base/src/page/Project/ImportProject/index.tsx b/packages/base/src/page/Project/ImportProject/index.tsx index 8a0f5effa..2db688400 100644 --- a/packages/base/src/page/Project/ImportProject/index.tsx +++ b/packages/base/src/page/Project/ImportProject/index.tsx @@ -2,54 +2,46 @@ import { BasicButton, PageHeader, EmptyBox, - BasicResult, - TypedLink -} from '@actiontech/shared'; + BasicResult +} from '@actiontech/dms-kit'; +import { TypedLink } from '@actiontech/shared'; import { useTranslation } from 'react-i18next'; import { FormAreaBlockStyleWrapper, FormStyleWrapper, formItemLayout -} from '@actiontech/shared/lib/components/CustomForm/style'; +} from '@actiontech/dms-kit/es/components/CustomForm/style'; import { Form } from 'antd'; -import { - FormItemBigTitle, - FormItemLabel -} from '@actiontech/shared/lib/components/CustomForm'; +import { FormItemBigTitle, FormItemLabel } from '@actiontech/dms-kit'; import Icon from '@ant-design/icons'; -import { getFileFromUploadChangeEvent } from '@actiontech/shared/lib/utils/Common'; -import { ActiontechTable } from '@actiontech/shared/lib/components/ActiontechTable'; +import { getFileFromUploadChangeEvent } from '@actiontech/dms-kit'; +import { ActiontechTable } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { useBoolean } from 'ahooks'; import FileUpload from './FileUpload'; import { DmsApi } from '@actiontech/shared/lib/api'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { useState } from 'react'; import { IPreviewImportProjectsV2 } from '@actiontech/shared/lib/api/base/service/common'; import { importProjectListColumn } from './column'; import { ImportProjectUploadFileWrapper } from '../style'; import { LeftArrowOutlined, OverviewOutlined } from '@actiontech/icons'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; - +import { ROUTE_PATHS } from '@actiontech/dms-kit'; const ImportProject = () => { const { t } = useTranslation(); - - const [selectFileForm] = Form.useForm<{ projectsFile: File }>(); - + const [selectFileForm] = Form.useForm<{ + projectsFile: File; + }>(); const [showProjectsTable, { setTrue: showTable, setFalse: hideTable }] = useBoolean(); - const [ importLoading, { setTrue: setImportPending, setFalse: setImportDone } ] = useBoolean(); - const [resultVisible, { setTrue: showResult, setFalse: hideResult }] = useBoolean(false); - const [importProjects, setImportProjects] = useState< IPreviewImportProjectsV2[] >([]); - const onSubmit = async () => { await selectFileForm.validateFields(); setImportPending(); @@ -65,14 +57,12 @@ const ImportProject = () => { setImportDone(); }); }; - const resetAndHideResult = () => { selectFileForm.resetFields(); hideResult(); hideTable(); setImportProjects([]); }; - return ( { ); }; - export default ImportProject; diff --git a/packages/base/src/page/Project/List/action.ts b/packages/base/src/page/Project/List/action.ts index a5e80343d..2cd765ae2 100644 --- a/packages/base/src/page/Project/List/action.ts +++ b/packages/base/src/page/Project/List/action.ts @@ -5,8 +5,8 @@ import { PermissionsConstantType } from '@actiontech/shared/lib/features'; import { t } from '../../../locale'; -import { ACTIONTECH_TABLE_ACTION_BUTTON_WIDTH } from '@actiontech/shared/lib/components/ActiontechTable/hooks/useTableAction'; -import { ActiontechTableActionsConfig } from '@actiontech/shared/lib/components/ActiontechTable/index.type'; +import { ACTIONTECH_TABLE_ACTION_BUTTON_WIDTH } from '@actiontech/dms-kit/es/components/ActiontechTable/hooks/useTableAction'; +import { ActiontechTableActionsConfig } from '@actiontech/dms-kit/es/components/ActiontechTable/index.type'; type Params = { checkActionPermission: ( diff --git a/packages/base/src/page/Project/List/columns.tsx b/packages/base/src/page/Project/List/columns.tsx index f312ad430..20acb17ce 100644 --- a/packages/base/src/page/Project/List/columns.tsx +++ b/packages/base/src/page/Project/List/columns.tsx @@ -1,12 +1,12 @@ import { t } from '../../../locale'; -import { formatTime } from '@actiontech/shared/lib/utils/Common'; +import { formatTime } from '@actiontech/dms-kit'; import { IListProjectV2 } from '@actiontech/shared/lib/api/base/service/common'; -import { ActiontechTableColumn } from '@actiontech/shared/lib/components/ActiontechTable'; -import { TableColumnWithIconStyleWrapper } from '@actiontech/shared/lib/styleWrapper/element'; +import { ActiontechTableColumn } from '@actiontech/dms-kit/es/components/ActiontechTable'; +import { TableColumnWithIconStyleWrapper } from '@actiontech/dms-kit'; import { FlagFilled, LockOutlined } from '@actiontech/icons'; import { BasicTypographyEllipsis, TypedLink } from '@actiontech/shared'; import { ProjectPriorityDictionary } from 'sqle/src/page/GlobalDashboard/index.data'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import { ROUTE_PATHS } from '@actiontech/dms-kit'; import { ProjectListBusinessTagStyleWrapper } from './style'; export const ProjectListTableColumnFactory = diff --git a/packages/base/src/page/Project/List/index.test.tsx b/packages/base/src/page/Project/List/index.test.tsx index 11c578c95..185119447 100644 --- a/packages/base/src/page/Project/List/index.test.tsx +++ b/packages/base/src/page/Project/List/index.test.tsx @@ -10,7 +10,7 @@ import { mockProjectList } from '@actiontech/shared/lib/testUtil/mockApi/base/pr import { baseSuperRender } from '../../../testUtils/superRender'; import EventEmitter from '../../../utils/EventEmitter'; import EmitterKey from '../../../data/EmitterKey'; -import { SystemRole } from '@actiontech/shared/lib/enum'; +import { SystemRole } from '@actiontech/dms-kit'; import { getBySelector } from '@actiontech/shared/lib/testUtil/customQuery'; jest.mock('react-redux', () => { diff --git a/packages/base/src/page/Project/List/index.tsx b/packages/base/src/page/Project/List/index.tsx index 08ddbcddc..567f891c8 100644 --- a/packages/base/src/page/Project/List/index.tsx +++ b/packages/base/src/page/Project/List/index.tsx @@ -6,7 +6,7 @@ import { useTableRequestError, useTableRequestParams, TableToolbar -} from '@actiontech/shared/lib/components/ActiontechTable'; +} from '@actiontech/dms-kit/es/components/ActiontechTable'; import { usePermission, useUserInfo } from '@actiontech/shared/lib/features'; import { useRequest } from 'ahooks'; import { message } from 'antd'; @@ -14,7 +14,7 @@ import { useCallback, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; import { ProjectListTableColumnFactory } from './columns'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import EventEmitter from '../../../utils/EventEmitter'; import EmitterKey from '../../../data/EmitterKey'; import { diff --git a/packages/base/src/page/Project/List/style.ts b/packages/base/src/page/Project/List/style.ts index e830ac203..b73f0e50f 100644 --- a/packages/base/src/page/Project/List/style.ts +++ b/packages/base/src/page/Project/List/style.ts @@ -1,6 +1,5 @@ import { styled } from '@mui/material/styles'; -import { BasicTag } from '@actiontech/shared'; - +import { BasicTag } from '@actiontech/dms-kit'; export const ProjectListBusinessTagStyleWrapper = styled(BasicTag)` &.ant-tag { width: max-content; diff --git a/packages/base/src/page/Project/action.tsx b/packages/base/src/page/Project/action.tsx index ab75bc139..e78ef7a4a 100644 --- a/packages/base/src/page/Project/action.tsx +++ b/packages/base/src/page/Project/action.tsx @@ -5,8 +5,7 @@ import { } from '@actiontech/shared/lib/features'; import { ReactNode } from 'react'; import { t } from '../../locale'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; - +import { ROUTE_PATHS } from '@actiontech/dms-kit'; export const ProjectManagementPageHeaderActions = ( onExport: () => void, exportPending: boolean, diff --git a/packages/base/src/page/Project/index.test.tsx b/packages/base/src/page/Project/index.test.tsx index 94ea93d81..f42bb4b74 100644 --- a/packages/base/src/page/Project/index.test.tsx +++ b/packages/base/src/page/Project/index.test.tsx @@ -9,7 +9,7 @@ import Project from '.'; import { act, cleanup, fireEvent, screen } from '@testing-library/react'; import { getBySelector } from '@actiontech/shared/lib/testUtil/customQuery'; import EmitterKey from '../../data/EmitterKey'; -import { SystemRole } from '@actiontech/shared/lib/enum'; +import { SystemRole } from '@actiontech/dms-kit'; import { mockCurrentUserReturn } from '@actiontech/shared/lib/testUtil/mockHook/data'; jest.mock('react-redux', () => { diff --git a/packages/base/src/page/Project/index.tsx b/packages/base/src/page/Project/index.tsx index 17492e682..7ff2b7159 100644 --- a/packages/base/src/page/Project/index.tsx +++ b/packages/base/src/page/Project/index.tsx @@ -1,5 +1,5 @@ -import { PageHeader } from '@actiontech/shared'; -import { TableRefreshButton } from '@actiontech/shared/lib/components/ActiontechTable'; +import { PageHeader } from '@actiontech/dms-kit'; +import { TableRefreshButton } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { Space, message } from 'antd'; import { useTranslation } from 'react-i18next'; import EventEmitter from '../../utils/EventEmitter'; @@ -12,21 +12,15 @@ import ProjectManageDrawer from './Drawer'; import { DmsApi } from '@actiontech/shared/lib/api'; import { useBoolean } from 'ahooks'; import { ProjectManagementPageHeaderActions } from './action'; - const Project: React.FC = () => { const { t } = useTranslation(); - const [messageApi, contextHolder] = message.useMessage(); - const [exportLoading, { setTrue: exportPending, setFalse: exportFinish }] = useBoolean(); - const dispatch = useDispatch(); - const refreshTable = () => { EventEmitter.emit(EmitterKey.DMS_Refresh_Project_List); }; - const onCreateProject = () => { dispatch( updateProjectModalStatus({ @@ -35,27 +29,27 @@ const Project: React.FC = () => { }) ); }; - const onExport = () => { exportPending(); const hideLoading = messageApi.loading( t('dmsProject.projectList.exportMessage'), 0 ); - DmsApi.ProjectService.ExportProjects({}, { responseType: 'blob' }).finally( - () => { - exportFinish(); - hideLoading(); + DmsApi.ProjectService.ExportProjects( + {}, + { + responseType: 'blob' } - ); + ).finally(() => { + exportFinish(); + hideLoading(); + }); }; - const headerActions = ProjectManagementPageHeaderActions( onExport, exportLoading, onCreateProject ); - return (
{contextHolder} @@ -82,5 +76,4 @@ const Project: React.FC = () => {
); }; - export default Project; diff --git a/packages/base/src/page/ResourceOverview/components/ResourceDetail/ResourceTopology/index.tsx b/packages/base/src/page/ResourceOverview/components/ResourceDetail/ResourceTopology/index.tsx index 78b5cb846..8a58420ab 100644 --- a/packages/base/src/page/ResourceOverview/components/ResourceDetail/ResourceTopology/index.tsx +++ b/packages/base/src/page/ResourceOverview/components/ResourceDetail/ResourceTopology/index.tsx @@ -1,16 +1,14 @@ import React, { useCallback, useEffect, useState } from 'react'; -import { BasicButton } from '@actiontech/shared'; +import { BasicButton } from '@actiontech/dms-kit'; import { Card, Tree, Space, type TreeDataNode } from 'antd'; import { useTranslation } from 'react-i18next'; import { DownOutlined, RightOutlined } from '@actiontech/icons'; import { AntTreeNodeProps } from 'antd/es/tree'; import classNames from 'classnames'; - interface TreeNodeData extends TreeDataNode { key: string; children?: TreeNodeData[]; } - interface ResourceTopologyProps { topology: TreeNodeData[]; selectedKey?: string; @@ -18,7 +16,6 @@ interface ResourceTopologyProps { expandedKeys: string[]; setExpandedKeys: (keys: string[]) => void; } - const ResourceTopology: React.FC = ({ topology, selectedKey, @@ -29,16 +26,13 @@ const ResourceTopology: React.FC = ({ const { t } = useTranslation(); const [autoExpandParent, setAutoExpandParent] = useState(true); const [allKeys, setAllKeys] = useState([]); - const onExpand = (keys: React.Key[]) => { setExpandedKeys(keys as string[]); setAutoExpandParent(false); }; - const onSelect = (keys: React.Key[]) => { setSelectedKey(keys[0] as string); }; - const getAllKeys = useCallback(() => { const keys: string[] = []; const traverse = (nodes: TreeNodeData[]) => { @@ -52,7 +46,6 @@ const ResourceTopology: React.FC = ({ traverse(topology ?? []); return keys; }, [topology]); - const toggleExpandAll = useCallback( (expand: boolean) => { if (expand) { @@ -64,7 +57,6 @@ const ResourceTopology: React.FC = ({ }, [setExpandedKeys, allKeys] ); - useEffect(() => { if (topology.length > 0) { const keys = getAllKeys(); @@ -72,7 +64,6 @@ const ResourceTopology: React.FC = ({ setExpandedKeys(keys); } }, [topology, getAllKeys, setExpandedKeys]); - return ( = ({ ); }; - export default ResourceTopology; diff --git a/packages/base/src/page/ResourceOverview/components/ResourceDetail/actions.tsx b/packages/base/src/page/ResourceOverview/components/ResourceDetail/actions.tsx index 0c452078e..95084730e 100644 --- a/packages/base/src/page/ResourceOverview/components/ResourceDetail/actions.tsx +++ b/packages/base/src/page/ResourceOverview/components/ResourceDetail/actions.tsx @@ -1,6 +1,6 @@ import { t } from '../../../../locale'; import { IResourceListData } from '@actiontech/shared/lib/api/base/service/common'; -import { ActiontechTableActionMeta } from '@actiontech/shared/lib/components/ActiontechTable/index.type'; +import { ActiontechTableActionMeta } from '@actiontech/dms-kit/es/components/ActiontechTable/index.type'; import { ActiontechTableToolbarActionWithPermissions, PERMISSIONS diff --git a/packages/base/src/page/ResourceOverview/components/ResourceDetail/columns.tsx b/packages/base/src/page/ResourceOverview/components/ResourceDetail/columns.tsx index 8847dee86..3211c4bd3 100644 --- a/packages/base/src/page/ResourceOverview/components/ResourceDetail/columns.tsx +++ b/packages/base/src/page/ResourceOverview/components/ResourceDetail/columns.tsx @@ -1,12 +1,11 @@ import { t } from '../../../../locale'; import { IResourceListData } from '@actiontech/shared/lib/api/base/service/common'; -import { ActiontechTableColumn } from '@actiontech/shared/lib/components/ActiontechTable'; +import { ActiontechTableColumn } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { IGetResourceOverviewResourceListV1Params } from '@actiontech/shared/lib/api/base/service/ResourceOverview/index.d'; -import { DatabaseTypeLogo, BasicToolTip } from '@actiontech/shared'; -import { TableColumnWithIconStyleWrapper } from '@actiontech/shared/lib/styleWrapper/element'; +import { DatabaseTypeLogo, BasicToolTip } from '@actiontech/dms-kit'; +import { TableColumnWithIconStyleWrapper } from '@actiontech/dms-kit'; import { FlagFilled, DatabaseSchemaFilled } from '@actiontech/icons'; import { ResourceOverviewTheme } from '../../../../theme/type'; - export const ResourceDetailListColumns = ( getLogoUrlByDbType: (dbType: string) => string, theme: ResourceOverviewTheme @@ -25,7 +24,6 @@ export const ResourceDetailListColumns = ( title: t('resourceOverview.resourceList.type'), render: (dbType) => { if (!dbType) return '-'; - return ( { const { t } = useTranslation(); const [form] = useForm(); const { mergeFromValueIntoParams } = useAsyncParams(); - const [ submitResultVisibility, { setTrue: showResult, setFalse: hiddenResult } ] = useBoolean(); const [submitLoading, { setTrue: startSubmit, setFalse: submitFinish }] = useBoolean(); - const { updateTaskSourceList, ...taskSourceTips } = useTaskSource(); - const onSubmit = async () => { const values = await form.validateFields(); startSubmit(); - const additionalParams = taskSourceTips.generateTaskSourceAdditionalParams( values.source ); - const params: IAddDBServiceSyncTaskParams = { db_service_sync_task: { name: values.name, @@ -75,7 +69,6 @@ const AddSyncTask: React.FC = () => { ) } }; - DBServiceSyncTaskService.AddDBServiceSyncTask(params) .then((res) => { if (res.data.code === ResponseCode.SUCCESS) { @@ -86,16 +79,13 @@ const AddSyncTask: React.FC = () => { submitFinish(); }); }; - const resetAndHideResult = useCallback(() => { hiddenResult(); EventEmitter.emit(EmitterKey.DMS_SYNC_TASK_RESET_FORM); }, [hiddenResult]); - useEffect(() => { updateTaskSourceList(); }, [updateTaskSourceList]); - return ( { ); }; - export default AddSyncTask; diff --git a/packages/base/src/page/SyncDataSource/Form/index.tsx b/packages/base/src/page/SyncDataSource/Form/index.tsx index dc9568e13..2ef84aca7 100644 --- a/packages/base/src/page/SyncDataSource/Form/index.tsx +++ b/packages/base/src/page/SyncDataSource/Form/index.tsx @@ -5,15 +5,15 @@ import { BasicInput, BasicSelect, CronInput, - EmptyBox, - TypedLink -} from '@actiontech/shared'; + EmptyBox +} from '@actiontech/dms-kit'; +import { TypedLink } from '@actiontech/shared'; import { FormAreaBlockStyleWrapper, FormAreaLineStyleWrapper, FormStyleWrapper, formItemLayout -} from '@actiontech/shared/lib/components/CustomForm/style'; +} from '@actiontech/dms-kit/es/components/CustomForm/style'; import { CustomLabelContent, FormInputBotBorder, @@ -21,9 +21,9 @@ import { FormItemLabel, FormItemNoLabel, FormItemSubTitle -} from '@actiontech/shared/lib/components/CustomForm'; -import { checkCron } from '@actiontech/shared/lib/components/CronInput/useCron/cron.tool'; -import { nameRule } from '@actiontech/shared/lib/utils/FormRule'; +} from '@actiontech/dms-kit'; +import { checkCron } from '@actiontech/dms-kit/es/components/CronInput/useCron/cron.tool'; +import { nameRule } from '@actiontech/dms-kit'; import EmitterKey from '../../../data/EmitterKey'; import EventEmitter from '../../../utils/EventEmitter'; import useGlobalRuleTemplate from 'sqle/src/hooks/useGlobalRuleTemplate'; @@ -31,7 +31,6 @@ import AutoCreatedFormItemByApi from 'sqle/src/components/BackendForm/AutoCreate import useAsyncParams from 'sqle/src/components/BackendForm/useAsyncParams'; import { SyncTaskFormProps } from './index.type'; import SqlAuditFields from '../../DataSource/components/Form/SqlAuditFields'; - const SyncTaskForm: React.FC = ({ form, defaultValue, @@ -42,18 +41,14 @@ const SyncTaskForm: React.FC = ({ const { t } = useTranslation(); const isUpdate = useMemo(() => !!defaultValue, [defaultValue]); const source = Form.useWatch('source', form); - const { generateFormValueByParams } = useAsyncParams(); - const { loading: getTaskSourceListLoading, generateTaskSourceSelectOption, generateTaskSourceDbTypesSelectOption, generateTaskSourceAdditionalParams } = taskSourceTips; - const formParams = generateTaskSourceAdditionalParams(source); - const handleChangeInstanceType = (type: string) => { // #if [sqle] form.resetFields([ @@ -67,7 +62,6 @@ const SyncTaskForm: React.FC = ({ updateGlobalRuleTemplateList(type); // #endif }; - const handleChangeAuditEnabled = (check: boolean) => { if (!check) { form.setFieldsValue({ @@ -83,7 +77,6 @@ const SyncTaskForm: React.FC = ({ } } }; - const handleChangeSource = () => { form.setFieldsValue({ instanceType: undefined @@ -96,7 +89,6 @@ const SyncTaskForm: React.FC = ({ updateGlobalRuleTemplateList, globalRuleTemplateList } = useGlobalRuleTemplate(); - const templateOptions = useMemo(() => { return globalRuleTemplateList.map((v) => ({ key: v.rule_template_id, @@ -145,15 +137,12 @@ const SyncTaskForm: React.FC = ({ updateGlobalRuleTemplateByInstanceType(); // #endif }; - EventEmitter.subscribe(EmitterKey.DMS_SYNC_TASK_RESET_FORM, resetForm); - return () => { EventEmitter.unsubscribe(EmitterKey.DMS_SYNC_TASK_RESET_FORM, resetForm); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [defaultValue?.db_type, form, isUpdate]); - useEffect(() => { if (!!defaultValue) { form.setFieldsValue({ @@ -191,7 +180,6 @@ const SyncTaskForm: React.FC = ({ } // eslint-disable-next-line react-hooks/exhaustive-deps }, [defaultValue, form]); - return ( = ({ }, ...nameRule() ]} - labelCol={{ span: 0 }} - wrapperCol={{ span: 24 }} + labelCol={{ + span: 0 + }} + wrapperCol={{ + span: 24 + }} > = ({ +
{t('dmsSyncDataSource.syncTaskForm.helpTips')} = ({ ); }; - export default SyncTaskForm; diff --git a/packages/base/src/page/SyncDataSource/List/__snapshots__/index.test.tsx.snap b/packages/base/src/page/SyncDataSource/List/__snapshots__/index.test.tsx.snap index b41c50751..9940f0405 100644 --- a/packages/base/src/page/SyncDataSource/List/__snapshots__/index.test.tsx.snap +++ b/packages/base/src/page/SyncDataSource/List/__snapshots__/index.test.tsx.snap @@ -229,18 +229,14 @@ exports[`page/SyncDataSource/SyncTaskList render list action when no permission class="ant-space-item" style="margin-right: 8px;" > - - - + + 编 辑 + +
- - - + + 编 辑 + +
- - - + + 编 辑 + +
- - - + + 编 辑 + +
void; deleteAction: (taskId: string) => void; + editSyncTask: (taskId: string) => void; }) => ActiontechTableActionsWithPermissions = ({ syncAction, - deleteAction + deleteAction, + editSyncTask }) => { return [ { key: 'edit', text: t('common.edit'), permissions: PERMISSIONS.ACTIONS.BASE.SYNC_DATA_SOURCE.EDIT, - link(record) { - return { - to: parse2ReactRouterPath(ROUTE_PATHS.BASE.SYNC_DATA_SOURCE.update, { - params: { taskId: record?.uid ?? '' } - }) - }; - } + buttonProps: (record) => ({ + onClick: () => editSyncTask(record?.uid ?? '') + }) }, { key: 'sync', diff --git a/packages/base/src/page/SyncDataSource/List/column.tsx b/packages/base/src/page/SyncDataSource/List/column.tsx index 1278f59c2..98f0e5b7a 100644 --- a/packages/base/src/page/SyncDataSource/List/column.tsx +++ b/packages/base/src/page/SyncDataSource/List/column.tsx @@ -1,11 +1,10 @@ import { t } from '../../../locale'; -import { formatTime } from '@actiontech/shared/lib/utils/Common'; +import { formatTime } from '@actiontech/dms-kit'; import { IListDBServiceSyncTask } from '@actiontech/shared/lib/api/base/service/common'; -import { ActiontechTableColumn } from '@actiontech/shared/lib/components/ActiontechTable'; -import { BasicTag, BasicToolTip, DatabaseTypeLogo } from '@actiontech/shared'; +import { ActiontechTableColumn } from '@actiontech/dms-kit/es/components/ActiontechTable'; +import { BasicTag, BasicToolTip, DatabaseTypeLogo } from '@actiontech/dms-kit'; import { useDbServiceDriver } from '@actiontech/shared/lib/features'; import { Space } from 'antd'; - export const SyncTaskListTableColumnFactory: () => ActiontechTableColumn = () => { const { getLogoUrlByDbType } = useDbServiceDriver(); @@ -29,7 +28,6 @@ export const SyncTaskListTableColumnFactory: () => ActiontechTableColumn ActiontechTableColumn ); } - if (!lastSyncErr && !!record.last_sync_success_time) return ( {t('common.success')} ); - return '-'; } }, diff --git a/packages/base/src/page/SyncDataSource/List/index.test.tsx b/packages/base/src/page/SyncDataSource/List/index.test.tsx index 7b73cdb29..93c778999 100644 --- a/packages/base/src/page/SyncDataSource/List/index.test.tsx +++ b/packages/base/src/page/SyncDataSource/List/index.test.tsx @@ -5,7 +5,7 @@ import syncTaskList from '@actiontech/shared/lib/testUtil/mockApi/base/syncTaskL import SyncTaskList from '.'; import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser'; import { syncTaskListMockData } from '@actiontech/shared/lib/testUtil/mockApi/base/syncTaskList/data'; -import { SystemRole } from '@actiontech/shared/lib/enum'; +import { SystemRole } from '@actiontech/dms-kit'; jest.mock('react-router-dom', () => { return { @@ -95,6 +95,15 @@ describe('page/SyncDataSource/SyncTaskList', () => { expect(requestTableList).toHaveBeenCalledTimes(2); }); + it('render edit button action', async () => { + customRender(); + + await act(async () => jest.advanceTimersByTime(3300)); + fireEvent.click(screen.getAllByText('编 辑')[0]); + await act(async () => jest.advanceTimersByTime(0)); + expect(navigateSpy).toHaveBeenCalledTimes(1); + }); + it('should not render action column when user no operation permissions', async () => { mockUseCurrentUser({ userRoles: { diff --git a/packages/base/src/page/SyncDataSource/List/index.tsx b/packages/base/src/page/SyncDataSource/List/index.tsx index 804f4cc49..65b63fa83 100644 --- a/packages/base/src/page/SyncDataSource/List/index.tsx +++ b/packages/base/src/page/SyncDataSource/List/index.tsx @@ -2,22 +2,25 @@ import { useRequest } from 'ahooks'; import { message } from 'antd'; import { useTranslation } from 'react-i18next'; import { SyncTaskListTableColumnFactory } from './column'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode, ROUTE_PATHS } from '@actiontech/dms-kit'; import DBServiceSyncTaskService from '@actiontech/shared/lib/api/base/service/DBServiceSyncTask'; import { ActiontechTable, useTableRequestError -} from '@actiontech/shared/lib/components/ActiontechTable'; +} from '@actiontech/dms-kit/es/components/ActiontechTable'; import { useEffect } from 'react'; import eventEmitter from '../../../utils/EventEmitter'; import EmitterKey from '../../../data/EmitterKey'; import { SyncTaskListActions } from './action'; import { usePermission } from '@actiontech/shared/lib/features'; +import { useTypedNavigate } from '@actiontech/shared'; const SyncTaskList: React.FC = () => { const { t } = useTranslation(); const [messageApi, contextHoler] = message.useMessage(); + const navigate = useTypedNavigate(); + const { parse2TableActionPermissions } = usePermission(); const { requestErrorMessage, handleTableRequestError } = @@ -65,6 +68,12 @@ const SyncTaskList: React.FC = () => { }); }; + const editSyncTask = (taskId: string) => { + navigate(ROUTE_PATHS.BASE.SYNC_DATA_SOURCE.update, { + params: { taskId } + }); + }; + const { loading, data, refresh } = useRequest(() => handleTableRequestError(DBServiceSyncTaskService.ListDBServiceSyncTasks()) ); @@ -94,7 +103,8 @@ const SyncTaskList: React.FC = () => { actions={parse2TableActionPermissions( SyncTaskListActions({ syncAction, - deleteAction + deleteAction, + editSyncTask }) )} /> diff --git a/packages/base/src/page/SyncDataSource/UpdatePage/index.tsx b/packages/base/src/page/SyncDataSource/UpdatePage/index.tsx index 58a17f406..ec2cca341 100644 --- a/packages/base/src/page/SyncDataSource/UpdatePage/index.tsx +++ b/packages/base/src/page/SyncDataSource/UpdatePage/index.tsx @@ -2,18 +2,16 @@ import { useTranslation } from 'react-i18next'; import { useBoolean } from 'ahooks'; import { useCallback, useEffect, useState } from 'react'; import { Empty, message, Space, Typography } from 'antd'; +import { BasicButton, EmptyBox, PageHeader } from '@actiontech/dms-kit'; import { BackButton, - BasicButton, - EmptyBox, - PageHeader, useTypedNavigate, useTypedParams } from '@actiontech/shared'; -import { PageLayoutHasFixedHeaderStyleWrapper } from '@actiontech/shared/lib/styleWrapper/element'; +import { PageLayoutHasFixedHeaderStyleWrapper } from '@actiontech/dms-kit'; import { useForm } from 'antd/es/form/Form'; import SyncTaskForm from '../Form'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { IGetDBServiceSyncTask } from '@actiontech/shared/lib/api/base/service/common'; import EmitterKey from '../../../data/EmitterKey'; import EventEmitter from '../../../utils/EventEmitter'; @@ -25,17 +23,14 @@ import { IUpdateDBServiceSyncTaskParams } from '@actiontech/shared/lib/api/base/ import useTaskSource from '../../../hooks/useTaskSource'; import useAsyncParams from 'sqle/src/components/BackendForm/useAsyncParams'; import { SyncTaskFormFields } from '../Form/index.type'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; - +import { ROUTE_PATHS } from '@actiontech/dms-kit'; const UpdateSyncTask: React.FC = () => { const { t } = useTranslation(); const navigate = useTypedNavigate(); - const [messageApi, contextHoler] = message.useMessage(); const [form] = useForm(); const { updateTaskSourceList, ...taskSourceTips } = useTaskSource(); const { mergeFromValueIntoParams } = useAsyncParams(); - const { taskId } = useTypedParams(); const [initError, setInitError] = useState(''); @@ -44,15 +39,12 @@ const UpdateSyncTask: React.FC = () => { const [taskInfoLoading, setTaskInfoLoading] = useState(false); const [syncInstanceTask, setSyncInstanceTask] = useState(); - const onSubmit = async () => { const values: SyncTaskFormFields = await form.validateFields(); startSubmit(); - const additionalParams = taskSourceTips.generateTaskSourceAdditionalParams( values.source ); - const params: IUpdateDBServiceSyncTaskParams = { db_service_sync_task_uid: taskId ?? '', db_service_sync_task: { @@ -83,13 +75,14 @@ const UpdateSyncTask: React.FC = () => { ) } }; - DBServiceSyncTaskService.UpdateDBServiceSyncTask(params) .then((res) => { if (res.data.code === ResponseCode.SUCCESS) { messageApi.success(t('dmsSyncDataSource.updateSyncTask.successTips')); navigate(ROUTE_PATHS.BASE.DATA_SOURCE_MANAGEMENT.index, { - queries: { active: DataSourceManagerSegmentedKey.SyncDataSource }, + queries: { + active: DataSourceManagerSegmentedKey.SyncDataSource + }, replace: true }); } @@ -98,7 +91,6 @@ const UpdateSyncTask: React.FC = () => { submitFinish(); }); }; - const getSyncInstanceTask = useCallback(() => { if (!taskId) { setInitError(t('common.unknownError')); @@ -120,16 +112,13 @@ const UpdateSyncTask: React.FC = () => { setTaskInfoLoading(false); }); }, [t, taskId]); - const reset = () => { EventEmitter.emit(EmitterKey.DMS_SYNC_TASK_RESET_FORM); }; - useEffect(() => { getSyncInstanceTask(); updateTaskSourceList(); }, [getSyncInstanceTask, updateTaskSourceList]); - return ( {contextHoler} @@ -160,7 +149,9 @@ const UpdateSyncTask: React.FC = () => { if={!initError} defaultNode={ @@ -195,5 +186,4 @@ const UpdateSyncTask: React.FC = () => { ); }; - export default UpdateSyncTask; diff --git a/packages/base/src/page/System/GitSSHConfig/index.test.tsx b/packages/base/src/page/System/GitSSHConfig/index.test.tsx index 85bb50f12..46c01a018 100644 --- a/packages/base/src/page/System/GitSSHConfig/index.test.tsx +++ b/packages/base/src/page/System/GitSSHConfig/index.test.tsx @@ -3,7 +3,7 @@ import { act, cleanup, fireEvent, screen } from '@testing-library/react'; import { baseSuperRender } from '../../../testUtils/superRender'; import configuration from '@actiontech/shared/lib/testUtil/mockApi/sqle/configuration'; import { getSSHPublicKeyMockData } from '@actiontech/shared/lib/testUtil/mockApi/sqle/configuration/data'; -import { Copy } from '@actiontech/shared'; +import { Copy } from '@actiontech/dms-kit'; import { createSpySuccessResponse } from '@actiontech/shared/lib/testUtil/mockApi'; describe('base/System/GitSSHConfig', () => { diff --git a/packages/base/src/page/System/GitSSHConfig/index.tsx b/packages/base/src/page/System/GitSSHConfig/index.tsx index 2814cb9a0..f19a05d67 100644 --- a/packages/base/src/page/System/GitSSHConfig/index.tsx +++ b/packages/base/src/page/System/GitSSHConfig/index.tsx @@ -1,18 +1,16 @@ import { useTranslation } from 'react-i18next'; import { Alert, Card, Space, Spin, Typography, message } from 'antd'; -import { BasicButton, BasicToolTip, Copy } from '@actiontech/shared'; +import { BasicButton, BasicToolTip } from '@actiontech/dms-kit'; +import { Copy } from '@actiontech/dms-kit'; import SystemBasicTitle from '../components/BasicTitle'; import { useRequest } from 'ahooks'; import { SqleApi } from '@actiontech/shared/lib/api'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { GitSSHConfigStyleWrapper } from './style'; - const { Text, Paragraph } = Typography; - const GitSSHConfig: React.FC = () => { const { t } = useTranslation(); const [messageApi, messageContextHolder] = message.useMessage(); - const { loading: getLoading, run: getPublicKey, @@ -22,7 +20,6 @@ const GitSSHConfig: React.FC = () => { (res) => res.data.data?.public_key ); }); - const { loading: generateLoading, run: generateSSHKey } = useRequest( () => { return SqleApi.ConfigurationService.genSSHPublicKey(); @@ -36,14 +33,12 @@ const GitSSHConfig: React.FC = () => { } } ); - const onCopy = () => { if (publicKey) { Copy.copyTextByTextarea(publicKey); messageApi.success(t('common.copied')); } }; - return ( {messageContextHolder} @@ -94,5 +89,4 @@ const GitSSHConfig: React.FC = () => { ); }; - export default GitSSHConfig; diff --git a/packages/base/src/page/System/GlobalSetting/components/CBOperationLogsExpiredHours.tsx b/packages/base/src/page/System/GlobalSetting/components/CBOperationLogsExpiredHours.tsx index cb30f718d..d5a9c0107 100644 --- a/packages/base/src/page/System/GlobalSetting/components/CBOperationLogsExpiredHours.tsx +++ b/packages/base/src/page/System/GlobalSetting/components/CBOperationLogsExpiredHours.tsx @@ -1,14 +1,9 @@ import { useTranslation } from 'react-i18next'; -import { ConfigItem } from '@actiontech/shared'; -import { - EditInputNumber, - LabelContent -} from '@actiontech/shared/lib/components/ConfigItem'; +import { ConfigItem } from '@actiontech/dms-kit'; +import { EditInputNumber, LabelContent } from '@actiontech/dms-kit'; import useValidatorNumber from './useValidatorNumber'; - import { IUpdateSystemVariablesReqV1 } from '@actiontech/shared/lib/api/sqle/service/common'; import { PERMISSIONS, usePermission } from '@actiontech/shared/lib/features'; - export interface CBOperationLogsExpiredHoursProps { expiredHours: number | undefined; fieldVisible: boolean; @@ -19,7 +14,6 @@ export interface CBOperationLogsExpiredHoursProps { fieldName: keyof IUpdateSystemVariablesReqV1 ) => void; } - const CBOperationLogsExpiredHours = ({ expiredHours, fieldVisible, @@ -61,5 +55,4 @@ const CBOperationLogsExpiredHours = ({ ); }; - export default CBOperationLogsExpiredHours; diff --git a/packages/base/src/page/System/GlobalSetting/components/OperationRecordExpiredHours.tsx b/packages/base/src/page/System/GlobalSetting/components/OperationRecordExpiredHours.tsx index cd4ec61d6..512081f4f 100644 --- a/packages/base/src/page/System/GlobalSetting/components/OperationRecordExpiredHours.tsx +++ b/packages/base/src/page/System/GlobalSetting/components/OperationRecordExpiredHours.tsx @@ -1,13 +1,9 @@ import { useTranslation } from 'react-i18next'; -import { ConfigItem } from '@actiontech/shared'; -import { - EditInputNumber, - LabelContent -} from '@actiontech/shared/lib/components/ConfigItem'; +import { ConfigItem } from '@actiontech/dms-kit'; +import { EditInputNumber, LabelContent } from '@actiontech/dms-kit'; import useValidatorNumber from './useValidatorNumber'; import { IUpdateSystemVariablesReqV1 } from '@actiontech/shared/lib/api/sqle/service/common'; import { PERMISSIONS, usePermission } from '@actiontech/shared/lib/features'; - export interface OperationRecordExpiredHoursProps { expiredHours: number | undefined; fieldVisible: boolean; @@ -18,7 +14,6 @@ export interface OperationRecordExpiredHoursProps { fieldName: keyof IUpdateSystemVariablesReqV1 ) => void; } - const OperationRecordExpiredHours = ({ expiredHours, fieldVisible, @@ -60,5 +55,4 @@ const OperationRecordExpiredHours = ({ ); }; - export default OperationRecordExpiredHours; diff --git a/packages/base/src/page/System/GlobalSetting/components/UrlAddressPrefixTips.tsx b/packages/base/src/page/System/GlobalSetting/components/UrlAddressPrefixTips.tsx index ef8a8cae0..35ff9521f 100644 --- a/packages/base/src/page/System/GlobalSetting/components/UrlAddressPrefixTips.tsx +++ b/packages/base/src/page/System/GlobalSetting/components/UrlAddressPrefixTips.tsx @@ -1,12 +1,8 @@ import { useTranslation } from 'react-i18next'; -import { ConfigItem } from '@actiontech/shared'; -import { - EditInput, - LabelContent -} from '@actiontech/shared/lib/components/ConfigItem'; +import { ConfigItem } from '@actiontech/dms-kit'; +import { EditInput, LabelContent } from '@actiontech/dms-kit'; import { IUpdateSystemVariablesReqV1 } from '@actiontech/shared/lib/api/sqle/service/common'; import { PERMISSIONS, usePermission } from '@actiontech/shared/lib/features'; - export interface UrlAddressPrefixTipsProps { url: string | undefined; fieldVisible: boolean; @@ -17,7 +13,6 @@ export interface UrlAddressPrefixTipsProps { fieldName: keyof IUpdateSystemVariablesReqV1 ) => void; } - const UrlAddressPrefixTips = ({ url, fieldVisible, @@ -55,5 +50,4 @@ const UrlAddressPrefixTips = ({ ); }; - export default UrlAddressPrefixTips; diff --git a/packages/base/src/page/System/GlobalSetting/components/useValidatorNumber.ts b/packages/base/src/page/System/GlobalSetting/components/useValidatorNumber.ts index 7a68d1b1a..c2faacaff 100644 --- a/packages/base/src/page/System/GlobalSetting/components/useValidatorNumber.ts +++ b/packages/base/src/page/System/GlobalSetting/components/useValidatorNumber.ts @@ -1,7 +1,7 @@ import { useTranslation } from 'react-i18next'; import { message } from 'antd'; -import { integerValidate } from '@actiontech/shared/lib/utils/Common'; +import { integerValidate } from '@actiontech/dms-kit'; const useValidatorNumber = () => { const { t } = useTranslation(); diff --git a/packages/base/src/page/System/GlobalSetting/index.tsx b/packages/base/src/page/System/GlobalSetting/index.tsx index 9453441b9..94b1d484e 100644 --- a/packages/base/src/page/System/GlobalSetting/index.tsx +++ b/packages/base/src/page/System/GlobalSetting/index.tsx @@ -1,16 +1,15 @@ import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useBoolean, useRequest } from 'ahooks'; -import useHideConfigInputNode from '../../../../../shared/lib/components/ConfigItem/hooks/useHideConfigInputNode'; +import useHideConfigInputNode from '@actiontech/dms-kit/es/components/ConfigItem/hooks/useHideConfigInputNode'; import { DmsApi } from '@actiontech/shared/lib/api'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; -import { IUpdateSystemVariablesReqV1 } from '@actiontech/shared/lib/api/base/service/common'; +import { ResponseCode, ConfigFieldMapMeta } from '@actiontech/dms-kit'; +import { IUpdateSystemVariablesReqV1 } from '@actiontech/shared/lib/api/sqle/service/common'; import { Spin } from 'antd'; import SystemBasicTitle from '../components/BasicTitle'; import OperationRecordExpiredHours from './components/OperationRecordExpiredHours'; import UrlAddressPrefixTips from './components/UrlAddressPrefixTips'; import CBOperationLogsExpiredHours from './components/CBOperationLogsExpiredHours'; -import { ConfigFieldMapMeta } from '@actiontech/shared'; const GlobalSetting = () => { const { t } = useTranslation(); diff --git a/packages/base/src/page/System/License/Modal/ImportLicense.tsx b/packages/base/src/page/System/License/Modal/ImportLicense.tsx index eb0f4f44c..2b54cde94 100644 --- a/packages/base/src/page/System/License/Modal/ImportLicense.tsx +++ b/packages/base/src/page/System/License/Modal/ImportLicense.tsx @@ -2,40 +2,34 @@ import { useTranslation } from 'react-i18next'; import { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useBoolean } from 'ahooks'; - import { Form, message, Upload } from 'antd'; import { useForm } from 'antd/es/form/Form'; import { RcFile } from 'antd/es/upload'; -import { BasicButton, BasicModal } from '@actiontech/shared'; -import { ActiontechTable } from '@actiontech/shared/lib/components/ActiontechTable'; +import { BasicButton, BasicModal } from '@actiontech/dms-kit'; +import { ActiontechTable } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { LicenseColumn } from '../index.data'; - -import { getFileFromUploadChangeEvent } from '@actiontech/shared/lib/utils/Common'; +import { getFileFromUploadChangeEvent } from '@actiontech/dms-kit'; import EventEmitter from '../../../../utils/EventEmitter'; import EmitterKey from '../../../../data/EmitterKey'; import { ModalName } from '../../../../data/ModalName'; import { IReduxState } from '../../../../store'; import { updateSystemModalStatus } from '../../../../store/system'; - import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; -import { ModalSize, ResponseCode } from '@actiontech/shared/lib/enum'; +import { ModalSize } from '@actiontech/dms-kit'; +import { ResponseCode } from '@actiontech/dms-kit'; import { ILicenseItem } from '@actiontech/shared/lib/api/sqle/service/common'; - const ImportLicenseModal = () => { const { t } = useTranslation(); const dispatch = useDispatch(); const [messageApi, messageContextHolder] = message.useMessage(); - const visible = useSelector( (state: IReduxState) => state.system.modalStatus[ModalName.DMS_Import_License] ); - const [licenseData, setLicenseData] = useState([]); const [prepareLoading, { setTrue: startPrepare, setFalse: prepareFinish }] = useBoolean(); const [form] = useForm(); - const fileChange = (currentFile: RcFile) => { startPrepare(); Configuration.CheckLicense({ @@ -56,7 +50,6 @@ const ImportLicenseModal = () => { }); return false; }; - const close = () => { form.resetFields(); dispatch( @@ -66,10 +59,8 @@ const ImportLicenseModal = () => { }) ); }; - const [importLoading, { setTrue: startImport, setFalse: importFinish }] = useBoolean(); - const submit = async () => { const values = await form.validateFields(); startImport(); @@ -86,7 +77,6 @@ const ImportLicenseModal = () => { importFinish(); } }; - return ( { ); }; - export default ImportLicenseModal; diff --git a/packages/base/src/page/System/License/action.tsx b/packages/base/src/page/System/License/action.tsx index 98386e3d5..a4e75a080 100644 --- a/packages/base/src/page/System/License/action.tsx +++ b/packages/base/src/page/System/License/action.tsx @@ -1,11 +1,11 @@ -import { ActionButton, BasicTooltipProps } from '@actiontech/shared'; +import { ActionButton } from '@actiontech/shared'; +import { BasicTooltipProps } from '@actiontech/dms-kit'; import { PERMISSIONS, PermissionControl } from '@actiontech/shared/lib/features'; import { ReactNode } from 'react'; import { t } from '../../../locale'; - type Params = { collectActionTooltipProps: BasicTooltipProps; collectAction: { @@ -16,7 +16,6 @@ type Params = { onClick: () => void; }; }; - export const LicenseActions = ( params: Params ): Record<'collect_license' | 'import_license', ReactNode> => { diff --git a/packages/base/src/page/System/License/index.data.tsx b/packages/base/src/page/System/License/index.data.tsx index d6aaf2669..7d641f17b 100644 --- a/packages/base/src/page/System/License/index.data.tsx +++ b/packages/base/src/page/System/License/index.data.tsx @@ -1,4 +1,4 @@ -import { ActiontechTableColumn } from '@actiontech/shared/lib/components/ActiontechTable'; +import { ActiontechTableColumn } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { t } from '../../../locale'; import { ILicenseItem } from '@actiontech/shared/lib/api/base/service/common'; import { BasicTypographyEllipsis } from '@actiontech/shared'; diff --git a/packages/base/src/page/System/License/index.tsx b/packages/base/src/page/System/License/index.tsx index b94f235e3..028572b00 100644 --- a/packages/base/src/page/System/License/index.tsx +++ b/packages/base/src/page/System/License/index.tsx @@ -11,10 +11,10 @@ import { ModalName } from '../../../data/ModalName'; import SystemBasicTitle from '../components/BasicTitle'; import ImportLicense from './Modal/ImportLicense'; import { LicenseColumn } from './index.data'; -import { ActiontechTable } from '@actiontech/shared/lib/components/ActiontechTable'; +import { ActiontechTable } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { LicenseActions } from './action'; import { useCurrentUser } from '@actiontech/shared/lib/features'; -import { DEFAULT_LANGUAGE } from '@actiontech/shared/lib/locale'; +import { DEFAULT_LANGUAGE } from '@actiontech/dms-kit'; const License = () => { const { t } = useTranslation(); diff --git a/packages/base/src/page/System/LoginConnection/LDAPSetting/components/ConfigField.tsx b/packages/base/src/page/System/LoginConnection/LDAPSetting/components/ConfigField.tsx index bf73c8c39..7765e056d 100644 --- a/packages/base/src/page/System/LoginConnection/LDAPSetting/components/ConfigField.tsx +++ b/packages/base/src/page/System/LoginConnection/LDAPSetting/components/ConfigField.tsx @@ -1,12 +1,8 @@ import { useTranslation } from 'react-i18next'; -import { BasicInput, BasicSwitch } from '@actiontech/shared'; -import { - CustomLabelContent, - FormItemLabel -} from '@actiontech/shared/lib/components/CustomForm'; -import { validatorPort } from '@actiontech/shared/lib/utils/FormRule'; +import { BasicInput, BasicSwitch } from '@actiontech/dms-kit'; +import { CustomLabelContent, FormItemLabel } from '@actiontech/dms-kit'; +import { validatorPort } from '@actiontech/dms-kit'; import { Form } from 'antd'; - const ConfigField = () => { const { t } = useTranslation(); const updatePassword = Form.useWatch('update_password'); @@ -17,7 +13,11 @@ const ConfigField = () => { name="enable_ssl" valuePropName="checked" className="has-required-style" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > @@ -25,7 +25,11 @@ const ConfigField = () => { label={t('dmsSystem.ldap.ldapServerHost')} name="ldap_server_host" className="has-required-style" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > { label={t('dmsSystem.ldap.ldapConnectPwd')} name="ldap_connect_pwd" className="has-required-style" - rules={[{ required: updatePassword }]} + rules={[ + { + required: updatePassword + } + ]} hidden={!updatePassword} > { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/LoginConnection/LDAPSetting/index.tsx b/packages/base/src/page/System/LoginConnection/LDAPSetting/index.tsx index 465f404e1..34cc31f14 100644 --- a/packages/base/src/page/System/LoginConnection/LDAPSetting/index.tsx +++ b/packages/base/src/page/System/LoginConnection/LDAPSetting/index.tsx @@ -10,11 +10,11 @@ import { useConfigRender, useConfigSwitchControls, ReadOnlyConfigColumnsType -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import ConfigField from './components/ConfigField'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; import { LDAPFormFields } from './index.type'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { ILDAPConfiguration, ILDAPConfigurationResData diff --git a/packages/base/src/page/System/LoginConnection/LoginBasicSetting/index.tsx b/packages/base/src/page/System/LoginConnection/LoginBasicSetting/index.tsx index 1e41b9c8b..4f541820b 100644 --- a/packages/base/src/page/System/LoginConnection/LoginBasicSetting/index.tsx +++ b/packages/base/src/page/System/LoginConnection/LoginBasicSetting/index.tsx @@ -1,19 +1,13 @@ import { Popconfirm, Spin } from 'antd'; import { useTranslation } from 'react-i18next'; -import { - BasicSwitch, - BasicToolTip, - ConfigItem, - EditInput, - LabelContent -} from '@actiontech/shared'; +import { BasicSwitch, BasicToolTip, ConfigItem } from '@actiontech/dms-kit'; +import { EditInput, LabelContent } from '@actiontech/dms-kit'; import { useState } from 'react'; import { useLoginConnectionContext } from '../context'; import { useBoolean, useRequest } from 'ahooks'; import { DmsApi } from '@actiontech/shared/lib/api'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { ILoginConfiguration } from '@actiontech/shared/lib/api/base/service/common'; - const LoginBasicSetting: React.FC = () => { const { t } = useTranslation(); const { isLDAPEnabled, isOAuthEnabled } = useLoginConnectionContext(); @@ -23,7 +17,6 @@ const LoginBasicSetting: React.FC = () => { isLoginButtonEditing, { setTrue: startEditing, setFalse: finishEditing } ] = useBoolean(); - const updateLoginConfig = async ( value: string | boolean, configKey: keyof ILoginConfiguration @@ -40,7 +33,6 @@ const LoginBasicSetting: React.FC = () => { } } }; - const { loading, refresh } = useRequest(() => DmsApi.ConfigurationService.GetLoginTips().then((res) => { if (res.data.code === ResponseCode.SUCCESS) { @@ -49,7 +41,6 @@ const LoginBasicSetting: React.FC = () => { } }) ); - const renderPasswordLoginSwitch = () => { if (!isOAuthEnabled) { return ( @@ -61,13 +52,11 @@ const LoginBasicSetting: React.FC = () => { ); } - const confirmTitle = isPasswordLoginDisabled ? t('dmsSystem.loginBasic.confirmDisable') : isLDAPEnabled ? t('dmsSystem.loginBasic.confirmEnableWithLDAP') : t('dmsSystem.loginBasic.confirmEnable'); - return ( { ); }; - return ( { ); }; - export default LoginBasicSetting; diff --git a/packages/base/src/page/System/LoginConnection/Oauth/components/ConfigField.tsx b/packages/base/src/page/System/LoginConnection/Oauth/components/ConfigField.tsx index 8a3ab1a96..6b4f4f7f5 100644 --- a/packages/base/src/page/System/LoginConnection/Oauth/components/ConfigField.tsx +++ b/packages/base/src/page/System/LoginConnection/Oauth/components/ConfigField.tsx @@ -1,17 +1,10 @@ import { useTranslation } from 'react-i18next'; - -import { BasicInput, BasicSwitch, EmptyBox } from '@actiontech/shared'; -import { - FormItemLabel, - CustomLabelContent -} from '@actiontech/shared/lib/components/CustomForm'; +import { BasicInput, BasicSwitch, EmptyBox } from '@actiontech/dms-kit'; +import { FormItemLabel, CustomLabelContent } from '@actiontech/dms-kit'; import { Form } from 'antd'; - const ConfigField = () => { const { t } = useTranslation(); - const autoCreateUser = Form.useWatch('autoCreateUser'); - return ( <> { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/LoginConnection/Oauth/index.tsx b/packages/base/src/page/System/LoginConnection/Oauth/index.tsx index 7d30c4a6c..90d60e177 100644 --- a/packages/base/src/page/System/LoginConnection/Oauth/index.tsx +++ b/packages/base/src/page/System/LoginConnection/Oauth/index.tsx @@ -2,11 +2,8 @@ import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useBoolean, useRequest } from 'ahooks'; import { Form, Space, Spin, Tag, Typography } from 'antd'; -import { - BasicToolTip, - EmptyBox, - EnterpriseFeatureDisplay -} from '@actiontech/shared'; +import { BasicToolTip, EmptyBox } from '@actiontech/dms-kit'; +import { EnterpriseFeatureDisplay } from '@actiontech/shared'; import { ConfigSwitch, ConfigModifyBtn, @@ -14,11 +11,11 @@ import { useConfigRender, useConfigSwitchControls, ReadOnlyConfigColumnsType -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import ConfigField from './components/ConfigField'; import { switchFieldName } from './index.data'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { OauthFormField } from './index.type'; import { IGetOauth2ConfigurationResData, @@ -32,7 +29,6 @@ import { PermissionControl } from '@actiontech/shared/lib/features'; import { useLoginConnectionContext } from '../context'; - const Oauth = () => { const { t } = useTranslation(); const { baseTheme } = useThemeStyleData(); @@ -71,11 +67,9 @@ const Oauth = () => { // #endif } ); - const isConfigClosed = useMemo(() => { return !oauthConfig?.enable_oauth2; }, [oauthConfig]); - const handleClickCancel = () => { if (isConfigClosed) form.setFieldValue(switchFieldName, false); setFormDefaultValue(); @@ -85,7 +79,6 @@ const Oauth = () => { setFormDefaultValue(); startModify(); }; - const [submitLoading, { setTrue: startSubmit, setFalse: submitFinish }] = useBoolean(); const handleSubmit = async (value: OauthFormField) => { @@ -111,15 +104,12 @@ const Oauth = () => { auto_bind_same_name_user: value.autoBindSameNameUser, enable_manually_bind: value.enableManuallyBind }; - if (!!value.scopes) { configuration.scopes = value.scopes.split(','); } - const params: IUpdateOauth2ConfigurationParams = { oauth2: configuration }; - try { const res = await Configuration.UpdateOauth2Configuration(params); if (res.data.code === ResponseCode.SUCCESS) { @@ -131,7 +121,6 @@ const Oauth = () => { submitFinish(); } }; - const setFormDefaultValue = useCallback(() => { form.setFieldsValue({ clientId: oauthConfig?.client_id, @@ -155,9 +144,7 @@ const Oauth = () => { enableManuallyBind: oauthConfig?.enable_manually_bind }); }, [form, oauthConfig]); - const switchOpen = Form.useWatch(switchFieldName, form); - const { configSwitchPopoverOpenState, generateConfigSwitchPopoverTitle, @@ -165,7 +152,6 @@ const Oauth = () => { handleConfigSwitchChange, hiddenConfigSwitchPopover } = useConfigSwitchControls(form, switchFieldName); - const onConfigSwitchPopoverConfirm = async () => { if (isConfigClosed && modifyFlag) { handleClickCancel(); @@ -190,7 +176,6 @@ const Oauth = () => { } } }; - const readonlyColumnsConfig: ReadOnlyConfigColumnsType = useMemo(() => { return [ @@ -273,7 +258,6 @@ const Oauth = () => { span: 3, dataIndex: 'scopes', hidden: !oauthConfig?.enable_oauth2, - render: (val) => { const scopes = val as string[]; return ( @@ -382,7 +366,6 @@ const Oauth = () => { dataIndex: 'login_perm_expr', hidden: !oauthConfig?.enable_oauth2 }, - { label: ( { } ]; }, [oauthConfig?.enable_oauth2, t, baseTheme]); - return (
@@ -538,5 +520,4 @@ const Oauth = () => {
); }; - export default Oauth; diff --git a/packages/base/src/page/System/LoginConnection/SMSSetting/__tests__/index.test.tsx b/packages/base/src/page/System/LoginConnection/SMSSetting/__tests__/index.test.tsx index e691fc8e8..1642f6d93 100644 --- a/packages/base/src/page/System/LoginConnection/SMSSetting/__tests__/index.test.tsx +++ b/packages/base/src/page/System/LoginConnection/SMSSetting/__tests__/index.test.tsx @@ -6,7 +6,7 @@ import { getBySelector } from '@actiontech/shared/lib/testUtil/customQuery'; import SMSSetting from '..'; import { createSpySuccessResponse } from '@actiontech/shared/lib/testUtil/mockApi'; import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser'; -import { SystemRole } from '@actiontech/shared/lib/enum'; +import { SystemRole } from '@actiontech/dms-kit'; describe('base/System/GlobalSetting/SMSSetting', () => { let getSmsConfigurationSpy: jest.SpyInstance; diff --git a/packages/base/src/page/System/LoginConnection/SMSSetting/components/ConfigExtraButtons.tsx b/packages/base/src/page/System/LoginConnection/SMSSetting/components/ConfigExtraButtons.tsx index e0ad64860..1caa31c5e 100644 --- a/packages/base/src/page/System/LoginConnection/SMSSetting/components/ConfigExtraButtons.tsx +++ b/packages/base/src/page/System/LoginConnection/SMSSetting/components/ConfigExtraButtons.tsx @@ -1,24 +1,22 @@ import { useTranslation } from 'react-i18next'; import { Space, Form, message } from 'antd'; -import { BasicInput } from '@actiontech/shared'; -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; +import { BasicInput } from '@actiontech/dms-kit'; +import { FormItemLabel } from '@actiontech/dms-kit'; import { useRef, useState } from 'react'; import baseConfiguration from '@actiontech/shared/lib/api/base/service/Configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; -import { formItemLayout } from '@actiontech/shared/lib/components/CustomForm/style'; +import { ResponseCode } from '@actiontech/dms-kit'; +import { formItemLayout } from '@actiontech/dms-kit/es/components/CustomForm/style'; import { ConfigModifyBtn, ConfigTestBtn, ConfigTestPopoverForm -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; - +} from '@actiontech/dms-kit'; export interface ConfigExtraButtonsProps { isConfigClosed: boolean; extraButtonsVisible: boolean; handleClickModify: () => void; enabled: boolean; } - const ConfigExtraButtons = ({ isConfigClosed, extraButtonsVisible, @@ -26,20 +24,17 @@ const ConfigExtraButtons = ({ enabled }: ConfigExtraButtonsProps) => { const { t } = useTranslation(); - const [messageApi, messageContextHolder] = message.useMessage(); - - const [testForm] = Form.useForm<{ phone: string }>(); - + const [testForm] = Form.useForm<{ + phone: string; + }>(); const testing = useRef(false); const [testPopoverVisible, toggleTestPopoverVisible] = useState(false); - const testCodingConfiguration = async () => { if (testing.current) { return; } const values = await testForm.validateFields(); - testing.current = true; toggleTestPopoverVisible(false); const hide = messageApi.loading( @@ -69,7 +64,6 @@ const ConfigExtraButtons = ({ testForm.resetFields(); }); }; - const onTestPopoverOpen = (open: boolean) => { if (!enabled) { return; @@ -79,7 +73,6 @@ const ConfigExtraButtons = ({ } toggleTestPopoverVisible(open); }; - return ( <> {messageContextHolder} @@ -99,8 +92,14 @@ const ConfigExtraButtons = ({ ); }; - export default ConfigExtraButtons; diff --git a/packages/base/src/page/System/LoginConnection/SMSSetting/components/ConfigField.tsx b/packages/base/src/page/System/LoginConnection/SMSSetting/components/ConfigField.tsx index f4b00baa3..8b696b78e 100644 --- a/packages/base/src/page/System/LoginConnection/SMSSetting/components/ConfigField.tsx +++ b/packages/base/src/page/System/LoginConnection/SMSSetting/components/ConfigField.tsx @@ -1,14 +1,8 @@ import { useTranslation } from 'react-i18next'; - -import { - CustomLabelContent, - FormItemLabel -} from '@actiontech/shared/lib/components/CustomForm'; -import { BasicInput } from '@actiontech/shared'; - +import { CustomLabelContent, FormItemLabel } from '@actiontech/dms-kit'; +import { BasicInput } from '@actiontech/dms-kit'; const ConfigField = () => { const { t } = useTranslation(); - return ( <> { /> } name="url" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > { /> } name="token" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/LoginConnection/SMSSetting/index.tsx b/packages/base/src/page/System/LoginConnection/SMSSetting/index.tsx index bf1300760..53bf386cd 100644 --- a/packages/base/src/page/System/LoginConnection/SMSSetting/index.tsx +++ b/packages/base/src/page/System/LoginConnection/SMSSetting/index.tsx @@ -6,7 +6,7 @@ import ConfigExtraButtons from './components/ConfigExtraButtons'; import ConfigField from './components/ConfigField'; import { DmsApi } from '@actiontech/shared/lib/api'; import { IGetSmsConfigurationReplyItem } from '@actiontech/shared/lib/api/base/service/common'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { FormFields } from './index.type'; import { switchFieldName } from './index.data'; import { @@ -16,7 +16,7 @@ import { ConfigSubmitButtonField, useConfigSwitchControls, CustomLabelContent -} from '@actiontech/shared'; +} from '@actiontech/dms-kit'; import { PERMISSIONS, PermissionControl diff --git a/packages/base/src/page/System/PersonalizeSetting/index.test.tsx b/packages/base/src/page/System/PersonalizeSetting/index.test.tsx index c4881a273..c73f528a7 100644 --- a/packages/base/src/page/System/PersonalizeSetting/index.test.tsx +++ b/packages/base/src/page/System/PersonalizeSetting/index.test.tsx @@ -9,7 +9,7 @@ import { getBySelector } from '@actiontech/shared/lib/testUtil/customQuery'; import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser'; -import { SystemRole } from '@actiontech/shared/lib/enum'; +import { SystemRole } from '@actiontech/dms-kit'; describe('base/System/PersonalizeSetting', () => { let requestGetBasicInfo: jest.SpyInstance; diff --git a/packages/base/src/page/System/PersonalizeSetting/index.tsx b/packages/base/src/page/System/PersonalizeSetting/index.tsx index 63ab9107a..e0332a138 100644 --- a/packages/base/src/page/System/PersonalizeSetting/index.tsx +++ b/packages/base/src/page/System/PersonalizeSetting/index.tsx @@ -2,47 +2,45 @@ import { useBoolean, useRequest } from 'ahooks'; import { useTranslation } from 'react-i18next'; import { useMemo } from 'react'; import { Spin } from 'antd'; -import { ConfigItem } from '@actiontech/shared'; +import { ConfigItem } from '@actiontech/dms-kit'; import { ConfigFieldMapMeta, EditInput, ImageUploader, LabelContent -} from '@actiontech/shared/lib/components/ConfigItem'; +} from '@actiontech/dms-kit'; import SystemBasicTitle from '../components/BasicTitle'; - import { DMS_DEFAULT_WEB_LOGO_URL, DMS_DEFAULT_WEB_TITLE -} from '@actiontech/shared/lib/data/common'; -import useHideConfigInputNode from '@actiontech/shared/lib/components/ConfigItem/hooks/useHideConfigInputNode'; +} from '@actiontech/dms-kit'; +import useHideConfigInputNode from '@actiontech/dms-kit/es/components/ConfigItem/hooks/useHideConfigInputNode'; import useSystemConfig from '../../../hooks/useSystemConfig'; import BasicInfo from '@actiontech/shared/lib/api/base/service/BasicInfo'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { IPersonalizationParams } from '@actiontech/shared/lib/api/base/service/BasicInfo/index.d'; import { PERMISSIONS, usePermission } from '@actiontech/shared/lib/features'; - const PersonalizeSetting: React.FC = () => { const { t } = useTranslation(); - const { checkActionPermission } = usePermission(); const [ titleFieldVisible, { setTrue: showTitleField, setFalse: hideTitleField } ] = useBoolean(false); - const fieldMetaMap = new Map< keyof IPersonalizationParams, ConfigFieldMapMeta >([ - ['title', { hideField: hideTitleField }], + [ + 'title', + { + hideField: hideTitleField + } + ], ['file', {}] ]); - useHideConfigInputNode(titleFieldVisible, hideTitleField); - const { syncWebTitleAndLogo } = useSystemConfig(); - const { data: basicInfo, loading, @@ -51,18 +49,14 @@ const PersonalizeSetting: React.FC = () => { BasicInfo.GetBasicInfo().then((res) => { const basicInfoRes = res.data.data; if (basicInfoRes) syncWebTitleAndLogo(basicInfoRes); - return basicInfoRes ?? {}; }) ); - const webTitleInPage = useMemo(() => { return !!basicInfo?.title ? basicInfo.title : DMS_DEFAULT_WEB_TITLE; }, [basicInfo]); - const [submitLoading, { setTrue: startSubmit, setFalse: submitFinish }] = useBoolean(); - const submitPersonalize = ( value: string | File, fieldName: keyof IPersonalizationParams @@ -88,7 +82,6 @@ const PersonalizeSetting: React.FC = () => { submitFinish(); }); }; - return ( @@ -145,5 +138,4 @@ const PersonalizeSetting: React.FC = () => { ); }; - export default PersonalizeSetting; diff --git a/packages/base/src/page/System/ProcessConnection/CodingSetting/__tests__/index.test.tsx b/packages/base/src/page/System/ProcessConnection/CodingSetting/__tests__/index.test.tsx index 645ae32f7..974145d86 100644 --- a/packages/base/src/page/System/ProcessConnection/CodingSetting/__tests__/index.test.tsx +++ b/packages/base/src/page/System/ProcessConnection/CodingSetting/__tests__/index.test.tsx @@ -6,7 +6,7 @@ import { getBySelector } from '@actiontech/shared/lib/testUtil/customQuery'; import CodingSetting from '..'; import { createSpySuccessResponse } from '@actiontech/shared/lib/testUtil/mockApi'; import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser'; -import { SystemRole } from '@actiontech/shared/lib/enum'; +import { SystemRole } from '@actiontech/dms-kit'; describe('base/System/ProcessConnection/CodingSetting', () => { let getCodingConfigurationSpy: jest.SpyInstance; diff --git a/packages/base/src/page/System/ProcessConnection/CodingSetting/components/ConfigExtraButtons.tsx b/packages/base/src/page/System/ProcessConnection/CodingSetting/components/ConfigExtraButtons.tsx index f7fe554d8..395893176 100644 --- a/packages/base/src/page/System/ProcessConnection/CodingSetting/components/ConfigExtraButtons.tsx +++ b/packages/base/src/page/System/ProcessConnection/CodingSetting/components/ConfigExtraButtons.tsx @@ -1,24 +1,22 @@ import { useTranslation } from 'react-i18next'; import { Space, Form, message } from 'antd'; -import { BasicInput } from '@actiontech/shared'; -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; +import { BasicInput } from '@actiontech/dms-kit'; +import { FormItemLabel } from '@actiontech/dms-kit'; import { useRef, useState } from 'react'; import configuration from '@actiontech/shared/lib/api/sqle/service/configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; -import { formItemLayout } from '@actiontech/shared/lib/components/CustomForm/style'; +import { ResponseCode } from '@actiontech/dms-kit'; +import { formItemLayout } from '@actiontech/dms-kit/es/components/CustomForm/style'; import { ConfigModifyBtn, ConfigTestBtn, ConfigTestPopoverForm -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; - +} from '@actiontech/dms-kit'; export interface ConfigExtraButtonsProps { isConfigClosed: boolean; extraButtonsVisible: boolean; handleClickModify: () => void; enabled: boolean; } - const ConfigExtraButtons = ({ isConfigClosed, extraButtonsVisible, @@ -26,25 +24,22 @@ const ConfigExtraButtons = ({ enabled }: ConfigExtraButtonsProps) => { const { t } = useTranslation(); - const [messageApi, messageContextHolder] = message.useMessage(); - const [testForm] = Form.useForm(); - const testing = useRef(false); const [testPopoverVisible, toggleTestPopoverVisible] = useState(false); - const testCodingConfiguration = async () => { if (testing.current) { return; } const values = await testForm.validateFields(); - testing.current = true; toggleTestPopoverVisible(false); const hide = messageApi.loading(t('dmsSystem.codingDocking.testing'), 0); configuration - .testCodingConfigV1({ coding_project_name: values.codingProjectName }) + .testCodingConfigV1({ + coding_project_name: values.codingProjectName + }) .then((res) => { if (res.data.code === ResponseCode.SUCCESS) { if (res.data.data?.is_message_sent_normally) { @@ -62,7 +57,6 @@ const ConfigExtraButtons = ({ testForm.resetFields(); }); }; - const onTestPopoverOpen = (open: boolean) => { if (!enabled) { return; @@ -72,7 +66,6 @@ const ConfigExtraButtons = ({ } toggleTestPopoverVisible(open); }; - return ( <> {messageContextHolder} @@ -92,8 +85,14 @@ const ConfigExtraButtons = ({ ); }; - export default ConfigExtraButtons; diff --git a/packages/base/src/page/System/ProcessConnection/CodingSetting/components/ConfigField.tsx b/packages/base/src/page/System/ProcessConnection/CodingSetting/components/ConfigField.tsx index e9b28d086..95005a5c7 100644 --- a/packages/base/src/page/System/ProcessConnection/CodingSetting/components/ConfigField.tsx +++ b/packages/base/src/page/System/ProcessConnection/CodingSetting/components/ConfigField.tsx @@ -1,18 +1,19 @@ import { useTranslation } from 'react-i18next'; - -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; -import { BasicInput } from '@actiontech/shared'; - +import { FormItemLabel } from '@actiontech/dms-kit'; +import { BasicInput } from '@actiontech/dms-kit'; const ConfigField = () => { const { t } = useTranslation(); - return ( <> { className="has-required-style" label={t('dmsSystem.codingDocking.accessToken')} name="token" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/ProcessConnection/CodingSetting/index.tsx b/packages/base/src/page/System/ProcessConnection/CodingSetting/index.tsx index 5cd0fe061..23a20ed1a 100644 --- a/packages/base/src/page/System/ProcessConnection/CodingSetting/index.tsx +++ b/packages/base/src/page/System/ProcessConnection/CodingSetting/index.tsx @@ -2,12 +2,12 @@ import { useTranslation } from 'react-i18next'; import { useBoolean, useRequest } from 'ahooks'; import { useCallback, useMemo } from 'react'; import { Form, Spin, Typography } from 'antd'; -import { CustomLabelContent } from '@actiontech/shared/lib/components/CustomForm'; +import { CustomLabelContent } from '@actiontech/dms-kit'; import ConfigExtraButtons from './components/ConfigExtraButtons'; import ConfigField from './components/ConfigField'; import configuration from '@actiontech/shared/lib/api/sqle/service/configuration'; import { ICodingConfigurationV1 } from '@actiontech/shared/lib/api/sqle/service/common'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { FormFields } from './index.type'; import { switchFieldName } from './index.data'; import { @@ -20,7 +20,7 @@ import { ConfigSwitch, ConfigSubmitButtonField, useConfigSwitchControls -} from '@actiontech/shared'; +} from '@actiontech/dms-kit'; const CodingSetting: React.FC = () => { const { t } = useTranslation(); diff --git a/packages/base/src/page/System/ProcessConnection/DingTalkSetting/components/ConfigExtraButtons.tsx b/packages/base/src/page/System/ProcessConnection/DingTalkSetting/components/ConfigExtraButtons.tsx index 6f73baa04..0bff9198b 100644 --- a/packages/base/src/page/System/ProcessConnection/DingTalkSetting/components/ConfigExtraButtons.tsx +++ b/packages/base/src/page/System/ProcessConnection/DingTalkSetting/components/ConfigExtraButtons.tsx @@ -1,20 +1,16 @@ import { useTranslation } from 'react-i18next'; import { useRef } from 'react'; - import { message, Space } from 'antd'; -import { BasicToolTip, BasicButton } from '@actiontech/shared'; -import { ConfigModifyBtn } from '@actiontech/shared/lib/components/SystemConfigurationHub'; - +import { BasicToolTip, BasicButton } from '@actiontech/dms-kit'; +import { ConfigModifyBtn } from '@actiontech/dms-kit'; import configuration from '@actiontech/shared/lib/api/sqle/service/configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { ThunderBoltFilled } from '@actiontech/icons'; - export interface ConfigExtraButtonsProps { isConfigClosed: boolean; extraButtonsVisible: boolean; handleClickModify: () => void; } - const ConfigExtraButtons = ({ isConfigClosed, extraButtonsVisible, @@ -22,7 +18,6 @@ const ConfigExtraButtons = ({ }: ConfigExtraButtonsProps) => { const { t } = useTranslation(); const [messageApi, messageContextHolder] = message.useMessage(); - const testTing = useRef(false); const testDingTalkConfiguration = () => { if (testTing.current) { @@ -46,7 +41,6 @@ const ConfigExtraButtons = ({ testTing.current = false; }); }; - return ( <> {messageContextHolder} @@ -66,5 +60,4 @@ const ConfigExtraButtons = ({ ); }; - export default ConfigExtraButtons; diff --git a/packages/base/src/page/System/ProcessConnection/DingTalkSetting/components/ConfigField.tsx b/packages/base/src/page/System/ProcessConnection/DingTalkSetting/components/ConfigField.tsx index 2d0bfe9c5..83f18bf91 100644 --- a/packages/base/src/page/System/ProcessConnection/DingTalkSetting/components/ConfigField.tsx +++ b/packages/base/src/page/System/ProcessConnection/DingTalkSetting/components/ConfigField.tsx @@ -1,18 +1,19 @@ import { useTranslation } from 'react-i18next'; - -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; -import { BasicInput } from '@actiontech/shared'; - +import { FormItemLabel } from '@actiontech/dms-kit'; +import { BasicInput } from '@actiontech/dms-kit'; const ConfigField = () => { const { t } = useTranslation(); - return ( <> { className="has-required-style" label="AppSecret" name="appSecret" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/ProcessConnection/DingTalkSetting/index.tsx b/packages/base/src/page/System/ProcessConnection/DingTalkSetting/index.tsx index 4263da11b..d3be5b6a1 100644 --- a/packages/base/src/page/System/ProcessConnection/DingTalkSetting/index.tsx +++ b/packages/base/src/page/System/ProcessConnection/DingTalkSetting/index.tsx @@ -2,19 +2,19 @@ import { useTranslation } from 'react-i18next'; import { useBoolean, useRequest } from 'ahooks'; import { useCallback, useMemo } from 'react'; import { Form, Spin, Typography } from 'antd'; -import { CustomLabelContent } from '@actiontech/shared/lib/components/CustomForm'; +import { CustomLabelContent } from '@actiontech/dms-kit'; import { ConfigSwitch, ConfigSubmitButtonField, useConfigRender, useConfigSwitchControls, ReadOnlyConfigColumnsType -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import ConfigField from './components/ConfigField'; import ConfigExtraButtons from './components/ConfigExtraButtons'; import configuration from '@actiontech/shared/lib/api/sqle/service/configuration'; import { IDingTalkConfigurationV1 } from '@actiontech/shared/lib/api/sqle/service/common'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { FormFields } from './index.type'; import { defaultFormData, switchFieldName } from './index.data'; import { diff --git a/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/components/ConfigExtraButtons.tsx b/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/components/ConfigExtraButtons.tsx index b5e329998..c4b38cc04 100644 --- a/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/components/ConfigExtraButtons.tsx +++ b/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/components/ConfigExtraButtons.tsx @@ -7,31 +7,25 @@ import { RadioGroupProps, Space } from 'antd'; -import { formItemLayout } from '@actiontech/shared/lib/components/CustomForm/style'; -import { - FormItemLabel, - FormItemNoLabel -} from '@actiontech/shared/lib/components/CustomForm'; -import { BasicInput, EmptyBox } from '@actiontech/shared'; -import { phoneRule } from '@actiontech/shared/lib/utils/FormRule'; +import { formItemLayout } from '@actiontech/dms-kit/es/components/CustomForm/style'; +import { FormItemLabel, FormItemNoLabel } from '@actiontech/dms-kit'; +import { BasicInput, EmptyBox } from '@actiontech/dms-kit'; +import { phoneRule } from '@actiontech/dms-kit'; import { ConfigModifyBtn, ConfigTestBtn, ConfigTestPopoverForm -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; - +} from '@actiontech/dms-kit'; import configuration from '@actiontech/shared/lib/api/sqle/service/configuration'; import { TestFeishuConfigurationReqV1AccountTypeEnum } from '@actiontech/shared/lib/api/sqle/service/common.enum'; import { TestFormFields } from '../index.type'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; - +import { ResponseCode } from '@actiontech/dms-kit'; export interface ConfigExtraButtonsProps { isConfigClosed: boolean; extraButtonsVisible: boolean; enabled: string | boolean; handleClickModify: () => void; } - const ConfigExtraButtons = ({ isConfigClosed, extraButtonsVisible, @@ -40,7 +34,6 @@ const ConfigExtraButtons = ({ }: ConfigExtraButtonsProps) => { const { t } = useTranslation(); const [message, messageContextHolder] = messageApi.useMessage(); - const [testForm] = Form.useForm(); const [testPopoverVisible, toggleTestPopoverVisible] = useState(false); const [receiveType, setReceiveType] = @@ -48,17 +41,14 @@ const ConfigExtraButtons = ({ TestFeishuConfigurationReqV1AccountTypeEnum.email ); const testing = useRef(false); - const testLarkAuditConfiguration = async () => { if (testing.current) { return; } const values = await testForm.validateFields(); - testing.current = true; toggleTestPopoverVisible(false); const hide = message.loading(t('dmsSystem.larkAudit.testing'), 0); - configuration .testFeishuAuditConfigV1({ account: @@ -84,18 +74,15 @@ const ConfigExtraButtons = ({ setReceiveType(TestFeishuConfigurationReqV1AccountTypeEnum.email); }); }; - const handleChangeReceiveType: RadioGroupProps['onChange'] = (e) => { const type = e.target.value; setReceiveType(type); - if (type === TestFeishuConfigurationReqV1AccountTypeEnum.email) { testForm.resetFields(['receivePhone']); } else { testForm.resetFields(['receiveEmail']); } }; - const onTestPopoverOpen = (open: boolean) => { if (!enabled) { return; @@ -106,7 +93,6 @@ const ConfigExtraButtons = ({ } toggleTestPopoverVisible(open); }; - return ( <> {messageContextHolder} @@ -129,7 +115,9 @@ const ConfigExtraButtons = ({ initialValue={ TestFeishuConfigurationReqV1AccountTypeEnum.email } - style={{ marginBottom: 0 }} + style={{ + marginBottom: 0 + }} > ); }; - export default ConfigExtraButtons; diff --git a/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/components/ConfigField.tsx b/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/components/ConfigField.tsx index d102a0dbb..55b2d76a2 100644 --- a/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/components/ConfigField.tsx +++ b/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/components/ConfigField.tsx @@ -1,7 +1,6 @@ import { useTranslation } from 'react-i18next'; -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; -import { BasicInput } from '@actiontech/shared'; - +import { FormItemLabel } from '@actiontech/dms-kit'; +import { BasicInput } from '@actiontech/dms-kit'; const ConfigField = () => { const { t } = useTranslation(); return ( @@ -10,7 +9,11 @@ const ConfigField = () => { className="has-required-style" label="App ID" name="appKey" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > { className="has-required-style" label="App Secret" name="appSecret" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/index.ee.tsx b/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/index.ee.tsx index db0c55a16..27f4b1b79 100644 --- a/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/index.ee.tsx +++ b/packages/base/src/page/System/ProcessConnection/LarkAuditSetting/index.ee.tsx @@ -8,14 +8,14 @@ import { useConfigRender, useConfigSwitchControls, ReadOnlyConfigColumnsType -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import ConfigExtraButtons from './components/ConfigExtraButtons'; import ConfigField from './components/ConfigField'; -import { CustomLabelContent } from '@actiontech/shared/lib/components/CustomForm'; +import { CustomLabelContent } from '@actiontech/dms-kit'; import configuration from '@actiontech/shared/lib/api/sqle/service/configuration'; import { FormFields } from './index.type'; import { defaultFormData, switchFieldName } from './index.data'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { IFeishuConfigurationV1 } from '@actiontech/shared/lib/api/sqle/service/common'; import { PERMISSIONS, diff --git a/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/components/ConfigExtraButtons.tsx b/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/components/ConfigExtraButtons.tsx index 0ec97757f..19eb5b97f 100644 --- a/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/components/ConfigExtraButtons.tsx +++ b/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/components/ConfigExtraButtons.tsx @@ -1,25 +1,23 @@ import { useTranslation } from 'react-i18next'; import { useRef, useState } from 'react'; import { Form, message, Space } from 'antd'; -import { BasicInput } from '@actiontech/shared'; +import { BasicInput } from '@actiontech/dms-kit'; import { ConfigModifyBtn, ConfigTestBtn, ConfigTestPopoverForm -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import configuration from '@actiontech/shared/lib/api/sqle/service/configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { TestFormFields } from '../index.type'; -import { formItemLayout } from '@actiontech/shared/lib/components/CustomForm/style'; -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; - +import { formItemLayout } from '@actiontech/dms-kit/es/components/CustomForm/style'; +import { FormItemLabel } from '@actiontech/dms-kit'; export interface ConfigExtraButtonsProps { isConfigClosed: boolean; extraButtonsVisible: boolean; handleClickModify: () => void; enabled: boolean; } - const ConfigExtraButtons = ({ isConfigClosed, extraButtonsVisible, @@ -29,22 +27,20 @@ const ConfigExtraButtons = ({ const { t } = useTranslation(); const [messageApi, messageContextHolder] = message.useMessage(); const [testForm] = Form.useForm(); - const testing = useRef(false); const [testPopoverVisible, toggleTestPopoverVisible] = useState(false); - const testWechatAuditConfiguration = async () => { if (testing.current) { return; } const values = await testForm.validateFields(); - testing.current = true; toggleTestPopoverVisible(false); const hide = messageApi.loading(t('dmsSystem.wechatAudit.testing'), 0); - configuration - .testWechatAuditConfigV1({ wechat_id: values.wechatUserID }) + .testWechatAuditConfigV1({ + wechat_id: values.wechatUserID + }) .then((res) => { if (res.data.code === ResponseCode.SUCCESS) { if (res.data.data?.is_message_sent_normally) { @@ -62,7 +58,6 @@ const ConfigExtraButtons = ({ testForm.resetFields(); }); }; - const onTestPopoverOpen = (open: boolean) => { if (!enabled) { return; @@ -72,7 +67,6 @@ const ConfigExtraButtons = ({ } toggleTestPopoverVisible(open); }; - return ( <> {messageContextHolder} @@ -92,8 +86,14 @@ const ConfigExtraButtons = ({ ); }; - export default ConfigExtraButtons; diff --git a/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/components/ConfigField.tsx b/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/components/ConfigField.tsx index 850bb1a7a..35967fecd 100644 --- a/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/components/ConfigField.tsx +++ b/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/components/ConfigField.tsx @@ -1,18 +1,19 @@ import { useTranslation } from 'react-i18next'; - -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; -import { BasicInput } from '@actiontech/shared'; - +import { FormItemLabel } from '@actiontech/dms-kit'; +import { BasicInput } from '@actiontech/dms-kit'; const ConfigField = () => { const { t } = useTranslation(); - return ( <> { className="has-required-style" label={t('dmsSystem.wechatAudit.corpSecret')} name="corpSecret" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/index.tsx b/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/index.tsx index c908c5300..0db319c10 100644 --- a/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/index.tsx +++ b/packages/base/src/page/System/ProcessConnection/WechatAuditSetting/index.tsx @@ -2,18 +2,18 @@ import { useTranslation } from 'react-i18next'; import { useBoolean, useRequest } from 'ahooks'; import { useCallback, useMemo } from 'react'; import { Form, Spin, Typography } from 'antd'; -import { CustomLabelContent } from '@actiontech/shared/lib/components/CustomForm'; +import { CustomLabelContent } from '@actiontech/dms-kit'; import { ConfigSwitch, ConfigSubmitButtonField, useConfigRender, useConfigSwitchControls, ReadOnlyConfigColumnsType -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import ConfigExtraButtons from './components/ConfigExtraButtons'; import ConfigField from './components/ConfigField'; import configuration from '@actiontech/shared/lib/api/sqle/service/configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { FormFields } from './index.type'; import { defaultFormData, switchFieldName } from './index.data'; import { IWechatConfigurationV1 } from '@actiontech/shared/lib/api/sqle/service/common'; diff --git a/packages/base/src/page/System/PushNotification/LarkSetting/conponents/ConfigExtraButtons.tsx b/packages/base/src/page/System/PushNotification/LarkSetting/conponents/ConfigExtraButtons.tsx index 6ee83dfa0..4a5f46a1a 100644 --- a/packages/base/src/page/System/PushNotification/LarkSetting/conponents/ConfigExtraButtons.tsx +++ b/packages/base/src/page/System/PushNotification/LarkSetting/conponents/ConfigExtraButtons.tsx @@ -2,31 +2,25 @@ import { useTranslation } from 'react-i18next'; import { useRef, useState } from 'react'; import { Form, message, Radio, RadioGroupProps, Space } from 'antd'; import { useForm } from 'antd/es/form/Form'; -import { formItemLayout } from '@actiontech/shared/lib/components/CustomForm/style'; -import { - FormItemLabel, - FormItemNoLabel -} from '@actiontech/shared/lib/components/CustomForm'; -import { BasicInput, EmptyBox } from '@actiontech/shared'; +import { formItemLayout } from '@actiontech/dms-kit/es/components/CustomForm/style'; +import { FormItemLabel, FormItemNoLabel } from '@actiontech/dms-kit'; +import { BasicInput, EmptyBox } from '@actiontech/dms-kit'; import { ConfigModifyBtn, ConfigTestBtn, ConfigTestPopoverForm -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; -import { phoneRule } from '@actiontech/shared/lib/utils/FormRule'; - +} from '@actiontech/dms-kit'; +import { phoneRule } from '@actiontech/dms-kit'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { TestFormFields } from '../index.type'; import { TestFeishuConfigurationAccountTypeEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; - export interface ConfigExtraButtonsProps { enabled: string | boolean; isConfigClosed: boolean; extraButtonsVisible: boolean; handleClickModify: () => void; } - const ConfigExtraButtons = ({ enabled, isConfigClosed, @@ -35,14 +29,12 @@ const ConfigExtraButtons = ({ }: ConfigExtraButtonsProps) => { const { t } = useTranslation(); const [messageApi, messageContextHolder] = message.useMessage(); - const [testPopoverVisible, toggleTestPopoverVisible] = useState(false); const [testForm] = useForm(); const [receiveType, setReceiveType] = useState( TestFeishuConfigurationAccountTypeEnum.email ); - const testing = useRef(false); const testLarkConfiguration = async () => { if (testing.current) { @@ -80,7 +72,6 @@ const ConfigExtraButtons = ({ setReceiveType(TestFeishuConfigurationAccountTypeEnum.email); }); }; - const onTestPopoverOpen = (open: boolean) => { if (!enabled) { return; @@ -91,11 +82,9 @@ const ConfigExtraButtons = ({ } toggleTestPopoverVisible(open); }; - const handleChangeReceiveType: RadioGroupProps['onChange'] = (e) => { const type = e.target.value; setReceiveType(type); - if (type === TestFeishuConfigurationAccountTypeEnum.email) { testForm.resetFields(['receivePhone']); } else { @@ -120,7 +109,9 @@ const ConfigExtraButtons = ({ name="receiveType" label={t('dmsSystem.lark.receiveType')} initialValue={TestFeishuConfigurationAccountTypeEnum.email} - style={{ marginBottom: 0 }} + style={{ + marginBottom: 0 + }} > ); }; - export default ConfigExtraButtons; diff --git a/packages/base/src/page/System/PushNotification/LarkSetting/conponents/ConfigField.tsx b/packages/base/src/page/System/PushNotification/LarkSetting/conponents/ConfigField.tsx index d84aa0745..6aacd80ce 100644 --- a/packages/base/src/page/System/PushNotification/LarkSetting/conponents/ConfigField.tsx +++ b/packages/base/src/page/System/PushNotification/LarkSetting/conponents/ConfigField.tsx @@ -1,18 +1,19 @@ import { useTranslation } from 'react-i18next'; - -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; -import { BasicInput } from '@actiontech/shared'; - +import { FormItemLabel } from '@actiontech/dms-kit'; +import { BasicInput } from '@actiontech/dms-kit'; const ConfigField = () => { const { t } = useTranslation(); - return ( <> { className="has-required-style" label="App Secret" name="appSecret" - rules={[{ required: true }]} + rules={[ + { + required: true + } + ]} > { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/PushNotification/LarkSetting/index.tsx b/packages/base/src/page/System/PushNotification/LarkSetting/index.tsx index 842c9f02b..4b30f387d 100644 --- a/packages/base/src/page/System/PushNotification/LarkSetting/index.tsx +++ b/packages/base/src/page/System/PushNotification/LarkSetting/index.tsx @@ -9,11 +9,11 @@ import { useConfigRender, useConfigSwitchControls, ReadOnlyConfigColumnsType -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import ConfigExtraButtons from './conponents/ConfigExtraButtons'; import ConfigField from './conponents/ConfigField'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { IFeishuConfigurationResData } from '@actiontech/shared/lib/api/base/service/common'; import { switchFieldName } from './index.data'; import { diff --git a/packages/base/src/page/System/PushNotification/SMTPSetting/components/ConfigExtraButtons.tsx b/packages/base/src/page/System/PushNotification/SMTPSetting/components/ConfigExtraButtons.tsx index b202ae15d..5cf2350e9 100644 --- a/packages/base/src/page/System/PushNotification/SMTPSetting/components/ConfigExtraButtons.tsx +++ b/packages/base/src/page/System/PushNotification/SMTPSetting/components/ConfigExtraButtons.tsx @@ -2,24 +2,22 @@ import { Form, message, Space } from 'antd'; import { useTranslation } from 'react-i18next'; import { useRef, useState } from 'react'; import { useForm } from 'antd/es/form/Form'; -import { formItemLayout } from '@actiontech/shared/lib/components/CustomForm/style'; -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; -import { BasicInput } from '@actiontech/shared'; +import { formItemLayout } from '@actiontech/dms-kit/es/components/CustomForm/style'; +import { FormItemLabel } from '@actiontech/dms-kit'; +import { BasicInput } from '@actiontech/dms-kit'; import { ConfigModifyBtn, ConfigTestBtn, ConfigTestPopoverForm -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; - +import { ResponseCode } from '@actiontech/dms-kit'; export type typeConfigExtraButtons = { isConfigClosed: boolean; enabled: string | number | boolean; extraButtonsVisible: boolean; handleClickModify: () => void; }; - const ConfigExtraButtons = ({ isConfigClosed, enabled, @@ -27,14 +25,12 @@ const ConfigExtraButtons = ({ handleClickModify }: typeConfigExtraButtons) => { const { t } = useTranslation(); - const [messageApi, messageContextHolder] = message.useMessage(); - const [testForm] = useForm<{ receiveEmail?: string }>(); - + const [testForm] = useForm<{ + receiveEmail?: string; + }>(); const [testPopoverVisible, toggleTestPopoverVisible] = useState(false); - const testTing = useRef(false); - const onTestPopoverOpen = (open: boolean) => { if (!enabled) { return; @@ -44,7 +40,6 @@ const ConfigExtraButtons = ({ } toggleTestPopoverVisible(open); }; - const handleTest = async () => { if (testTing.current) { return; @@ -68,7 +63,9 @@ const ConfigExtraButtons = ({ const resData = res.data?.data; if (resData?.is_smtp_send_normal) { messageApi.success( - t('dmsSystem.smtp.testSuccess', { email: values.receiveEmail }) + t('dmsSystem.smtp.testSuccess', { + email: values.receiveEmail + }) ); testForm.resetFields(); } else { @@ -84,7 +81,6 @@ const ConfigExtraButtons = ({ testForm.resetFields(); }); }; - return ( <> {messageContextHolder} @@ -101,7 +97,9 @@ const ConfigExtraButtons = ({
); }; - export default ConfigExtraButtons; diff --git a/packages/base/src/page/System/PushNotification/SMTPSetting/components/ConfigField.tsx b/packages/base/src/page/System/PushNotification/SMTPSetting/components/ConfigField.tsx index f5048bd8c..7f6cad8ec 100644 --- a/packages/base/src/page/System/PushNotification/SMTPSetting/components/ConfigField.tsx +++ b/packages/base/src/page/System/PushNotification/SMTPSetting/components/ConfigField.tsx @@ -1,14 +1,9 @@ import { useTranslation } from 'react-i18next'; -import { BasicInput, BasicSwitch } from '@actiontech/shared'; -import { - CustomLabelContent, - FormItemLabel -} from '@actiontech/shared/lib/components/CustomForm'; -import { validatorPort } from '@actiontech/shared/lib/utils/FormRule'; - +import { BasicInput, BasicSwitch } from '@actiontech/dms-kit'; +import { CustomLabelContent, FormItemLabel } from '@actiontech/dms-kit'; +import { validatorPort } from '@actiontech/dms-kit'; const ConfigField = () => { const { t } = useTranslation(); - return ( <> { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/PushNotification/SMTPSetting/index.tsx b/packages/base/src/page/System/PushNotification/SMTPSetting/index.tsx index 444a93426..9af12cb9d 100644 --- a/packages/base/src/page/System/PushNotification/SMTPSetting/index.tsx +++ b/packages/base/src/page/System/PushNotification/SMTPSetting/index.tsx @@ -8,26 +8,24 @@ import { useConfigRender, useConfigSwitchControls, ReadOnlyConfigColumnsType -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit/es/components/SystemConfigurationHub'; import { SMTPSettingFormFields } from './index.type'; import { switchFieldName } from './index.data'; import { ISMTPConfigurationResData } from '@actiontech/shared/lib/api/base/service/common'; -import { BasicToolTip } from '@actiontech/shared'; +import { BasicToolTip } from '@actiontech/dms-kit'; import ConfigField from './components/ConfigField'; import ConfigExtraButtons from './components/ConfigExtraButtons'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { InfoCircleOutlined } from '@actiontech/icons'; import useThemeStyleData from '../../../../hooks/useThemeStyleData'; import { PERMISSIONS, PermissionControl } from '@actiontech/shared/lib/features'; - const SMTPSetting = () => { const { t } = useTranslation(); const { baseTheme } = useThemeStyleData(); - const { form, renderConfigForm, @@ -40,7 +38,6 @@ const SMTPSetting = () => { switchFieldName, switchFieldLabel: t('dmsSystem.smtp.enable') }); - const { data: smtpInfo, refresh: refreshSMTPInfo, @@ -58,9 +55,7 @@ const SMTPSetting = () => { } } ); - const switchOpen = Form.useWatch(switchFieldName, form); - const readonlyColumnsConfig: ReadOnlyConfigColumnsType = useMemo(() => { return [ @@ -104,10 +99,8 @@ const SMTPSetting = () => { } ]; }, [t, smtpInfo, baseTheme]); - const [submitLoading, { setTrue: startSubmit, setFalse: submitFinish }] = useBoolean(); - const submit = (values: SMTPSettingFormFields) => { startSubmit(); Configuration.UpdateSMTPConfiguration({ @@ -131,11 +124,9 @@ const SMTPSetting = () => { submitFinish(); }); }; - const isConfigClosed = useMemo(() => { return !smtpInfo?.enable_smtp_notify; }, [smtpInfo]); - const setFormDefaultValue = useCallback(() => { form.setFieldsValue({ host: smtpInfo?.smtp_host, @@ -148,18 +139,15 @@ const SMTPSetting = () => { passwordConfirm: undefined }); }, [form, smtpInfo]); - const handleClickModify = useCallback(() => { setFormDefaultValue(); startModify(); }, [startModify, setFormDefaultValue]); - const handleClickCancel = () => { if (isConfigClosed) form.setFieldValue(switchFieldName, false); setFormDefaultValue(); modifyFinish(); }; - const { configSwitchPopoverOpenState, generateConfigSwitchPopoverTitle, @@ -167,7 +155,6 @@ const SMTPSetting = () => { handleConfigSwitchChange, hiddenConfigSwitchPopover } = useConfigSwitchControls(form, switchFieldName); - const onConfigSwitchPopoverConfirm = () => { if (isConfigClosed && modifyFlag) { handleClickCancel(); @@ -193,7 +180,6 @@ const SMTPSetting = () => { }); } }; - return (
@@ -247,5 +233,4 @@ const SMTPSetting = () => {
); }; - export default SMTPSetting; diff --git a/packages/base/src/page/System/PushNotification/WebhookSetting/components/ConfigExtraButtons.tsx b/packages/base/src/page/System/PushNotification/WebhookSetting/components/ConfigExtraButtons.tsx index b70e102a7..1e8a84494 100644 --- a/packages/base/src/page/System/PushNotification/WebhookSetting/components/ConfigExtraButtons.tsx +++ b/packages/base/src/page/System/PushNotification/WebhookSetting/components/ConfigExtraButtons.tsx @@ -1,12 +1,11 @@ import { useTranslation } from 'react-i18next'; import { useRef } from 'react'; import { message, Space } from 'antd'; -import { BasicButton, BasicToolTip } from '@actiontech/shared'; -import { ConfigModifyBtn } from '@actiontech/shared/lib/components/SystemConfigurationHub'; +import { BasicButton, BasicToolTip } from '@actiontech/dms-kit'; +import { ConfigModifyBtn } from '@actiontech/dms-kit'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { ThunderBoltFilled } from '@actiontech/icons'; - export interface ConfigExtraButtonsProps { enabled: string | number | boolean; isConfigClosed: boolean; @@ -14,7 +13,6 @@ export interface ConfigExtraButtonsProps { handleClickModify: () => void; msgUrl: string; } - const ConfigExtraButtons = ({ enabled, isConfigClosed, @@ -24,23 +22,22 @@ const ConfigExtraButtons = ({ }: ConfigExtraButtonsProps) => { const { t } = useTranslation(); const [messageApi, messageContextHolder] = message.useMessage(); - const testTing = useRef(false); const test = () => { if (testTing.current) { return; } - testTing.current = true; const hide = messageApi.loading( - t('dmsSystem.webhook.testing', { url: msgUrl }), + t('dmsSystem.webhook.testing', { + url: msgUrl + }), 0 ); Configuration.TestWebHookConfiguration() .then((res) => { if (res.data.code === ResponseCode.SUCCESS) { const resData = res.data?.data; - if (resData?.is_message_sent_normally) { messageApi.success(t('dmsSystem.webhook.testSuccess')); } else { @@ -55,7 +52,6 @@ const ConfigExtraButtons = ({ testTing.current = false; }); }; - return ( <> {messageContextHolder} @@ -78,5 +74,4 @@ const ConfigExtraButtons = ({ ); }; - export default ConfigExtraButtons; diff --git a/packages/base/src/page/System/PushNotification/WebhookSetting/components/ConfigField.tsx b/packages/base/src/page/System/PushNotification/WebhookSetting/components/ConfigField.tsx index 845838d34..6889ab4c2 100644 --- a/packages/base/src/page/System/PushNotification/WebhookSetting/components/ConfigField.tsx +++ b/packages/base/src/page/System/PushNotification/WebhookSetting/components/ConfigField.tsx @@ -1,11 +1,8 @@ import { useTranslation } from 'react-i18next'; - -import { BasicInput, BasicInputNumber } from '@actiontech/shared'; -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; - +import { BasicInput, BasicInputNumber } from '@actiontech/dms-kit'; +import { FormItemLabel } from '@actiontech/dms-kit'; const ConfigField = () => { const { t } = useTranslation(); - return ( <> { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/PushNotification/WebhookSetting/index.tsx b/packages/base/src/page/System/PushNotification/WebhookSetting/index.tsx index 3772a0416..f6f7061c0 100644 --- a/packages/base/src/page/System/PushNotification/WebhookSetting/index.tsx +++ b/packages/base/src/page/System/PushNotification/WebhookSetting/index.tsx @@ -9,13 +9,13 @@ import { useConfigRender, useConfigSwitchControls, ReadOnlyConfigColumnsType -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import ConfigExtraButtons from './components/ConfigExtraButtons'; import ConfigField from './components/ConfigField'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; import { IWebHookConfigurationData } from '@actiontech/shared/lib/api/base/service/common'; import { WebhookFormFields } from './index.type'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { PERMISSIONS, PermissionControl diff --git a/packages/base/src/page/System/PushNotification/Wechat/components/ConfigExtraButtons.tsx b/packages/base/src/page/System/PushNotification/Wechat/components/ConfigExtraButtons.tsx index 646bb5e00..bf82ba713 100644 --- a/packages/base/src/page/System/PushNotification/Wechat/components/ConfigExtraButtons.tsx +++ b/packages/base/src/page/System/PushNotification/Wechat/components/ConfigExtraButtons.tsx @@ -1,28 +1,21 @@ import { useTranslation } from 'react-i18next'; import { useRef, useState } from 'react'; - import { Form, message, Space } from 'antd'; -import { formItemLayout } from '@actiontech/shared/lib/components/CustomForm/style'; -import { - CustomLabelContent, - FormItemLabel -} from '@actiontech/shared/lib/components/CustomForm'; +import { formItemLayout } from '@actiontech/dms-kit/es/components/CustomForm/style'; +import { CustomLabelContent, FormItemLabel } from '@actiontech/dms-kit'; import { ConfigModifyBtn, ConfigTestBtn, ConfigTestPopoverForm -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; -import { BasicInput } from '@actiontech/shared'; - +} from '@actiontech/dms-kit'; +import { BasicInput } from '@actiontech/dms-kit'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; - export type typeConfigExtraButtons = { extraButtonsVisible: boolean; isConfigClosed: boolean; enabled: string | boolean | undefined; handleClickModify: () => void; }; - const ConfigExtraButtons = ({ extraButtonsVisible, isConfigClosed, @@ -31,8 +24,9 @@ const ConfigExtraButtons = ({ }: typeConfigExtraButtons) => { const { t } = useTranslation(); const [messageApi, messageContextHolder] = message.useMessage(); - const [testForm] = Form.useForm<{ receiveId?: string }>(); - + const [testForm] = Form.useForm<{ + receiveId?: string; + }>(); const [testPopoverVisible, toggleTestPopoverVisible] = useState(false); const testTing = useRef(false); const test = async () => { @@ -40,11 +34,12 @@ const ConfigExtraButtons = ({ return; } const values = await testForm.validateFields(); - testTing.current = true; toggleTestPopoverVisible(false); const hide = messageApi.loading( - t('dmsSystem.wechat.testing', { id: values.receiveId }), + t('dmsSystem.wechat.testing', { + id: values.receiveId + }), 0 ); Configuration.TestWeChatConfiguration({ @@ -68,7 +63,6 @@ const ConfigExtraButtons = ({ testForm.resetFields(); }); }; - const onTestPopoverOpen = (open: boolean) => { if (!enabled) { return; @@ -78,7 +72,6 @@ const ConfigExtraButtons = ({ } toggleTestPopoverVisible(open); }; - return ( <> {messageContextHolder} @@ -100,7 +93,9 @@ const ConfigExtraButtons = ({ tips={t('dmsSystem.wechat.receiveWechatTips')} /> } - style={{ marginBottom: 0 }} + style={{ + marginBottom: 0 + }} name="receiveId" rules={[ { @@ -130,5 +125,4 @@ const ConfigExtraButtons = ({ ); }; - export default ConfigExtraButtons; diff --git a/packages/base/src/page/System/PushNotification/Wechat/components/ConfigField.tsx b/packages/base/src/page/System/PushNotification/Wechat/components/ConfigField.tsx index 1b73c534e..4e64fe7ab 100644 --- a/packages/base/src/page/System/PushNotification/Wechat/components/ConfigField.tsx +++ b/packages/base/src/page/System/PushNotification/Wechat/components/ConfigField.tsx @@ -1,11 +1,8 @@ import { useTranslation } from 'react-i18next'; - -import { BasicInput, BasicSwitch } from '@actiontech/shared'; -import { FormItemLabel } from '@actiontech/shared/lib/components/CustomForm'; - +import { BasicInput, BasicSwitch } from '@actiontech/dms-kit'; +import { FormItemLabel } from '@actiontech/dms-kit'; const ConfigField = () => { const { t } = useTranslation(); - return ( <> { ); }; - export default ConfigField; diff --git a/packages/base/src/page/System/PushNotification/Wechat/index.tsx b/packages/base/src/page/System/PushNotification/Wechat/index.tsx index 8aeb40c78..9493f0cb5 100644 --- a/packages/base/src/page/System/PushNotification/Wechat/index.tsx +++ b/packages/base/src/page/System/PushNotification/Wechat/index.tsx @@ -9,11 +9,11 @@ import { useConfigRender, useConfigSwitchControls, ReadOnlyConfigColumnsType -} from '@actiontech/shared/lib/components/SystemConfigurationHub'; +} from '@actiontech/dms-kit'; import ConfigExtraButtons from './components/ConfigExtraButtons'; import ConfigField from './components/ConfigField'; import Configuration from '@actiontech/shared/lib/api/base/service/Configuration'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import { WechatFormFields } from './index.type'; import { IWeChatConfigurationResData } from '@actiontech/shared/lib/api/base/service/common'; import { diff --git a/packages/base/src/page/System/components/BasicTitle/index.tsx b/packages/base/src/page/System/components/BasicTitle/index.tsx index d258700a9..b04a5dcac 100644 --- a/packages/base/src/page/System/components/BasicTitle/index.tsx +++ b/packages/base/src/page/System/components/BasicTitle/index.tsx @@ -1,20 +1,17 @@ import { ReactNode } from 'react'; import { Space, Row } from 'antd'; -import { BasicToolTip } from '@actiontech/shared'; +import { BasicToolTip } from '@actiontech/dms-kit'; import { InfoCircleOutlined } from '@actiontech/icons'; import useThemeStyleData from '../../../../hooks/useThemeStyleData'; - export type SystemBasicTitleProps = { title: ReactNode | string; titleTip?: ReactNode | string; titleExtra?: ReactNode | string; children: ReactNode | string; }; - const SystemBasicTitle = (props: SystemBasicTitleProps) => { const { title, children, titleTip, titleExtra } = props; const { baseTheme } = useThemeStyleData(); - return (
{
); }; - export default SystemBasicTitle; diff --git a/packages/base/src/page/System/index.ce.test.tsx b/packages/base/src/page/System/index.ce.test.tsx index e23fb3aa0..240c5f3f4 100644 --- a/packages/base/src/page/System/index.ce.test.tsx +++ b/packages/base/src/page/System/index.ce.test.tsx @@ -9,7 +9,7 @@ import { baseSuperRender } from '../../testUtils/superRender'; import system from '@actiontech/shared/lib/testUtil/mockApi/base/system'; import dms from '@actiontech/shared/lib/testUtil/mockApi/base/global'; -import { DMS_DEFAULT_WEB_TITLE } from '@actiontech/shared/lib/data/common'; +import { DMS_DEFAULT_WEB_TITLE } from '@actiontech/dms-kit'; import { getAllBySelector } from '@actiontech/shared/lib/testUtil/customQuery'; describe('base/System-ee', () => { diff --git a/packages/base/src/page/System/index.test.tsx b/packages/base/src/page/System/index.test.tsx index f1e6591b2..c4cf691df 100644 --- a/packages/base/src/page/System/index.test.tsx +++ b/packages/base/src/page/System/index.test.tsx @@ -4,7 +4,7 @@ import { cleanup, act, fireEvent, screen } from '@testing-library/react'; import { baseSuperRender } from '../../testUtils/superRender'; import system from '@actiontech/shared/lib/testUtil/mockApi/base/system'; import dms from '@actiontech/shared/lib/testUtil/mockApi/base/global'; -import { DMS_DEFAULT_WEB_TITLE } from '@actiontech/shared/lib/data/common'; +import { DMS_DEFAULT_WEB_TITLE } from '@actiontech/dms-kit'; import { ModalName } from '../../data/ModalName'; import { getAllBySelector } from '@actiontech/shared/lib/testUtil/customQuery'; import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser'; diff --git a/packages/base/src/page/System/index.tsx b/packages/base/src/page/System/index.tsx index a65e62b18..a3247f5eb 100644 --- a/packages/base/src/page/System/index.tsx +++ b/packages/base/src/page/System/index.tsx @@ -2,7 +2,8 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { Row } from 'antd'; -import { BasicSegmented, PageHeader, useTypedQuery } from '@actiontech/shared'; +import { BasicSegmented, PageHeader } from '@actiontech/dms-kit'; +import { useTypedQuery } from '@actiontech/shared'; import { SystemStyleWrapper } from './style'; import { initSystemModalStatus } from '../../store/system'; import { ModalName } from '../../data/ModalName'; @@ -15,14 +16,11 @@ import License from './License'; import PersonalizeSetting from './PersonalizeSetting'; import GitSSHConfig from './GitSSHConfig'; import DatabaseAccountPasswordPolicyForm from './DatabaseAccountPasswordPolicy'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; - +import { ROUTE_PATHS } from '@actiontech/dms-kit'; const System = () => { const { t } = useTranslation(); - const dispatch = useDispatch(); const extractQueries = useTypedQuery(); - const options = useMemo( () => [ // #if [sqle] @@ -43,7 +41,6 @@ const System = () => { value: SystemSegmentedKeyEnum.LoginConnection, components: }, - // #if [sqle] { label: t('dmsSystem.tabPaneTitle.globalConfiguration'), @@ -79,13 +76,10 @@ const System = () => { ], [t] ); - const [activeTabKey, setActiveTabKey] = useState(options[0].value); - const renderActiveTab = useCallback(() => { return options.find((item) => item.value === activeTabKey)?.components; }, [activeTabKey, options]); - useEffect(() => { const urlSearchParams = extractQueries(ROUTE_PATHS.BASE.SYSTEM.index); if (urlSearchParams && urlSearchParams.active_tab) { @@ -122,5 +116,4 @@ const System = () => { ); }; - export default System; diff --git a/packages/base/src/page/Transit/index.tsx b/packages/base/src/page/Transit/index.tsx index bcf06a7a4..d93c1aee2 100644 --- a/packages/base/src/page/Transit/index.tsx +++ b/packages/base/src/page/Transit/index.tsx @@ -1,20 +1,29 @@ /* eslint-disable no-console */ import { useEffect } from 'react'; -import { - HeaderProgress, - useTypedNavigate, - useTypedQuery -} from '@actiontech/shared'; +import { HeaderProgress } from '@actiontech/dms-kit'; +import { useTypedNavigate, useTypedQuery } from '@actiontech/shared'; import { useCurrentUser } from '@actiontech/shared/lib/features'; -import { TRANSIT_FROM_CONSTANT } from '@actiontech/shared/lib/data/common'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import { TRANSIT_FROM_CONSTANT } from '@actiontech/dms-kit'; +import { ROUTE_PATHS } from '@actiontech/dms-kit'; import { parse2ReactRouterPath } from '@actiontech/shared/lib/components/TypedRouter/utils'; const TARGET_DATA = (projectID: string): Record => { return { create_workflow: parse2ReactRouterPath( ROUTE_PATHS.SQLE.SQL_EXEC_WORKFLOW.create, - { params: { projectID } } + { + params: { + projectID + } + } + ), + create_export_workflow: parse2ReactRouterPath( + ROUTE_PATHS.BASE.DATA_EXPORT.create, + { + params: { + projectID + } + } ) }; }; @@ -23,58 +32,57 @@ const Transit: React.FC = () => { const navigate = useTypedNavigate(); const { bindProjects } = useCurrentUser(); const extractQueries = useTypedQuery(); - useEffect(() => { const searchParams = extractQueries(ROUTE_PATHS.BASE.TRANSIT.index); - const from = searchParams?.from; const to = searchParams?.to; const compressionData = searchParams?.compression_data; const projectName = searchParams?.project_name; - if (!from || !to || !compressionData) { console.error( `Missing required parameters!\n from=${from}\n to=${to}\n compression_data=${compressionData}` ); - navigate(ROUTE_PATHS.BASE.HOME, { replace: true }); + navigate(ROUTE_PATHS.BASE.HOME, { + replace: true + }); return; } - if (!Object.keys(TRANSIT_FROM_CONSTANT).includes(from)) { console.error(`Unknown source: ${from}`); - navigate(ROUTE_PATHS.BASE.HOME, { replace: true }); + navigate(ROUTE_PATHS.BASE.HOME, { + replace: true + }); return; } - if (projectName) { const projectID = bindProjects.find( (v) => v.project_name === projectName )?.project_id; - if (!projectID) { console.error(`Not found project: ${projectName}`); - navigate(ROUTE_PATHS.BASE.HOME, { replace: true }); + navigate(ROUTE_PATHS.BASE.HOME, { + replace: true + }); return; } - const path = TARGET_DATA(projectID)[to!]; - if (!path) { console.error(`Not found target path: ${to}`); - navigate(ROUTE_PATHS.BASE.HOME, { replace: true }); + navigate(ROUTE_PATHS.BASE.HOME, { + replace: true + }); return; } - navigate(`${path}?from=${from}&compression_data=${compressionData}`, { replace: true }); } else { console.error(`project name is undefined`); - navigate(ROUTE_PATHS.BASE.HOME, { replace: true }); + navigate(ROUTE_PATHS.BASE.HOME, { + replace: true + }); } }, [bindProjects, navigate, extractQueries]); - return ; }; - export default Transit; diff --git a/packages/base/src/page/UserCenter/Drawer/Role/AddRole/index.tsx b/packages/base/src/page/UserCenter/Drawer/Role/AddRole/index.tsx index 6c2836614..4af957c80 100644 --- a/packages/base/src/page/UserCenter/Drawer/Role/AddRole/index.tsx +++ b/packages/base/src/page/UserCenter/Drawer/Role/AddRole/index.tsx @@ -10,25 +10,18 @@ import { useBoolean } from 'ahooks'; import EmitterKey from '../../../../../data/EmitterKey'; import EventEmitter from '../../../../../utils/EventEmitter'; import { updateUserManageModalStatus } from '../../../../../store/userCenter'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import Role from '@actiontech/shared/lib/api/base/service/Role'; -import { BasicDrawer, BasicButton } from '@actiontech/shared'; - +import { BasicDrawer, BasicButton } from '@actiontech/dms-kit'; const AddRole = () => { const [form] = Form.useForm(); - const [messageApi, contextHolder] = message.useMessage(); - const { t } = useTranslation(); - const dispatch = useDispatch(); - const [createLoading, { setTrue, setFalse }] = useBoolean(); - const visible = useSelector( (state) => !!state.userCenter.modalStatus[ModalName.DMS_Add_Role] ); - const onClose = useCallback(() => { form.resetFields(); dispatch( @@ -38,7 +31,6 @@ const AddRole = () => { }) ); }, [dispatch, form]); - const addRole = useCallback(async () => { const values = await form.validateFields(); setTrue(); @@ -64,7 +56,6 @@ const AddRole = () => { setFalse(); }); }, [onClose, form, setFalse, setTrue, t, messageApi]); - return ( { ); }; - export default AddRole; diff --git a/packages/base/src/page/UserCenter/Drawer/Role/CloneRole/index.tsx b/packages/base/src/page/UserCenter/Drawer/Role/CloneRole/index.tsx index fc73ac132..5093929c1 100644 --- a/packages/base/src/page/UserCenter/Drawer/Role/CloneRole/index.tsx +++ b/packages/base/src/page/UserCenter/Drawer/Role/CloneRole/index.tsx @@ -10,30 +10,22 @@ import { useBoolean } from 'ahooks'; import EmitterKey from '../../../../../data/EmitterKey'; import EventEmitter from '../../../../../utils/EventEmitter'; import { updateUserManageModalStatus } from '../../../../../store/userCenter'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import Role from '@actiontech/shared/lib/api/base/service/Role'; -import { BasicDrawer, BasicButton } from '@actiontech/shared'; +import { BasicDrawer, BasicButton } from '@actiontech/dms-kit'; import { IListRole } from '@actiontech/shared/lib/api/base/service/common'; - const CloneRole = () => { const [form] = Form.useForm(); - const [messageApi, contextHolder] = message.useMessage(); - const { t } = useTranslation(); - const dispatch = useDispatch(); - const [createLoading, { setTrue, setFalse }] = useBoolean(); - const visible = useSelector( (state) => !!state.userCenter.modalStatus[ModalName.DMS_Clone_Role] ); - const currentRole = useSelector( (state) => state.userCenter.selectRole ); - const onClose = useCallback(() => { form.resetFields(); dispatch( @@ -43,7 +35,6 @@ const CloneRole = () => { }) ); }, [dispatch, form]); - const cloneRole = useCallback(async () => { const values = await form.validateFields(); setTrue(); @@ -69,7 +60,6 @@ const CloneRole = () => { setFalse(); }); }, [onClose, form, setFalse, setTrue, t, messageApi]); - useEffect(() => { if (visible && currentRole) { form.setFieldsValue({ @@ -79,7 +69,6 @@ const CloneRole = () => { }); } }, [visible, currentRole, form]); - return ( { ); }; - export default CloneRole; diff --git a/packages/base/src/page/UserCenter/Drawer/Role/RoleForm/index.tsx b/packages/base/src/page/UserCenter/Drawer/Role/RoleForm/index.tsx index 3c3b1a4fe..9821be8ac 100644 --- a/packages/base/src/page/UserCenter/Drawer/Role/RoleForm/index.tsx +++ b/packages/base/src/page/UserCenter/Drawer/Role/RoleForm/index.tsx @@ -1,31 +1,26 @@ import React, { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { Form, Switch, Spin } from 'antd'; -import { EmptyBox, BasicInput } from '@actiontech/shared'; -import { roleNameRule } from '@actiontech/shared/lib/utils/FormRule'; +import { EmptyBox, BasicInput } from '@actiontech/dms-kit'; +import { roleNameRule } from '@actiontech/dms-kit'; import { IRoleFormProps } from './index.type'; import { ListOpPermissionsFilterByTargetEnum } from '@actiontech/shared/lib/api/base/service/OpPermission/index.enum'; import useOpPermission from '../../../../../hooks/useOpPermission'; import OpPermissionCheckboxGroup from './components/OpPermissionCheckboxGroup'; import { RoleFormAlertStyleWrapper } from './style'; - const RoleForm: React.FC = (props) => { const { t } = useTranslation(); - const name = Form.useWatch('name', props.form); - const { loading: getOpPermissionListLoading, updateOpPermissionList, opPermissionList } = useOpPermission(); - useEffect(() => { if (props.visible) { updateOpPermissionList(ListOpPermissionsFilterByTargetEnum.member); } }, [updateOpPermissionList, props.visible]); - return ( = (props) => { = (props) => { ); }; - export default RoleForm; diff --git a/packages/base/src/page/UserCenter/Drawer/Role/UpdateRole/index.tsx b/packages/base/src/page/UserCenter/Drawer/Role/UpdateRole/index.tsx index f99e2273d..34740db17 100644 --- a/packages/base/src/page/UserCenter/Drawer/Role/UpdateRole/index.tsx +++ b/packages/base/src/page/UserCenter/Drawer/Role/UpdateRole/index.tsx @@ -11,30 +11,22 @@ import EmitterKey from '../../../../../data/EmitterKey'; import EventEmitter from '../../../../../utils/EventEmitter'; import { updateUserManageModalStatus } from '../../../../../store/userCenter'; import { IListRole } from '@actiontech/shared/lib/api/base/service/common'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import Role from '@actiontech/shared/lib/api/base/service/Role'; import { ListRoleStatEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; -import { BasicDrawer, BasicButton } from '@actiontech/shared'; - +import { BasicDrawer, BasicButton } from '@actiontech/dms-kit'; const UpdateRole = () => { const [form] = Form.useForm(); - const { t } = useTranslation(); - const dispatch = useDispatch(); - const [messageApi, contextHolder] = message.useMessage(); - const [updateLoading, { setTrue, setFalse }] = useBoolean(); - const visible = useSelector( (state) => !!state.userCenter.modalStatus[ModalName.DMS_Update_Role] ); - const currentRole = useSelector( (state) => state.userCenter.selectRole ); - const onClose = useCallback(() => { form.resetFields(); dispatch( @@ -44,7 +36,6 @@ const UpdateRole = () => { }) ); }, [dispatch, form]); - const updateRole = useCallback(async () => { const values = await form.validateFields(); setTrue(); @@ -71,7 +62,6 @@ const UpdateRole = () => { setFalse(); }); }, [onClose, currentRole?.uid, form, setFalse, setTrue, t, messageApi]); - useEffect(() => { if (visible) { form.setFieldsValue({ @@ -82,7 +72,6 @@ const UpdateRole = () => { }); } }, [visible, currentRole, form]); - return ( { ); }; - export default UpdateRole; diff --git a/packages/base/src/page/UserCenter/Drawer/User/AddUser/index.tsx b/packages/base/src/page/UserCenter/Drawer/User/AddUser/index.tsx index d523f0f53..33ee4a899 100644 --- a/packages/base/src/page/UserCenter/Drawer/User/AddUser/index.tsx +++ b/packages/base/src/page/UserCenter/Drawer/User/AddUser/index.tsx @@ -6,30 +6,23 @@ import { useDispatch, useSelector } from 'react-redux'; import { ModalName } from '../../../../../data/ModalName'; import { IReduxState } from '../../../../../store'; import { updateUserManageModalStatus } from '../../../../../store/userCenter'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import EmitterKey from '../../../../../data/EmitterKey'; import UserForm from '../UserForm'; import { IUserFormFields } from '../UserForm/index.type'; import EventEmitter from '../../../../../utils/EventEmitter'; -import { BasicDrawer, BasicButton } from '@actiontech/shared'; +import { BasicDrawer, BasicButton } from '@actiontech/dms-kit'; import User from '@actiontech/shared/lib/api/base/service/User'; import dayjs from 'dayjs'; - const AddUser = () => { const [form] = Form.useForm(); - const { t } = useTranslation(); - const dispatch = useDispatch(); - const [createLoading, { setTrue, setFalse }] = useBoolean(); - const visible = useSelector( (state) => !!state.userCenter.modalStatus[ModalName.DMS_Add_User] ); - const [messageApi, contextHolder] = message.useMessage(); - const onClose = useCallback(() => { form.resetFields(); dispatch( @@ -39,7 +32,6 @@ const AddUser = () => { }) ); }, [dispatch, form]); - const addUser = useCallback(async () => { const values = await form.validateFields(); setTrue(); @@ -71,7 +63,6 @@ const AddUser = () => { setFalse(); }); }, [onClose, form, setFalse, setTrue, t, messageApi]); - return ( { ); }; - export default AddUser; diff --git a/packages/base/src/page/UserCenter/Drawer/User/UpdateUser/index.tsx b/packages/base/src/page/UserCenter/Drawer/User/UpdateUser/index.tsx index d15bc1202..125c28322 100644 --- a/packages/base/src/page/UserCenter/Drawer/User/UpdateUser/index.tsx +++ b/packages/base/src/page/UserCenter/Drawer/User/UpdateUser/index.tsx @@ -9,7 +9,7 @@ import UserForm from '../UserForm'; import { IUserFormFields } from '../UserForm/index.type'; import { ModalName } from '../../../../../data/ModalName'; import { updateUserManageModalStatus } from '../../../../../store/userCenter'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +import { ResponseCode } from '@actiontech/dms-kit'; import EventEmitter from '../../../../../utils/EventEmitter'; import { IListUser, @@ -17,28 +17,20 @@ import { } from '@actiontech/shared/lib/api/base/service/common'; import User from '@actiontech/shared/lib/api/base/service/User'; import { ListUserStatEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; -import { BasicDrawer, BasicButton } from '@actiontech/shared'; -import { SystemRole } from '@actiontech/shared/lib/enum'; - +import { BasicDrawer, BasicButton } from '@actiontech/dms-kit'; +import { SystemRole } from '@actiontech/dms-kit'; const UpdateUser = () => { const [form] = Form.useForm(); - const { t } = useTranslation(); - const dispatch = useDispatch(); - const [updateLoading, { setTrue, setFalse }] = useBoolean(); - const visible = useSelector( (state) => !!state.userCenter.modalStatus[ModalName.DMS_Update_User] ); - const currentUser = useSelector( (state) => state.userCenter.selectUser ); - const [messageApi, contextHolder] = message.useMessage(); - const onClose = useCallback(() => { form.resetFields(); dispatch( @@ -48,10 +40,8 @@ const UpdateUser = () => { }) ); }, [dispatch, form]); - const updateUser = async () => { const values = await form.validateFields(); - const userParams: IUpdateUser = { password: values.passwordConfirm, email: values.email ?? '', @@ -63,7 +53,6 @@ const UpdateUser = () => { is_disabled: values.username !== 'admin' ? !!values.isDisabled : false }; setTrue(); - User.UpdateUser({ user_uid: currentUser?.uid ?? '', user: userParams @@ -83,7 +72,6 @@ const UpdateUser = () => { setFalse(); }); }; - useEffect(() => { if (visible) { form.setFieldsValue({ @@ -100,7 +88,6 @@ const UpdateUser = () => { }); } }, [visible, currentUser, form]); - return ( { ); }; - export default UpdateUser; diff --git a/packages/base/src/page/UserCenter/Drawer/User/UserForm/index.tsx b/packages/base/src/page/UserCenter/Drawer/User/UserForm/index.tsx index 48297dab7..728d7d58a 100644 --- a/packages/base/src/page/UserCenter/Drawer/User/UserForm/index.tsx +++ b/packages/base/src/page/UserCenter/Drawer/User/UserForm/index.tsx @@ -1,28 +1,24 @@ import { IUserFormProps } from './index.type'; import { Form, Switch } from 'antd'; -import { BasicInput, BasicSelect, EmptyBox } from '@actiontech/shared'; +import { BasicInput, BasicSelect, EmptyBox } from '@actiontech/dms-kit'; import React, { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; -import { phoneRule } from '@actiontech/shared/lib/utils/FormRule'; -import { BasicToolTip } from '@actiontech/shared'; +import { phoneRule } from '@actiontech/dms-kit'; +import { BasicToolTip } from '@actiontech/dms-kit'; import useOpPermission from '../../../../../hooks/useOpPermission'; import { ListOpPermissionsFilterByTargetEnum } from '@actiontech/shared/lib/api/base/service/OpPermission/index.enum'; - const UserForm: React.FC = (props) => { const { t } = useTranslation(); - const { loading: getOpPermissionListLoading, opPermissionOptions, updateOpPermissionList } = useOpPermission(); - useEffect(() => { if (props.visible) { updateOpPermissionList(ListOpPermissionsFilterByTargetEnum.user); } }, [updateOpPermissionList, props.visible]); - return (
= (props) => { ); }; - export default UserForm; diff --git a/packages/base/src/page/UserCenter/__tests__/index.test.tsx b/packages/base/src/page/UserCenter/__tests__/index.test.tsx index c03fdfb17..eb9aa04fc 100644 --- a/packages/base/src/page/UserCenter/__tests__/index.test.tsx +++ b/packages/base/src/page/UserCenter/__tests__/index.test.tsx @@ -6,7 +6,7 @@ import userCenter from '@actiontech/shared/lib/testUtil/mockApi/base/userCenter' import { useDispatch } from 'react-redux'; import { ModalName } from '../../../data/ModalName'; import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser'; -import { SystemRole } from '@actiontech/shared/lib/enum'; +import { SystemRole } from '@actiontech/dms-kit'; jest.mock('react-redux', () => { return { diff --git a/packages/base/src/page/UserCenter/action.tsx b/packages/base/src/page/UserCenter/action.tsx index 2d2822173..794604849 100644 --- a/packages/base/src/page/UserCenter/action.tsx +++ b/packages/base/src/page/UserCenter/action.tsx @@ -8,7 +8,6 @@ import { ActionButton } from '@actiontech/shared'; import { t } from '../../locale'; import { ModalName } from '../../data/ModalName'; import { PlusOutlined } from '@actiontech/icons'; - export const UserCenterPageHeaderActions = ( activePage: UserCenterListEnum, handleClick: (modalName: ModalName) => void diff --git a/packages/base/src/page/UserCenter/components/PermissionList/List.tsx b/packages/base/src/page/UserCenter/components/PermissionList/List.tsx index 6926e7b96..499887e5f 100644 --- a/packages/base/src/page/UserCenter/components/PermissionList/List.tsx +++ b/packages/base/src/page/UserCenter/components/PermissionList/List.tsx @@ -2,7 +2,7 @@ import { ActiontechTable, useTableRequestError, useTableRequestParams -} from '@actiontech/shared/lib/components/ActiontechTable'; +} from '@actiontech/dms-kit/es/components/ActiontechTable'; import { permissionListColumns } from './column'; import { UserCenterListEnum } from '../../index.enum'; import { IListOpPermission } from '@actiontech/shared/lib/api/base/service/common'; diff --git a/packages/base/src/page/UserCenter/components/PermissionList/column.tsx b/packages/base/src/page/UserCenter/components/PermissionList/column.tsx index 62be2470f..e3de426c2 100644 --- a/packages/base/src/page/UserCenter/components/PermissionList/column.tsx +++ b/packages/base/src/page/UserCenter/components/PermissionList/column.tsx @@ -1,4 +1,4 @@ -import { ActiontechTableColumn } from '@actiontech/shared/lib/components/ActiontechTable/index.type'; +import { ActiontechTableColumn } from '@actiontech/dms-kit/es/components/ActiontechTable/index.type'; import { IListOpPermission } from '@actiontech/shared/lib/api/base/service/common'; import { t } from '../../../../locale'; import { getOpRangeTypeName } from '../../../../hooks/useOpPermission/index.data'; diff --git a/packages/base/src/page/UserCenter/components/RoleList/List.tsx b/packages/base/src/page/UserCenter/components/RoleList/List.tsx index 103b51e0e..6909b987b 100644 --- a/packages/base/src/page/UserCenter/components/RoleList/List.tsx +++ b/packages/base/src/page/UserCenter/components/RoleList/List.tsx @@ -7,8 +7,8 @@ import { useTableRequestError, useTableRequestParams, TableToolbar -} from '@actiontech/shared/lib/components/ActiontechTable'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +} from '@actiontech/dms-kit/es/components/ActiontechTable'; +import { ResponseCode } from '@actiontech/dms-kit'; import { IListRole } from '@actiontech/shared/lib/api/base/service/common'; import Role from '@actiontech/shared/lib/api/base/service/Role'; import { ModalName } from '../../../../data/ModalName'; diff --git a/packages/base/src/page/UserCenter/components/RoleList/column.tsx b/packages/base/src/page/UserCenter/components/RoleList/column.tsx index 8006fa2a2..5d8274dc0 100644 --- a/packages/base/src/page/UserCenter/components/RoleList/column.tsx +++ b/packages/base/src/page/UserCenter/components/RoleList/column.tsx @@ -1,12 +1,12 @@ import { IListRole } from '@actiontech/shared/lib/api/base/service/common'; -import { ActiontechTableColumn } from '@actiontech/shared/lib/components/ActiontechTable/index.type'; +import { ActiontechTableColumn } from '@actiontech/dms-kit/es/components/ActiontechTable/index.type'; import { ListRoleStatEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; import { orderBy } from 'lodash'; import { t } from '../../../../locale'; import generateTag from '../../utils/generateTag'; import { Space, Popover, Typography } from 'antd'; import { BasicTypographyEllipsis } from '@actiontech/shared'; -import { TableColumnWithIconStyleWrapper } from '@actiontech/shared/lib/styleWrapper/element'; +import { TableColumnWithIconStyleWrapper } from '@actiontech/dms-kit'; import { CheckHexagonOutlined, CloseHexagonOutlined } from '@actiontech/icons'; import { groupBy } from 'lodash'; diff --git a/packages/base/src/page/UserCenter/components/UserList/List.tsx b/packages/base/src/page/UserCenter/components/UserList/List.tsx index 40f04468b..af5ac534b 100644 --- a/packages/base/src/page/UserCenter/components/UserList/List.tsx +++ b/packages/base/src/page/UserCenter/components/UserList/List.tsx @@ -8,8 +8,8 @@ import { useTableRequestError, useTableRequestParams, TableToolbar -} from '@actiontech/shared/lib/components/ActiontechTable'; -import { ResponseCode } from '@actiontech/shared/lib/enum'; +} from '@actiontech/dms-kit/es/components/ActiontechTable'; +import { ResponseCode } from '@actiontech/dms-kit'; import { IListUser } from '@actiontech/shared/lib/api/base/service/common'; import { IListUsersParams } from '@actiontech/shared/lib/api/base/service/User/index.d'; import User from '@actiontech/shared/lib/api/base/service/User'; diff --git a/packages/base/src/page/UserCenter/components/UserList/__tests__/UserList.test.tsx b/packages/base/src/page/UserCenter/components/UserList/__tests__/UserList.test.tsx index 18b55df13..36bd84d62 100644 --- a/packages/base/src/page/UserCenter/components/UserList/__tests__/UserList.test.tsx +++ b/packages/base/src/page/UserCenter/components/UserList/__tests__/UserList.test.tsx @@ -18,7 +18,7 @@ import EventEmitter from '../../../../../utils/EventEmitter'; import EmitterKey from '../../../../../data/EmitterKey'; import { UserCenterListEnum } from '../../../index.enum'; import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser'; -import { SystemRole } from '@actiontech/shared/lib/enum'; +import { SystemRole } from '@actiontech/dms-kit'; jest.mock('react-redux', () => { return { diff --git a/packages/base/src/page/UserCenter/components/UserList/action.ts b/packages/base/src/page/UserCenter/components/UserList/action.ts index e680e6874..84f86db2f 100644 --- a/packages/base/src/page/UserCenter/components/UserList/action.ts +++ b/packages/base/src/page/UserCenter/components/UserList/action.ts @@ -4,7 +4,7 @@ import { PERMISSIONS } from '@actiontech/shared/lib/features'; import { t } from '../../../../locale'; -import { OpPermissionTypeUid, SystemRole } from '@actiontech/shared/lib/enum'; +import { OpPermissionTypeUid, SystemRole } from '@actiontech/dms-kit'; export const UserListActions = ( onEditUser: (record?: IListUser) => void, diff --git a/packages/base/src/page/UserCenter/components/UserList/column.tsx b/packages/base/src/page/UserCenter/components/UserList/column.tsx index 4633a13a6..67799a4d3 100644 --- a/packages/base/src/page/UserCenter/components/UserList/column.tsx +++ b/packages/base/src/page/UserCenter/components/UserList/column.tsx @@ -2,11 +2,11 @@ import { IListUser } from '@actiontech/shared/lib/api/base/service/common'; import { ActiontechTableColumn, ActiontechTableActionMeta -} from '@actiontech/shared/lib/components/ActiontechTable/index.type'; +} from '@actiontech/dms-kit/es/components/ActiontechTable/index.type'; import { ListUserStatEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; import { t } from '../../../../locale'; -import { TableColumnWithIconStyleWrapper } from '@actiontech/shared/lib/styleWrapper/element'; -import { OpPermissionTypeUid, SystemRole } from '@actiontech/shared/lib/enum'; +import { TableColumnWithIconStyleWrapper } from '@actiontech/dms-kit'; +import { OpPermissionTypeUid, SystemRole } from '@actiontech/dms-kit'; import { CheckHexagonOutlined, CloseHexagonOutlined } from '@actiontech/icons'; import SystemRoleTagList from '../../../../components/SystemRoleTagList'; import ProjectTagList from '../../../../components/ProjectTagList'; diff --git a/packages/base/src/page/UserCenter/index.tsx b/packages/base/src/page/UserCenter/index.tsx index a5416ac3b..bdba8ddff 100644 --- a/packages/base/src/page/UserCenter/index.tsx +++ b/packages/base/src/page/UserCenter/index.tsx @@ -1,12 +1,9 @@ import { useState } from 'react'; import { useDispatch } from 'react-redux'; import { Space } from 'antd'; -import { - PageHeader, - SegmentedTabs, - SegmentedTabsProps -} from '@actiontech/shared'; -import { TableRefreshButton } from '@actiontech/shared/lib/components/ActiontechTable'; +import { PageHeader, SegmentedTabs } from '@actiontech/dms-kit'; +import { SegmentedTabsProps } from '@actiontech/dms-kit'; +import { TableRefreshButton } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { UserCenterListEnum } from './index.enum'; import { useTranslation } from 'react-i18next'; import UserManageDrawer from './Drawer'; @@ -18,18 +15,13 @@ import PermissionList from './components/PermissionList/List'; import eventEmitter from '../../utils/EventEmitter'; import EmitterKey from '../../data/EmitterKey'; import { UserCenterPageHeaderActions } from './action'; - const UserCenter: React.FC = () => { const { t } = useTranslation(); - const dispatch = useDispatch(); - const [activePage, setActivePage] = useState(UserCenterListEnum.user_list); - const onRefreshTable = () => { eventEmitter.emit(EmitterKey.DMS_Refresh_User_Center_List); }; - const pageItems: SegmentedTabsProps['items'] = [ { value: UserCenterListEnum.user_list, @@ -47,7 +39,6 @@ const UserCenter: React.FC = () => { children: } ]; - const renderExtraButton = () => { const handleClick = (modalName: ModalName) => { dispatch( @@ -57,12 +48,10 @@ const UserCenter: React.FC = () => { }) ); }; - const pageHeaderActions = UserCenterPageHeaderActions( activePage, handleClick ); - return ( <> {pageHeaderActions['add_user']} @@ -70,11 +59,9 @@ const UserCenter: React.FC = () => { ); }; - const handleTabChange = (key: UserCenterListEnum) => { setActivePage(key); }; - return (
{
); }; - export default UserCenter; diff --git a/packages/base/src/page/UserCenter/utils/generateTag.tsx b/packages/base/src/page/UserCenter/utils/generateTag.tsx index c8381d075..430c3b6d7 100644 --- a/packages/base/src/page/UserCenter/utils/generateTag.tsx +++ b/packages/base/src/page/UserCenter/utils/generateTag.tsx @@ -1,6 +1,5 @@ -import { BasicTag } from '@actiontech/shared'; +import { BasicTag } from '@actiontech/dms-kit'; import { IUidWithName } from '@actiontech/shared/lib/api/base/service/common'; - export default function generateTag(list: IUidWithName[]) { return list?.map((r) => {r.name}); } diff --git a/packages/base/src/router/router.base.tsx b/packages/base/src/router/router.base.tsx index 5980af50b..59c1b3ea3 100644 --- a/packages/base/src/router/router.base.tsx +++ b/packages/base/src/router/router.base.tsx @@ -1,6 +1,6 @@ // @warn/cli/create-dms-page import { PERMISSIONS } from '@actiontech/shared/lib/features'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import { ROUTE_PATHS } from '@actiontech/dms-kit'; import { RouterConfigItem } from '@actiontech/shared/lib/types/common.type'; import React from 'react'; // #if [ee] diff --git a/packages/base/src/router/router.tsx b/packages/base/src/router/router.tsx index b25b2cc77..814468224 100644 --- a/packages/base/src/router/router.tsx +++ b/packages/base/src/router/router.tsx @@ -6,7 +6,7 @@ import { BaseGlobalRouterConfig, BaseProjectRouterConfig } from './router.base'; -import { ROUTE_PATHS } from '@actiontech/shared/lib/data/routePaths'; +import { ROUTE_PATHS } from '@actiontech/dms-kit'; // #if [sqle] import { diff --git a/packages/base/src/store/availabilityZone/__tests__/index.test.ts b/packages/base/src/store/availabilityZone/__tests__/index.test.ts index 46d2c1d0e..9f039d4ae 100644 --- a/packages/base/src/store/availabilityZone/__tests__/index.test.ts +++ b/packages/base/src/store/availabilityZone/__tests__/index.test.ts @@ -1,18 +1,14 @@ import { IReduxState } from '../..'; import reducers, { updateSelectAvailabilityZone, - updateAvailabilityZoneTips, - updateMemorizedAvailabilityZone, - updateRecentlySelectedZoneRecord + updateAvailabilityZoneTips } from '..'; describe('store/availabilityZone', () => { const state: IReduxState['availabilityZone'] = { modalStatus: {}, selectAvailabilityZone: null, - availabilityZoneTips: [], - memorizedAvailabilityZone: undefined, - recentlySelectedZoneRecord: [] + availabilityZoneTips: [] }; it('should execute updateSelectAvailabilityZone', () => { @@ -33,9 +29,7 @@ describe('store/availabilityZone', () => { expect(newState).toEqual({ modalStatus: {}, selectAvailabilityZone: zoneData, - availabilityZoneTips: [], - memorizedAvailabilityZone: undefined, - recentlySelectedZoneRecord: [] + availabilityZoneTips: [] }); }); @@ -55,50 +49,7 @@ describe('store/availabilityZone', () => { expect(newState).toEqual({ modalStatus: {}, selectAvailabilityZone: null, - availabilityZoneTips: tips, - memorizedAvailabilityZone: undefined, - recentlySelectedZoneRecord: [] - }); - }); - - it('should execute updateMemorizedAvailabilityZone', () => { - const zone = { uid: '1', name: 'test1' }; - - const newState = reducers( - state, - updateMemorizedAvailabilityZone({ - memorizedAvailabilityZone: zone - }) - ); - - expect(newState).toEqual({ - modalStatus: {}, - selectAvailabilityZone: null, - availabilityZoneTips: [], - memorizedAvailabilityZone: zone, - recentlySelectedZoneRecord: [] - }); - }); - - it('should execute updateRecentlySelectedZoneRecord', () => { - const zones = [ - { uid: '1', name: 'test1' }, - { uid: '2', name: 'test2' } - ]; - - const newState = reducers( - state, - updateRecentlySelectedZoneRecord({ - recentlySelectedZoneRecord: zones - }) - ); - - expect(newState).toEqual({ - modalStatus: {}, - selectAvailabilityZone: null, - availabilityZoneTips: [], - memorizedAvailabilityZone: undefined, - recentlySelectedZoneRecord: zones + availabilityZoneTips: tips }); }); }); diff --git a/packages/base/src/store/availabilityZone/index.ts b/packages/base/src/store/availabilityZone/index.ts index 069ea7de5..559aeef96 100644 --- a/packages/base/src/store/availabilityZone/index.ts +++ b/packages/base/src/store/availabilityZone/index.ts @@ -1,6 +1,6 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { commonModalReducer } from '../common'; -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; import { IGateway } from '@actiontech/shared/lib/api/base/service/common'; import { IUidWithName } from '@actiontech/shared/lib/api/base/service/common'; @@ -8,16 +8,12 @@ type AvailabilityZoneReduxState = { modalStatus: ModalStatus; selectAvailabilityZone: IGateway | null; availabilityZoneTips: IUidWithName[]; - memorizedAvailabilityZone: IUidWithName | undefined; - recentlySelectedZoneRecord: IUidWithName[]; }; const initialState: AvailabilityZoneReduxState = { modalStatus: {}, selectAvailabilityZone: null, - availabilityZoneTips: [], - memorizedAvailabilityZone: undefined, - recentlySelectedZoneRecord: [] + availabilityZoneTips: [] }; const dmsAvailabilityZone = createSlice({ @@ -40,22 +36,6 @@ const dmsAvailabilityZone = createSlice({ ) { state.availabilityZoneTips = availabilityZoneTips; }, - updateMemorizedAvailabilityZone( - state, - { - payload: { memorizedAvailabilityZone } - }: PayloadAction<{ memorizedAvailabilityZone: IUidWithName | undefined }> - ) { - state.memorizedAvailabilityZone = memorizedAvailabilityZone; - }, - updateRecentlySelectedZoneRecord( - state, - { - payload: { recentlySelectedZoneRecord } - }: PayloadAction<{ recentlySelectedZoneRecord: IUidWithName[] }> - ) { - state.recentlySelectedZoneRecord = recentlySelectedZoneRecord; - }, ...commonModalReducer() } }); @@ -64,9 +44,7 @@ export const { updateSelectAvailabilityZone, initModalStatus: initAvailabilityZoneModalStatus, updateModalStatus: updateAvailabilityZoneModalStatus, - updateAvailabilityZoneTips, - updateMemorizedAvailabilityZone, - updateRecentlySelectedZoneRecord + updateAvailabilityZoneTips } = dmsAvailabilityZone.actions; export default dmsAvailabilityZone.reducer; diff --git a/packages/base/src/store/cloudBeaver/index.ts b/packages/base/src/store/cloudBeaver/index.ts index 8539bb120..02f2858a8 100644 --- a/packages/base/src/store/cloudBeaver/index.ts +++ b/packages/base/src/store/cloudBeaver/index.ts @@ -1,6 +1,6 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { commonModalReducer } from '../common'; -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; import { ICBOperationLog } from '@actiontech/shared/lib/api/base/service/common'; type MemberReduxState = { diff --git a/packages/base/src/store/common/index.test.ts b/packages/base/src/store/common/index.test.ts index 0de62d0bb..c018834d2 100644 --- a/packages/base/src/store/common/index.test.ts +++ b/packages/base/src/store/common/index.test.ts @@ -1,6 +1,6 @@ import { createSlice } from '@reduxjs/toolkit'; import { commonModalReducer } from '.'; -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; describe('store/common', () => { const testStore = createSlice({ diff --git a/packages/base/src/store/common/index.ts b/packages/base/src/store/common/index.ts index d4ed308ae..df5de48a9 100644 --- a/packages/base/src/store/common/index.ts +++ b/packages/base/src/store/common/index.ts @@ -1,4 +1,4 @@ -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; import { PayloadAction } from '@reduxjs/toolkit'; export const commonModalReducer = < diff --git a/packages/base/src/store/dataExport/index.ts b/packages/base/src/store/dataExport/index.ts index ed96575bd..e01037889 100644 --- a/packages/base/src/store/dataExport/index.ts +++ b/packages/base/src/store/dataExport/index.ts @@ -1,4 +1,4 @@ -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; import { PayloadAction, createSlice } from '@reduxjs/toolkit'; import { commonModalReducer } from '../common'; import { diff --git a/packages/base/src/store/index.ts b/packages/base/src/store/index.ts index dca145736..9195df4e4 100644 --- a/packages/base/src/store/index.ts +++ b/packages/base/src/store/index.ts @@ -1,7 +1,7 @@ import { configureStore } from '@reduxjs/toolkit'; import { baseStoreData } from './base'; import { SQLEStoreData } from 'sqle/src/store'; -import { findDuplicateKeys } from '@actiontech/shared/lib/utils/Common'; +import { findDuplicateKeys } from '@actiontech/dms-kit'; // #if [DEV] const dupKeys = findDuplicateKeys([baseStoreData, SQLEStoreData]); diff --git a/packages/base/src/store/member/index.ts b/packages/base/src/store/member/index.ts index 93f02281c..54dfaf674 100644 --- a/packages/base/src/store/member/index.ts +++ b/packages/base/src/store/member/index.ts @@ -1,6 +1,6 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { commonModalReducer } from '../common'; -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; import { IListMember, IListMemberGroup diff --git a/packages/base/src/store/nav/index.ts b/packages/base/src/store/nav/index.ts index ff93957b9..a63030636 100644 --- a/packages/base/src/store/nav/index.ts +++ b/packages/base/src/store/nav/index.ts @@ -1,5 +1,5 @@ import { createSlice } from '@reduxjs/toolkit'; -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; import { commonModalReducer } from '../common'; type NavReduxState = { diff --git a/packages/base/src/store/permission/index.ts b/packages/base/src/store/permission/index.ts index 6e339b6b0..7c6a8ad22 100644 --- a/packages/base/src/store/permission/index.ts +++ b/packages/base/src/store/permission/index.ts @@ -1,6 +1,6 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit'; import { IGetUserOpPermissionReply } from '@actiontech/shared/lib/api/base/service/common'; -import { ModuleFeatureSupportStatus } from '@actiontech/shared/lib/enum'; +import { ModuleFeatureSupportStatus } from '@actiontech/dms-kit'; type PermissionState = { moduleFeatureSupport: ModuleFeatureSupportStatus; diff --git a/packages/base/src/store/project/index.ts b/packages/base/src/store/project/index.ts index 20d6553d6..db4b7fa54 100644 --- a/packages/base/src/store/project/index.ts +++ b/packages/base/src/store/project/index.ts @@ -1,6 +1,6 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { commonModalReducer } from '../common'; -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; import { IListProjectV2 } from '@actiontech/shared/lib/api/base/service/common'; type ProjectReduxState = { diff --git a/packages/base/src/store/system/index.test.ts b/packages/base/src/store/system/index.test.ts index 52db915a3..fd72947a0 100644 --- a/packages/base/src/store/system/index.test.ts +++ b/packages/base/src/store/system/index.test.ts @@ -1,7 +1,7 @@ import reducers, { updateWebTitleAndLogo } from '.'; import { IReduxState } from '..'; -import { DMS_DEFAULT_WEB_TITLE } from '@actiontech/shared/lib/data/common'; +import { DMS_DEFAULT_WEB_TITLE } from '@actiontech/dms-kit'; describe('store system', () => { const state: IReduxState['system'] = { diff --git a/packages/base/src/store/system/index.ts b/packages/base/src/store/system/index.ts index 397b76c26..ec667592a 100644 --- a/packages/base/src/store/system/index.ts +++ b/packages/base/src/store/system/index.ts @@ -1,7 +1,7 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit'; import { commonModalReducer } from '../common'; -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; -import { DMS_DEFAULT_WEB_TITLE } from '@actiontech/shared/lib/data/common'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; +import { DMS_DEFAULT_WEB_TITLE } from '@actiontech/dms-kit'; type SystemReduxState = { modalStatus: ModalStatus; diff --git a/packages/base/src/store/user/index.test.ts b/packages/base/src/store/user/index.test.ts index dc5d8a218..5de8fc3a6 100644 --- a/packages/base/src/store/user/index.test.ts +++ b/packages/base/src/store/user/index.test.ts @@ -6,16 +6,18 @@ import reducers, { updateUserInfoFetchStatus, updateBindProjects, updateManagementPermissions, - updateLanguage + updateLanguage, + updateSystemPreference } from '.'; import { IReduxState } from '..'; -import { LocalStorageWrapper } from '@actiontech/shared'; +import { LocalStorageWrapper } from '@actiontech/dms-kit'; import { StorageKey, SupportLanguage, SupportTheme, SystemRole -} from '@actiontech/shared/lib/enum'; +} from '@actiontech/dms-kit'; +import { GetUserSystemEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; describe('store user', () => { const state: IReduxState['user'] = { @@ -30,7 +32,8 @@ describe('store user', () => { managementPermissions: [], role: '', isUserInfoFetched: false, - language: SupportLanguage.zhCN + language: SupportLanguage.zhCN, + systemPreference: undefined }; it('should update token when dispatch updateToken action', () => { @@ -50,7 +53,8 @@ describe('store user', () => { bindProjects: [], managementPermissions: [], role: '', - isUserInfoFetched: false + isUserInfoFetched: false, + systemPreference: undefined }); }); @@ -71,7 +75,8 @@ describe('store user', () => { bindProjects: [], managementPermissions: [], role: '', - isUserInfoFetched: false + isUserInfoFetched: false, + systemPreference: undefined }); }); @@ -93,7 +98,8 @@ describe('store user', () => { bindProjects: [], managementPermissions: [], role: '', - isUserInfoFetched: false + isUserInfoFetched: false, + systemPreference: undefined }); }); @@ -115,7 +121,8 @@ describe('store user', () => { bindProjects: [], managementPermissions: [], role: SystemRole.admin, - isUserInfoFetched: false + isUserInfoFetched: false, + systemPreference: undefined }); }); @@ -136,7 +143,8 @@ describe('store user', () => { bindProjects: [], managementPermissions: [], role: '', - isUserInfoFetched: false + isUserInfoFetched: false, + systemPreference: undefined }); }); @@ -152,7 +160,8 @@ describe('store user', () => { bindProjects: [], managementPermissions: [], role: '', - isUserInfoFetched: true + isUserInfoFetched: true, + systemPreference: undefined }); }); @@ -181,7 +190,8 @@ describe('store user', () => { bindProjects: mockBindProjects, managementPermissions: [], role: '', - isUserInfoFetched: false + isUserInfoFetched: false, + systemPreference: undefined }); }); @@ -203,7 +213,30 @@ describe('store user', () => { bindProjects: [], managementPermissions: mockManagementPermissions, role: '', - isUserInfoFetched: false + isUserInfoFetched: false, + systemPreference: undefined + }); + }); + + it('should update systemPreference when dispatch updateSystemPreference action', () => { + const newState = reducers( + state, + updateSystemPreference({ + systemPreference: GetUserSystemEnum.MANAGEMENT + }) + ); + expect(newState).not.toBe(state); + expect(newState).toEqual({ + username: '', + uid: '', + token: '', + theme: SupportTheme.LIGHT, + language: SupportLanguage.zhCN, + bindProjects: [], + managementPermissions: [], + role: '', + isUserInfoFetched: false, + systemPreference: GetUserSystemEnum.MANAGEMENT }); }); }); diff --git a/packages/base/src/store/user/index.ts b/packages/base/src/store/user/index.ts index 9df2cdf4b..4c3bd4675 100644 --- a/packages/base/src/store/user/index.ts +++ b/packages/base/src/store/user/index.ts @@ -1,16 +1,17 @@ -import { LocalStorageWrapper } from '@actiontech/shared'; import { StorageKey, + LocalStorageWrapper, SupportLanguage, SupportTheme, SystemRole -} from '@actiontech/shared/lib/enum'; +} from '@actiontech/dms-kit'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { IUidWithName, IUserBindProject } from '@actiontech/shared/lib/api/base/service/common'; -import { DEFAULT_LANGUAGE } from '@actiontech/shared/lib/locale'; +import { DEFAULT_LANGUAGE } from '@actiontech/dms-kit'; +import { GetUserSystemEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; export type IBindProject = { archived?: boolean } & IUserBindProject; @@ -24,6 +25,7 @@ type UserReduxState = { uid: string; isUserInfoFetched: boolean; language: SupportLanguage; + systemPreference?: GetUserSystemEnum; }; const initialState: UserReduxState = { @@ -41,7 +43,8 @@ const initialState: UserReduxState = { language: LocalStorageWrapper.getOrDefault( StorageKey.Language, DEFAULT_LANGUAGE - ) as SupportLanguage + ) as SupportLanguage, + systemPreference: undefined }; const user = createSlice({ @@ -107,6 +110,14 @@ const user = createSlice({ }, updateUserInfoFetchStatus: (state, { payload }: PayloadAction) => { state.isUserInfoFetched = payload; + }, + updateSystemPreference: ( + state, + { + payload: { systemPreference } + }: PayloadAction<{ systemPreference?: GetUserSystemEnum }> + ) => { + state.systemPreference = systemPreference; } } }); @@ -119,7 +130,8 @@ export const { updateBindProjects, updateManagementPermissions, updateUserUid, - updateUserInfoFetchStatus + updateUserInfoFetchStatus, + updateSystemPreference } = user.actions; export default user.reducer; diff --git a/packages/base/src/store/userCenter/index.ts b/packages/base/src/store/userCenter/index.ts index 0716d0b78..3060aa464 100644 --- a/packages/base/src/store/userCenter/index.ts +++ b/packages/base/src/store/userCenter/index.ts @@ -1,6 +1,6 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { commonModalReducer } from '../common'; -import { ModalStatus } from '@actiontech/shared/lib/types/common.type'; +import { ModalStatus } from '@actiontech/dms-kit/es/types/common.type'; import { IListUser, IListUserGroup, diff --git a/packages/base/src/testUtils/mockHooks/data.tsx b/packages/base/src/testUtils/mockHooks/data.tsx index b42434b60..9f70ce8b6 100644 --- a/packages/base/src/testUtils/mockHooks/data.tsx +++ b/packages/base/src/testUtils/mockHooks/data.tsx @@ -9,11 +9,8 @@ export const mockSystemConfigData = { export const mockUseRecentlySelectedZoneData = { availabilityZone: undefined, updateRecentlySelectedZone: jest.fn(), - recentlySelectedZoneRecord: [], setAvailabilityZone: jest.fn(), - setRecentlySelectedZoneRecord: jest.fn(), initializeAvailabilityZone: jest.fn(), verifyRecentlySelectedZoneRecord: jest.fn(), - availabilityZoneOptions: [], clearRecentlySelectedZone: jest.fn() }; diff --git a/packages/base/src/testUtils/mockHooks/mockUseRecentlySelectedZone.ts b/packages/base/src/testUtils/mockHooks/mockUseRecentlySelectedZone.ts index d726704c7..c66ab2faf 100644 --- a/packages/base/src/testUtils/mockHooks/mockUseRecentlySelectedZone.ts +++ b/packages/base/src/testUtils/mockHooks/mockUseRecentlySelectedZone.ts @@ -1,4 +1,4 @@ -import * as useRecentlySelectedZone from '../../hooks/useRecentlySelectedZone'; +import * as useRecentlySelectedZone from '@actiontech/dms-kit/es/features/useRecentlySelectedZone'; import { mockUseRecentlySelectedZoneData } from './data'; export const mockUseRecentlySelectedZone = ( diff --git a/packages/base/src/testUtils/superRender.tsx b/packages/base/src/testUtils/superRender.tsx index a4926905b..d02434347 100644 --- a/packages/base/src/testUtils/superRender.tsx +++ b/packages/base/src/testUtils/superRender.tsx @@ -5,7 +5,7 @@ import { RenderParams } from '@actiontech/shared/lib/testUtil/superRender'; import { renderHook } from '@testing-library/react-hooks'; -import lightTheme from '@actiontech/shared/lib/theme/light'; +import { lightTheme } from '@actiontech/dms-kit'; import basePackageTheme from '../theme/light'; const themeData = { diff --git a/packages/base/src/theme/dark/dataExport.ts b/packages/base/src/theme/dark/dataExport.ts index 91bf7d948..4f8c0a701 100644 --- a/packages/base/src/theme/dark/dataExport.ts +++ b/packages/base/src/theme/dark/dataExport.ts @@ -1,4 +1,4 @@ -import { darkThemeUI } from '@actiontech/shared/lib/theme/dark/basic'; +import { darkThemeUI } from '@actiontech/dms-kit/es/theme/dark/basic'; import { DataExportTheme } from '../type'; import { WorkflowRecordStatusEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; diff --git a/packages/base/src/theme/dark/guidance.ts b/packages/base/src/theme/dark/guidance.ts index f7db367d1..1a741a8ce 100644 --- a/packages/base/src/theme/dark/guidance.ts +++ b/packages/base/src/theme/dark/guidance.ts @@ -1,7 +1,7 @@ import { darkThemeUI, darkThemeBasic -} from '@actiontech/shared/lib/theme/dark/basic'; +} from '@actiontech/dms-kit/es/theme/dark/basic'; import { GuidanceTheme } from '../type'; export const guidanceTheme: GuidanceTheme = { diff --git a/packages/base/src/theme/dark/sideMenu.ts b/packages/base/src/theme/dark/sideMenu.ts index 0bcb2ec73..c31559f43 100644 --- a/packages/base/src/theme/dark/sideMenu.ts +++ b/packages/base/src/theme/dark/sideMenu.ts @@ -1,4 +1,4 @@ -import { darkThemeUI } from '@actiontech/shared/lib/theme/dark/basic'; +import { darkThemeUI } from '@actiontech/dms-kit/es/theme/dark/basic'; import { SideMenuTheme } from '../type'; export const sideMenuTheme: SideMenuTheme = { diff --git a/packages/base/src/theme/dark/system.ts b/packages/base/src/theme/dark/system.ts index 4f52d5a98..69407efd5 100644 --- a/packages/base/src/theme/dark/system.ts +++ b/packages/base/src/theme/dark/system.ts @@ -1,4 +1,4 @@ -import { darkThemeUI } from '@actiontech/shared/lib/theme/dark/basic'; +import { darkThemeUI } from '@actiontech/dms-kit/es/theme/dark/basic'; import { SystemTheme } from '../type'; export const systemTheme: SystemTheme = { diff --git a/packages/base/src/theme/index.ts b/packages/base/src/theme/index.ts index 149bb9572..f190c7869 100644 --- a/packages/base/src/theme/index.ts +++ b/packages/base/src/theme/index.ts @@ -1,8 +1,10 @@ -import sharedDarkTheme from '@actiontech/shared/lib/theme/dark'; -import sharedLightTheme from '@actiontech/shared/lib/theme/light'; import lightTheme from './light'; import darkTheme from './dark'; -import { SupportTheme } from '@actiontech/shared/lib/enum'; +import { + SupportTheme, + darkTheme as sharedDarkTheme, + lightTheme as sharedLightTheme +} from '@actiontech/dms-kit'; const ThemeData = { [SupportTheme.DARK]: { diff --git a/packages/base/src/theme/light/dataExport.ts b/packages/base/src/theme/light/dataExport.ts index c99262a29..9d42a2875 100644 --- a/packages/base/src/theme/light/dataExport.ts +++ b/packages/base/src/theme/light/dataExport.ts @@ -1,4 +1,4 @@ -import { lightThemeUI } from '@actiontech/shared/lib/theme/light/basic'; +import { lightThemeUI } from '@actiontech/dms-kit/es/theme/light/basic'; import { DataExportTheme } from '../type'; import { WorkflowRecordStatusEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; diff --git a/packages/base/src/theme/light/guidance.ts b/packages/base/src/theme/light/guidance.ts index cb8b8a983..0e7efe9e6 100644 --- a/packages/base/src/theme/light/guidance.ts +++ b/packages/base/src/theme/light/guidance.ts @@ -1,7 +1,7 @@ import { lightThemeUI, lightThemeBasic -} from '@actiontech/shared/lib/theme/light/basic'; +} from '@actiontech/dms-kit/es/theme/light/basic'; import { GuidanceTheme } from '../type'; export const guidanceTheme: GuidanceTheme = { diff --git a/packages/base/src/theme/light/sideMenu.ts b/packages/base/src/theme/light/sideMenu.ts index 14763c031..13f35a987 100644 --- a/packages/base/src/theme/light/sideMenu.ts +++ b/packages/base/src/theme/light/sideMenu.ts @@ -1,4 +1,4 @@ -import { lightThemeUI } from '@actiontech/shared/lib/theme/light/basic'; +import { lightThemeUI } from '@actiontech/dms-kit/es/theme/light/basic'; import { SideMenuTheme } from '../type'; export const sideMenuTheme: SideMenuTheme = { diff --git a/packages/base/src/theme/light/system.ts b/packages/base/src/theme/light/system.ts index da4f05b25..5d006855b 100644 --- a/packages/base/src/theme/light/system.ts +++ b/packages/base/src/theme/light/system.ts @@ -1,4 +1,4 @@ -import { lightThemeUI } from '@actiontech/shared/lib/theme/light/basic'; +import { lightThemeUI } from '@actiontech/dms-kit/es/theme/light/basic'; import { SystemTheme } from '../type'; export const systemTheme: SystemTheme = { diff --git a/packages/base/src/utils/EventEmitter.ts b/packages/base/src/utils/EventEmitter.ts index 1a56cb196..521dd819a 100644 --- a/packages/base/src/utils/EventEmitter.ts +++ b/packages/base/src/utils/EventEmitter.ts @@ -1,4 +1,4 @@ -import { EventEmitter } from '@actiontech/shared'; +import { EventEmitter } from '@actiontech/dms-kit'; import EmitterKey from '../data/EmitterKey'; const eventEmitter = new EventEmitter(); diff --git a/packages/base/tsconfig.json b/packages/base/tsconfig.json index a4cb7b26e..740aafa02 100644 --- a/packages/base/tsconfig.json +++ b/packages/base/tsconfig.json @@ -4,6 +4,7 @@ "compilerOptions": { "paths": { "~/*": ["./src/*"] - } + }, + "skipLibCheck": true } } diff --git a/packages/base/vite.config.mts b/packages/base/vite.config.mts index d1d4eccac..3b1c287ed 100644 --- a/packages/base/vite.config.mts +++ b/packages/base/vite.config.mts @@ -53,7 +53,8 @@ export default defineConfig(() => { eslint({ exclude: [ '**/node_modules/**', - '**/packages/**/lib/api/**', + '**/packages/**/lib/**', + '**/packages/**/es/**', '!**/packages/**/lib/api/common/**' ] }), diff --git a/packages/dms-kit/.dumi/theme/slots/HeaderExtra/index.tsx b/packages/dms-kit/.dumi/theme/slots/HeaderExtra/index.tsx new file mode 100644 index 000000000..155605014 --- /dev/null +++ b/packages/dms-kit/.dumi/theme/slots/HeaderExtra/index.tsx @@ -0,0 +1,2 @@ +import HeaderExtra from '../../../../../../DumiHeaderExtraSlots'; +export default HeaderExtra; diff --git a/packages/dms-kit/.dumirc.ts b/packages/dms-kit/.dumirc.ts new file mode 100644 index 000000000..29575ccb8 --- /dev/null +++ b/packages/dms-kit/.dumirc.ts @@ -0,0 +1,55 @@ +import { defineConfig } from 'dumi'; +import { join } from 'path'; +import { version } from './package.json'; + +export default defineConfig({ + outputPath: 'docs-dist', + publicPath: `/dms-docs/`, + base: `/dms-docs/`, + themeConfig: { + name: 'DMS-Kit', + nav: [{ title: '组件', link: '/components' }] + }, + resolve: { + atomDirs: [{ type: 'components', dir: 'src/components' }] + }, + // 配置dumi忽略某些文件,仅用于文档生成 + conventionRoutes: { + // 排除测试文件 + exclude: [ + /\/demo\//, + /\/demos\//, + /\/__tests__\//, + /\/__snapshots__\//, + /\.test\.(ts|tsx|js|jsx)$/, + /\.snap$/, + /\/testUtil\// + ] + }, + alias: { + '@actiontech/dms-kit': join(__dirname, 'src'), + '@actiontech/icons': join(__dirname, '../icons/src') + }, + styles: [ + `html, body { + background: transparent; + }`, + `.dumi-default-toc { + display: none !important; + } + .dumi-default-doc-layout > main { + max-width: 100% !important; + } + .dumi-default-sidebar { + width: 20% !important; + min-width: 200px !important; + max-width: 400px !important; + } + ` + ], + mfsu: false, + hash: true, + define: { + VERSION: version + } +}); diff --git a/packages/dms-kit/.fatherrc.ts b/packages/dms-kit/.fatherrc.ts new file mode 100644 index 000000000..e49271e55 --- /dev/null +++ b/packages/dms-kit/.fatherrc.ts @@ -0,0 +1,36 @@ +import { defineConfig } from 'father'; + +export default defineConfig({ + // 排除不需要打包的文件 + sourcemap: false, + esm: { + output: 'es', + transformer: 'babel', + ignores: [ + 'src/**/demo/**', + 'src/**/demos/**', + 'src/**/__tests__/**', + 'src/**/__snapshots__/**', + 'src/**/*.test.ts', + 'src/**/*.test.tsx', + 'src/**/*.snap', + 'src/testUtil/**', + 'src/**/*.md' + ] + }, + cjs: { + output: 'lib', + transformer: 'babel', + ignores: [ + 'src/**/demo/**', + 'src/**/demos/**', + 'src/**/__tests__/**', + 'src/**/__snapshots__/**', + 'src/**/*.test.ts', + 'src/**/*.test.tsx', + 'src/**/*.snap', + 'src/testUtil/**', + 'src/**/*.md' + ] + } +}); diff --git a/packages/dms-kit/.npmrc b/packages/dms-kit/.npmrc new file mode 100644 index 000000000..0757ca96e --- /dev/null +++ b/packages/dms-kit/.npmrc @@ -0,0 +1,2 @@ +registry=https://registry.npmmirror.com +@actiontech:registry=http://10.186.18.19:4873/ diff --git a/packages/dms-kit/README.md b/packages/dms-kit/README.md new file mode 100644 index 000000000..3ad3f7d26 --- /dev/null +++ b/packages/dms-kit/README.md @@ -0,0 +1,61 @@ +# @actiontech/dms-kit + +DMS Kit 是 ActionTech DMS 项目的共享组件库,提供了一套完整的 React 组件、工具函数、主题配置和类型定义。 + +## 安装 + +```bash +npm install @actiontech/dms-kit +# 或 +pnpm add @actiontech/dms-kit +``` + +## 使用 + +### 组件导入 + +```typescript +import { ActionButton, BasicTable, CustomForm } from '@actiontech/dms-kit'; +``` + +### 工具函数导入 + +```typescript +import { formatTime, validateEmail } from '@actiontech/dms-kit'; +``` + +### 主题配置导入 + +```typescript +import { darkTheme, lightTheme } from '@actiontech/dms-kit'; +``` + +### 类型定义导入 + +```typescript +import type { ThemeConfig } from '@actiontech/dms-kit'; +``` + +## 依赖要求 + +- React >= 17 +- React DOM >= 17 +- Antd >= 5.7.3 + +## 开发 + +### 构建 + +```bash +pnpm build +``` + +### 开发模式 + +```bash +pnpm dev +``` + +## 许可证 + +MIT diff --git a/packages/dms-kit/docs/CHANGELOG.md b/packages/dms-kit/docs/CHANGELOG.md new file mode 100644 index 000000000..8a5171707 --- /dev/null +++ b/packages/dms-kit/docs/CHANGELOG.md @@ -0,0 +1,10 @@ +--- +nav: + title: changelog + order: 2 +--- + +# changelog + +## 0.0.2 +- 该版本主要为版本号更新,无代码变更。 \ No newline at end of file diff --git a/packages/dms-kit/docs/components.md b/packages/dms-kit/docs/components.md new file mode 100644 index 000000000..8b6f6b400 --- /dev/null +++ b/packages/dms-kit/docs/components.md @@ -0,0 +1,72 @@ +--- +title: 组件总览 +--- + +## 组件库简介 + +dms-kit 是一个基于 Ant Design 封装的业务组件库,提供统一的样式规范和增强的功能特性,支持 React 17 及以上版本。 + +## 快速上手 + +### 安装依赖 + +```bash +npm install @actiontech/dms-kit +``` + +### 基础用法 + +```tsx +import React from 'react'; +import { ConfigProvider, BasicButton, BasicInput, BasicSelect } from '@actiontech/dms-kit'; + +const App = () => ( + + 按钮 + + + +); + +export default App; +``` + +## 定制主题 + +所有组件都支持主题系统,可通过 `ConfigProvider` 的 `theme` 和 `themeData` 属性进行配置。例如切换深色主题: + +``` +import React from 'react'; +import { ConfigProvider, SupportTheme } from '@actiontech/dms-kit'; + +const App = () => ( + + {/* 你的应用 */} + +); + +export default App; +``` + +## 国际化 + +组件库内置中英文语言包,可通过 `ConfigProvider` 的 `language` 和 `resources` 属性进行切换和扩展。例如切换英文: + +``` +import React from 'react'; +import { ConfigProvider, SupportLanguage } from '@actiontech/dms-kit'; + +const App = () => ( + + {/* 你的应用 */} + +); + +export default App; +``` \ No newline at end of file diff --git a/packages/dms-kit/docs/index.md b/packages/dms-kit/docs/index.md new file mode 100644 index 000000000..f15bb49bd --- /dev/null +++ b/packages/dms-kit/docs/index.md @@ -0,0 +1,9 @@ +--- +title: dms公共库 使用文档 +hero: + title: dms公共库 + description: dms公共库 使用文档 + actions: + - text: 组件 + link: /components +--- \ No newline at end of file diff --git a/packages/dms-kit/package.json b/packages/dms-kit/package.json new file mode 100644 index 000000000..05cf82ac0 --- /dev/null +++ b/packages/dms-kit/package.json @@ -0,0 +1,65 @@ +{ + "name": "@actiontech/dms-kit", + "version": "1.0.0", + "description": "DMS Kit - React UI Components Library", + "main": "lib/index.js", + "module": "es/index.js", + "types": "es/index.d.ts", + "license": "MIT", + "files": [ + "lib", + "es", + "package.json", + "README.md" + ], + "sideEffects": false, + "scripts": { + "build": "father build", + "dev": "father dev --incremental", + "docs:dev": "dumi dev", + "docs:build": "dumi build", + "docs:preview": "dumi preview", + "test": "jest --watchAll=true", + "test:c": "jest --watchAll=false --coverage", + "test:ci": "jest --ci --watchAll=false --coverage --color --silent --testLocationInResults" + }, + "publishConfig": { + "registry": "http://10.186.18.19:4873/", + "access": "restricted" + }, + "dependencies": { + "ahooks": "^3.7.0", + "axios": ">=0.27.2", + "classnames": "^2.3.0", + "dayjs": "^1", + "rc-input-number": "~8.0.2", + "rc-tree-select": "~5.9.0", + "sql-formatter": "^12.2.4", + "nprogress": "^0.2.0", + "query-string": "^7.1.1", + "highlight.js": "^11.0.1", + "cron-parser": "^4.9.0", + "@actiontech/icons": "workspace:^" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17", + "react-router-dom": "^6.10.0", + "antd": ">=5.7.3", + "@ant-design/icons": "^4.7.0", + "@ant-design/cssinjs": "^1.17.0", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@mui/material": "^5.11.16", + "@mui/styles": "^5.11.16", + "@mui/system": "^5.9.1", + "i18next": "^21.8.14", + "react-i18next": "^11.18.6", + "typescript": "^5.0.2" + }, + "devDependencies": { + "father": "^4.5.2", + "dumi": "^2.3.8", + "babel-plugin-import": "^1.13.8" + } +} \ No newline at end of file diff --git a/packages/dms-kit/src/components/ActionButton/ActionButton.tsx b/packages/dms-kit/src/components/ActionButton/ActionButton.tsx new file mode 100644 index 000000000..a19d30d61 --- /dev/null +++ b/packages/dms-kit/src/components/ActionButton/ActionButton.tsx @@ -0,0 +1,51 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { ActionButtonProps } from './ActionButton.types'; +import { useTranslation } from 'react-i18next'; +import { Popconfirm } from 'antd'; +import { PopconfirmMessageStyleWrapper } from '../../styleWrapper/element'; +import { BasicButton } from '../BasicButton'; +import { BasicToolTip } from '../BasicToolTip'; + +const ActionButton = (props: ActionButtonProps) => { + const { t } = useTranslation(); + + if (props.actionType === 'confirm') { + const { actionType, text, confirm, ...buttonProps } = props; + return ( + + {confirm.title} + + ) : ( + confirm.title + ) + } + > + {text} + + ); + } + + if (props.actionType === 'tooltip') { + const { actionType, text, tooltip, ...buttonProps } = props; + + return ( + + {text} + + ); + } + + const { actionType, text, ...buttonProps } = props; + + return {text}; +}; + +ActionButton.displayName = 'ActionButton'; + +export default ActionButton; diff --git a/packages/dms-kit/src/components/ActionButton/ActionButton.types.ts b/packages/dms-kit/src/components/ActionButton/ActionButton.types.ts new file mode 100644 index 000000000..4c47eaf98 --- /dev/null +++ b/packages/dms-kit/src/components/ActionButton/ActionButton.types.ts @@ -0,0 +1,31 @@ +import { PopconfirmProps, SpaceProps } from 'antd'; +import { Key, ReactNode } from 'react'; +import { BasicButtonProps } from '../BasicButton'; +import { BasicTooltipProps } from '../BasicToolTip'; + +type ActionButtonBase = Omit & { + text?: ReactNode; +}; + +type ActionButtonWithNormal = { + actionType?: never; +}; + +type ActionBUttonWithConfirm = { + actionType: 'confirm'; + confirm: PopconfirmProps; +}; + +type ActionButtonWithTooltip = { + actionType: 'tooltip'; + tooltip: BasicTooltipProps; +}; + +export type ActionButtonProps = + | (ActionButtonBase & ActionBUttonWithConfirm) + | (ActionButtonBase & ActionButtonWithTooltip) + | (ActionButtonBase & ActionButtonWithNormal); + +export type ActionButtonGroupProps = { + actions: Array; +} & SpaceProps; diff --git a/packages/dms-kit/src/components/ActionButton/ActionButtonGroup.tsx b/packages/dms-kit/src/components/ActionButton/ActionButtonGroup.tsx new file mode 100644 index 000000000..a7d34fd44 --- /dev/null +++ b/packages/dms-kit/src/components/ActionButton/ActionButtonGroup.tsx @@ -0,0 +1,23 @@ +import { Space } from 'antd'; +import ActionButton from './ActionButton'; +import { ActionButtonGroupProps } from './ActionButton.types'; + +const ActionButtonGroup = ({ + actions, + ...spaceProps +}: ActionButtonGroupProps) => { + if (actions.length === 0) { + return null; + } + return ( + + {actions.map(({ key, ...action }) => { + return ; + })} + + ); +}; + +ActionButtonGroup.displayName = 'ActionButtonGroup'; + +export default ActionButtonGroup; diff --git a/packages/dms-kit/src/components/ActionButton/README.md b/packages/dms-kit/src/components/ActionButton/README.md new file mode 100644 index 000000000..e6bb860ac --- /dev/null +++ b/packages/dms-kit/src/components/ActionButton/README.md @@ -0,0 +1,14 @@ +--- +title: 对一些常见的带有其他功能按钮的封装 +category: business +--- + +## Example + +``` +TODO + +暂时先与 shared 中的 ActionButton 共存,此版本为移除了 link 相关功能的版本。主要为了解除与 react router 的耦合。 + +base、sqle 中仍然先使用 shared 中的版本,后续进行迁移并调整 link 功能的实现。 +``` diff --git a/packages/dms-kit/src/components/ActionButton/index.ts b/packages/dms-kit/src/components/ActionButton/index.ts new file mode 100644 index 000000000..db1ce89a2 --- /dev/null +++ b/packages/dms-kit/src/components/ActionButton/index.ts @@ -0,0 +1,3 @@ +export { default as ActionButton } from './ActionButton'; +export { default as ActionButtonGroup } from './ActionButtonGroup'; +export type * from './ActionButton.types'; diff --git a/packages/shared/lib/components/ActiontechTable/README.md b/packages/dms-kit/src/components/ActiontechTable/README.md similarity index 52% rename from packages/shared/lib/components/ActiontechTable/README.md rename to packages/dms-kit/src/components/ActiontechTable/README.md index b172cf567..34a4c72fd 100644 --- a/packages/shared/lib/components/ActiontechTable/README.md +++ b/packages/dms-kit/src/components/ActiontechTable/README.md @@ -7,4 +7,6 @@ category: lib ``` TODO -``` \ No newline at end of file + +改为使用 dms-kit 下的 ActionButton,解除与 react router 的耦合 +``` diff --git a/packages/shared/lib/components/ActiontechTable/Table.tsx b/packages/dms-kit/src/components/ActiontechTable/Table.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/Table.tsx rename to packages/dms-kit/src/components/ActiontechTable/Table.tsx diff --git a/packages/shared/lib/components/ActiontechTable/components/ColumnsItems.tsx b/packages/dms-kit/src/components/ActiontechTable/components/ColumnsItems.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/components/ColumnsItems.tsx rename to packages/dms-kit/src/components/ActiontechTable/components/ColumnsItems.tsx diff --git a/packages/shared/lib/components/ActiontechTable/components/ColumnsSetting.tsx b/packages/dms-kit/src/components/ActiontechTable/components/ColumnsSetting.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/components/ColumnsSetting.tsx rename to packages/dms-kit/src/components/ActiontechTable/components/ColumnsSetting.tsx index d3fd21b84..0e91117b7 100644 --- a/packages/shared/lib/components/ActiontechTable/components/ColumnsSetting.tsx +++ b/packages/dms-kit/src/components/ActiontechTable/components/ColumnsSetting.tsx @@ -4,8 +4,6 @@ import { Popover } from 'antd'; import { CatchTableColumnValueType, ColumnsSettingProps } from '../index.type'; import useTableSettings from '../hooks/useTableSettings'; import { ColumnsSettingDropdownStyleWrapper } from './style'; -import { eventEmitter } from '../../../utils/EventEmitter'; -import EmitterKey from '../../../data/EmitterKey'; import { cloneDeep } from 'lodash'; import type { DragEndEvent, DragMoveEvent } from '@dnd-kit/core'; import { @@ -24,6 +22,8 @@ import ColumnsItems, { typeFixed } from './ColumnsItems'; import { DownOutlined, UpOutlined, SettingOutlined } from '@actiontech/icons'; import { ColumnsSettingStyleWrapper } from './style'; import { BasicButton } from '../../BasicButton'; +import EmitterKey from '../../../data/EmitterKey'; +import { eventEmitter } from '../../../utils/EventEmitter'; /** * todo: diff --git a/packages/shared/lib/components/ActiontechTable/components/FilterButton.tsx b/packages/dms-kit/src/components/ActiontechTable/components/FilterButton.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/components/FilterButton.tsx rename to packages/dms-kit/src/components/ActiontechTable/components/FilterButton.tsx diff --git a/packages/shared/lib/components/ActiontechTable/components/FilterContainer.tsx b/packages/dms-kit/src/components/ActiontechTable/components/FilterContainer.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/components/FilterContainer.tsx rename to packages/dms-kit/src/components/ActiontechTable/components/FilterContainer.tsx diff --git a/packages/shared/lib/components/ActiontechTable/components/RefreshButton.tsx b/packages/dms-kit/src/components/ActiontechTable/components/RefreshButton.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/components/RefreshButton.tsx rename to packages/dms-kit/src/components/ActiontechTable/components/RefreshButton.tsx diff --git a/packages/shared/lib/components/ActiontechTable/components/SearchInput.tsx b/packages/dms-kit/src/components/ActiontechTable/components/SearchInput.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/components/SearchInput.tsx rename to packages/dms-kit/src/components/ActiontechTable/components/SearchInput.tsx diff --git a/packages/shared/lib/components/ActiontechTable/components/TableWrapper.tsx b/packages/dms-kit/src/components/ActiontechTable/components/TableWrapper.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/components/TableWrapper.tsx rename to packages/dms-kit/src/components/ActiontechTable/components/TableWrapper.tsx diff --git a/packages/shared/lib/components/ActiontechTable/components/Toolbar.tsx b/packages/dms-kit/src/components/ActiontechTable/components/Toolbar.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/components/Toolbar.tsx rename to packages/dms-kit/src/components/ActiontechTable/components/Toolbar.tsx diff --git a/packages/shared/lib/components/ActiontechTable/components/style.ts b/packages/dms-kit/src/components/ActiontechTable/components/style.ts similarity index 98% rename from packages/shared/lib/components/ActiontechTable/components/style.ts rename to packages/dms-kit/src/components/ActiontechTable/components/style.ts index 7b32d06bf..4d8fe61a1 100644 --- a/packages/shared/lib/components/ActiontechTable/components/style.ts +++ b/packages/dms-kit/src/components/ActiontechTable/components/style.ts @@ -1,7 +1,7 @@ import { styled } from '@mui/material/styles'; import { Space } from 'antd'; -import BasicInput from '../../BasicInput/Input'; -import BasicRangePicker from '../../BasicRangePicker/BasicRangePicker'; +import { BasicInput } from '../../BasicInput'; +import { BasicRangePicker } from '../../BasicRangePicker'; export const FilterContainerStyleWrapper = styled(Space)` border-bottom: ${({ theme }) => diff --git a/packages/shared/lib/components/ActiontechTable/context/index.ts b/packages/dms-kit/src/components/ActiontechTable/context/index.ts similarity index 100% rename from packages/shared/lib/components/ActiontechTable/context/index.ts rename to packages/dms-kit/src/components/ActiontechTable/context/index.ts diff --git a/packages/shared/lib/components/ActiontechTable/hooks/useCustomFilter.tsx b/packages/dms-kit/src/components/ActiontechTable/hooks/useCustomFilter.tsx similarity index 98% rename from packages/shared/lib/components/ActiontechTable/hooks/useCustomFilter.tsx rename to packages/dms-kit/src/components/ActiontechTable/hooks/useCustomFilter.tsx index f6623e3c7..6d3d55943 100644 --- a/packages/shared/lib/components/ActiontechTable/hooks/useCustomFilter.tsx +++ b/packages/dms-kit/src/components/ActiontechTable/hooks/useCustomFilter.tsx @@ -7,10 +7,11 @@ import { FilterCustomProps, UpdateTableFilterInfoType } from '../index.type'; -import { CustomSelect, CustomSelectProps } from '../../CustomSelect'; +import { CustomSelect } from '../../CustomSelect'; +import { CustomSelectProps } from '../../CustomSelect'; +import { CustomInput } from '../../CustomInput'; import { CustomFilterRangePickerStyleWrapper } from '../components/style'; import { SearchOutlined } from '@actiontech/icons'; -import { CustomInput } from '../../CustomInput'; const useCustomFilter = () => { const { t } = useTranslation(); diff --git a/packages/shared/lib/components/ActiontechTable/hooks/useTableAction.tsx b/packages/dms-kit/src/components/ActiontechTable/hooks/useTableAction.tsx similarity index 95% rename from packages/shared/lib/components/ActiontechTable/hooks/useTableAction.tsx rename to packages/dms-kit/src/components/ActiontechTable/hooks/useTableAction.tsx index 468f987fc..64450164d 100644 --- a/packages/shared/lib/components/ActiontechTable/hooks/useTableAction.tsx +++ b/packages/dms-kit/src/components/ActiontechTable/hooks/useTableAction.tsx @@ -13,11 +13,11 @@ import { InlineTableActionButtonsStyleWrapper, InlineTableActionMoreButtonPopoverStyleWrapper } from '../components/style'; -import EmptyBox from '../../EmptyBox/EmptyBox'; import { checkButtonPermissions, checkButtonDisabled } from '../utils'; import classNames from 'classnames'; import { DashOutlined } from '@actiontech/icons'; -import { ActionButton, ActionButtonProps } from '../../ActionButton'; +import { ActionButtonProps, ActionButton } from '../../ActionButton'; +import { EmptyBox } from '../../EmptyBox'; import { BasicButton } from '../../BasicButton'; export const ACTIONTECH_TABLE_ACTION_BUTTON_WIDTH = 82; @@ -76,18 +76,6 @@ const useTableAction = () => { /> ); } - const link = - typeof action.link === 'function' ? action.link(record) : action.link; - if (link) { - return ( - - ); - } return ; }; if (actions.length === 1) { diff --git a/packages/shared/lib/components/ActiontechTable/hooks/useTableFilterContainer.tsx b/packages/dms-kit/src/components/ActiontechTable/hooks/useTableFilterContainer.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/hooks/useTableFilterContainer.tsx rename to packages/dms-kit/src/components/ActiontechTable/hooks/useTableFilterContainer.tsx diff --git a/packages/shared/lib/components/ActiontechTable/hooks/useTableRequestError.tsx b/packages/dms-kit/src/components/ActiontechTable/hooks/useTableRequestError.tsx similarity index 96% rename from packages/shared/lib/components/ActiontechTable/hooks/useTableRequestError.tsx rename to packages/dms-kit/src/components/ActiontechTable/hooks/useTableRequestError.tsx index 94c7b62f8..88e179b89 100644 --- a/packages/shared/lib/components/ActiontechTable/hooks/useTableRequestError.tsx +++ b/packages/dms-kit/src/components/ActiontechTable/hooks/useTableRequestError.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { AxiosResponse } from 'axios'; import { useState } from 'react'; -import { getErrorMessage } from '../../../utils/Common'; +import { getErrorMessage } from '../../../utils'; const useTableRequestError = () => { const [requestErrorMessage, setRequestErrorMessage] = useState(''); diff --git a/packages/shared/lib/components/ActiontechTable/hooks/useTableRequestParams.tsx b/packages/dms-kit/src/components/ActiontechTable/hooks/useTableRequestParams.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/hooks/useTableRequestParams.tsx rename to packages/dms-kit/src/components/ActiontechTable/hooks/useTableRequestParams.tsx diff --git a/packages/shared/lib/components/ActiontechTable/hooks/useTableSettings.tsx b/packages/dms-kit/src/components/ActiontechTable/hooks/useTableSettings.tsx similarity index 98% rename from packages/shared/lib/components/ActiontechTable/hooks/useTableSettings.tsx rename to packages/dms-kit/src/components/ActiontechTable/hooks/useTableSettings.tsx index 3f5f6a3e9..82aabcb08 100644 --- a/packages/shared/lib/components/ActiontechTable/hooks/useTableSettings.tsx +++ b/packages/dms-kit/src/components/ActiontechTable/hooks/useTableSettings.tsx @@ -4,11 +4,11 @@ import { CatchTableColumnsType } from '../index.type'; import { useCallback, useEffect, useState } from 'react'; -import { eventEmitter } from '../../../utils/EventEmitter'; -import EmitterKey from '../../../data/EmitterKey'; import { getColumnsLabel } from '../utils'; -import LocalStorageWrapper from '../../../utils/LocalStorageWrapper'; import { isEqual } from 'lodash'; +import EmitterKey from '../../../data/EmitterKey'; +import { LocalStorageWrapper } from '../../../utils'; +import { eventEmitter } from '../../../utils/EventEmitter'; const useTableSettings = < T extends Record, diff --git a/packages/shared/lib/components/ActiontechTable/index.tsx b/packages/dms-kit/src/components/ActiontechTable/index.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/index.tsx rename to packages/dms-kit/src/components/ActiontechTable/index.tsx diff --git a/packages/shared/lib/components/ActiontechTable/index.type.ts b/packages/dms-kit/src/components/ActiontechTable/index.type.ts similarity index 98% rename from packages/shared/lib/components/ActiontechTable/index.type.ts rename to packages/dms-kit/src/components/ActiontechTable/index.type.ts index dfd86adbc..c1f962001 100644 --- a/packages/shared/lib/components/ActiontechTable/index.type.ts +++ b/packages/dms-kit/src/components/ActiontechTable/index.type.ts @@ -2,11 +2,10 @@ import { TableProps, ButtonProps, PopconfirmProps, InputProps } from 'antd'; import { RangePickerProps } from 'antd/es/date-picker'; import { ColumnGroupType, ColumnType } from 'antd/es/table'; import { CSSProperties, Key, ReactNode } from 'react'; -import { CustomSelectProps } from '../CustomSelect'; -import { BasicButtonProps } from '../BasicButton'; -import { TypedLinkProps } from '../TypedRouter'; import { ExcludeSymbol } from '../../types/common.type'; import { CustomInputProps } from '../CustomInput'; +import { BasicButtonProps } from '../BasicButton'; +import { CustomSelectProps } from '../CustomSelect'; //======================================= utils @@ -257,7 +256,6 @@ export type ActiontechTableToolbarActionMeta = { text: ReactNode; buttonProps?: Omit; confirm?: PopconfirmProps | false; - link?: TypedLinkProps | false; permissions?: boolean; }; @@ -309,7 +307,6 @@ export type ActiontechTableActionMeta> = { text: ReactNode; buttonProps?: (record?: T) => Omit; confirm?: ((record?: T) => PopconfirmProps) | false; - link?: ((record?: T) => TypedLinkProps) | false; permissions?: (record?: T) => boolean; }; diff --git a/packages/shared/lib/components/ActiontechTable/style.tsx b/packages/dms-kit/src/components/ActiontechTable/style.tsx similarity index 100% rename from packages/shared/lib/components/ActiontechTable/style.tsx rename to packages/dms-kit/src/components/ActiontechTable/style.tsx diff --git a/packages/shared/lib/components/ActiontechTable/utils/index.ts b/packages/dms-kit/src/components/ActiontechTable/utils/index.ts similarity index 100% rename from packages/shared/lib/components/ActiontechTable/utils/index.ts rename to packages/dms-kit/src/components/ActiontechTable/utils/index.ts diff --git a/packages/shared/lib/components/BasicButton/BasicButton.test.tsx b/packages/dms-kit/src/components/BasicButton/BasicButton.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicButton/BasicButton.test.tsx rename to packages/dms-kit/src/components/BasicButton/BasicButton.test.tsx diff --git a/packages/shared/lib/components/BasicButton/BasicButton.tsx b/packages/dms-kit/src/components/BasicButton/BasicButton.tsx similarity index 100% rename from packages/shared/lib/components/BasicButton/BasicButton.tsx rename to packages/dms-kit/src/components/BasicButton/BasicButton.tsx diff --git a/packages/shared/lib/components/BasicButton/BasicButton.types.ts b/packages/dms-kit/src/components/BasicButton/BasicButton.types.ts similarity index 100% rename from packages/shared/lib/components/BasicButton/BasicButton.types.ts rename to packages/dms-kit/src/components/BasicButton/BasicButton.types.ts diff --git a/packages/dms-kit/src/components/BasicButton/README.md b/packages/dms-kit/src/components/BasicButton/README.md new file mode 100644 index 000000000..77f2fa915 --- /dev/null +++ b/packages/dms-kit/src/components/BasicButton/README.md @@ -0,0 +1,123 @@ +--- +group: + title: 通用 + order: 1 +--- + +# BasicButton 基础按钮 + +基于 Ant Design Button 组件封装的基础按钮组件,提供了统一的样式规范和额外的功能特性。 + +## 何时使用 + +- 需要统一按钮样式规范时 +- 需要无边框图标按钮时 +- 需要保持与设计系统一致的按钮组件时 + +## 代码演示 + +### 基础用法 + + + +### 按钮类型 + + + +### 按钮尺寸 + + + +### 图标按钮 + + + +### 无边框图标按钮 + + + +### 按钮状态 + + + +## API + +### BasicButton + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| noBorderIcon | 是否为无边框图标按钮 | `boolean` | `false` | - | + +### 继承属性 + +BasicButton 组件继承了 Ant Design Button 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| type | 按钮类型 | `'primary' \| 'ghost' \| 'dashed' \| 'link' \| 'text' \| 'default'` | `'default'` | - | +| size | 按钮大小 | `'large' \| 'middle' \| 'small'` | `'middle'` | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| loading | 是否加载中 | `boolean \| { delay: number }` | `false` | - | +| icon | 设置按钮的图标组件 | `ReactNode` | - | - | +| children | 按钮内容 | `ReactNode` | - | - | +| className | 按钮类名 | `string` | - | - | +| style | 按钮样式 | `CSSProperties` | - | - | +| onClick | 点击按钮时的回调 | `(event) => void` | - | - | + +## 设计规范 + +### 尺寸规范 + +- **大尺寸 (lg)**: `padding: 0 16px` +- **默认尺寸**: `padding: 0 12px` +- **小尺寸 (sm)**: `padding: 0 8px` + +### 样式特性 + +- 统一的圆角设计 (`border-radius: 4px`) +- 无边框设计 (`border: 0`) +- 居中对齐的图标和文字 +- 基于主题的色彩系统 +- 支持悬停、激活、禁用等状态样式 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicButton = { + default: { + default: { background, color, boxShadow }, + hover: { background }, + active: { background }, + disabled: { background, color } + }, + primary: { + default: { background, color, boxShadow }, + hover: { background }, + active: { background }, + disabled: { background, color } + }, + dashed: { + default: { border } + }, + dangerous: { + default: { color }, + disabled: { color } + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `noBorderIcon` 属性主要用于创建无边框的图标按钮 +3. 所有 Ant Design Button 的属性和事件都可以正常使用 +4. 组件会自动应用统一的样式类名 `basic-button-wrapper` + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Button 封装 +- 支持所有 Button 组件的属性和事件 +- 新增 `noBorderIcon` 属性支持无边框图标按钮 +- 统一的样式规范和主题系统集成 diff --git a/packages/shared/lib/components/BasicButton/__snapshots__/BasicButton.test.tsx.snap b/packages/dms-kit/src/components/BasicButton/__snapshots__/BasicButton.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicButton/__snapshots__/BasicButton.test.tsx.snap rename to packages/dms-kit/src/components/BasicButton/__snapshots__/BasicButton.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicButton/demo/basic.tsx b/packages/dms-kit/src/components/BasicButton/demo/basic.tsx new file mode 100644 index 000000000..4dba73d50 --- /dev/null +++ b/packages/dms-kit/src/components/BasicButton/demo/basic.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { BasicButton, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicButtonDemo = () => { + return ( + + alert('Clicked!')}> + Primary Button + + Default Button + + ); +}; +export default BasicButtonDemo; diff --git a/packages/dms-kit/src/components/BasicButton/demo/icon.tsx b/packages/dms-kit/src/components/BasicButton/demo/icon.tsx new file mode 100644 index 000000000..c12bba03b --- /dev/null +++ b/packages/dms-kit/src/components/BasicButton/demo/icon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons'; + +const IconButtonDemo = () => { + return ( + +
+ } /> + } /> + } /> + } /> +
+
+ ); +}; + +export default IconButtonDemo; diff --git a/packages/dms-kit/src/components/BasicButton/demo/noBorderIcon.tsx b/packages/dms-kit/src/components/BasicButton/demo/noBorderIcon.tsx new file mode 100644 index 000000000..ba6de2512 --- /dev/null +++ b/packages/dms-kit/src/components/BasicButton/demo/noBorderIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { SettingOutlined } from '@ant-design/icons'; + +const NoBorderIconDemo = () => { + return ( + +
+ } /> + + 使用 noBorderIcon 属性可以移除图标按钮的边框和背景 + +
+
+ ); +}; + +export default NoBorderIconDemo; diff --git a/packages/dms-kit/src/components/BasicButton/demo/sizes.tsx b/packages/dms-kit/src/components/BasicButton/demo/sizes.tsx new file mode 100644 index 000000000..14c9e5dfb --- /dev/null +++ b/packages/dms-kit/src/components/BasicButton/demo/sizes.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { BasicButton, ConfigProvider } from '@actiontech/dms-kit'; + +const ButtonSizesDemo = () => { + return ( + +
+ 大尺寸 + 默认尺寸 + 小尺寸 +
+
+ ); +}; + +export default ButtonSizesDemo; diff --git a/packages/dms-kit/src/components/BasicButton/demo/states.tsx b/packages/dms-kit/src/components/BasicButton/demo/states.tsx new file mode 100644 index 000000000..5ebbd997a --- /dev/null +++ b/packages/dms-kit/src/components/BasicButton/demo/states.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { BasicButton, ConfigProvider } from '@actiontech/dms-kit'; + +const ButtonStatesDemo = () => { + return ( + +
+ 正常状态 + 禁用状态 + 加载状态 + 主要按钮加载 +
+
+ ); +}; + +export default ButtonStatesDemo; diff --git a/packages/dms-kit/src/components/BasicButton/demo/types.tsx b/packages/dms-kit/src/components/BasicButton/demo/types.tsx new file mode 100644 index 000000000..06ce8d54a --- /dev/null +++ b/packages/dms-kit/src/components/BasicButton/demo/types.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { BasicButton, ConfigProvider } from '@actiontech/dms-kit'; + +const ButtonTypesDemo = () => { + return ( + +
+ 默认按钮 + 主要按钮 + 虚线按钮 + 文本按钮 + 链接按钮 + 危险按钮 +
+
+ ); +}; + +export default ButtonTypesDemo; diff --git a/packages/shared/lib/components/BasicButton/index.ts b/packages/dms-kit/src/components/BasicButton/index.ts similarity index 100% rename from packages/shared/lib/components/BasicButton/index.ts rename to packages/dms-kit/src/components/BasicButton/index.ts diff --git a/packages/shared/lib/components/BasicButton/style.ts b/packages/dms-kit/src/components/BasicButton/style.ts similarity index 100% rename from packages/shared/lib/components/BasicButton/style.ts rename to packages/dms-kit/src/components/BasicButton/style.ts diff --git a/packages/shared/lib/components/BasicDatePicker/BasicDatePicker.test.tsx b/packages/dms-kit/src/components/BasicDatePicker/BasicDatePicker.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicDatePicker/BasicDatePicker.test.tsx rename to packages/dms-kit/src/components/BasicDatePicker/BasicDatePicker.test.tsx diff --git a/packages/shared/lib/components/BasicDatePicker/BasicDatePicker.tsx b/packages/dms-kit/src/components/BasicDatePicker/BasicDatePicker.tsx similarity index 100% rename from packages/shared/lib/components/BasicDatePicker/BasicDatePicker.tsx rename to packages/dms-kit/src/components/BasicDatePicker/BasicDatePicker.tsx diff --git a/packages/shared/lib/components/BasicDatePicker/BasicDatePicker.types.ts b/packages/dms-kit/src/components/BasicDatePicker/BasicDatePicker.types.ts similarity index 100% rename from packages/shared/lib/components/BasicDatePicker/BasicDatePicker.types.ts rename to packages/dms-kit/src/components/BasicDatePicker/BasicDatePicker.types.ts diff --git a/packages/dms-kit/src/components/BasicDatePicker/README.md b/packages/dms-kit/src/components/BasicDatePicker/README.md new file mode 100644 index 000000000..a8432f633 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDatePicker/README.md @@ -0,0 +1,140 @@ +--- +group: + title: 通用 + order: 1 +--- + +# BasicDatePicker 基础日期选择器组件 + +## 组件介绍 + +BasicDatePicker 是一个基于 Ant Design DatePicker 组件封装的基础日期选择器,提供了统一的样式风格、时钟图标前缀、自定义导航按钮等功能。它是 dms-kit 中常用的日期输入组件。 + +## 何时使用 + +- 需要选择单个日期时 +- 需要统一的日期选择器样式风格 +- 需要时钟图标前缀的日期输入框 +- 需要自定义导航按钮的日期选择器 + +## 代码演示 + +### 基础用法 + +最简单的日期选择器用法,支持基本的日期选择功能。 + + + +### 不同尺寸 + +支持三种尺寸:small、middle、large。 + + + +### 自定义格式 + +支持自定义日期显示格式和输入格式。 + + + +### 禁用状态 + +当不需要用户输入时,可以禁用日期选择器。 + + + +### 范围限制 + +可以设置日期的选择范围,限制用户只能选择特定时间段的日期。 + + + +### 显示超级图标 + +控制是否显示年份和月份的快速跳转按钮。 + + + +### 自定义样式 + +通过 className 属性添加自定义样式类。 + +## API 文档 + +### BasicDatePickerProps + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| hideSuperIcon | 是否隐藏年份和月份的快速跳转按钮 | boolean | true | - | +| className | 自定义 CSS 类名 | string | - | - | + +### 继承属性 + +BasicDatePicker 继承了 Ant Design DatePicker 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| value | 当前选中的日期 | Dayjs | - | - | +| defaultValue | 默认选中的日期 | Dayjs | - | - | +| onChange | 日期变化回调 | (date: Dayjs \| null, dateString: string) => void | - | - | +| placeholder | 输入框提示文字 | string | - | - | +| format | 日期格式 | string | 'YYYY-MM-DD' | - | +| size | 输入框大小 | 'large' \| 'middle' \| 'small' | 'middle' | - | +| disabled | 是否禁用 | boolean | false | - | +| allowClear | 是否显示清除按钮 | boolean | true | - | +| showTime | 是否显示时间选择 | boolean \| object | false | - | +| disabledDate | 不可选择的日期 | (current: Dayjs) => boolean | - | - | +| onOpenChange | 弹出层展开/收起回调 | (open: boolean) => void | - | - | + +## 设计规范 + +### 样式特点 + +- **时钟图标**: 左侧显示时钟图标,颜色为主题的四级文本色 +- **统一边框**: 使用主题的二级边框色,hover 和 focus 状态有相应的边框变化 +- **自定义导航**: 左右箭头按钮使用自定义图标,支持主题色配置 +- **圆角设计**: 输入框和下拉面板都使用 4px 圆角 + +### 主题配置 + +BasicDatePicker 支持以下主题变量: + +```less +// 日期选择器样式变量 +@color-text-quaternary: #8c8c8c; +@color-border-secondary: #d9d9d9; +@color-bg-layout: #fafafa; +@color-white: #ffffff; +@color-primary: #1890ff; + +// 下拉面板样式 +@basic-range-picker-dropdown-icon-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); +@basic-range-picker-hover-border: 1px solid #40a9ff; +@basic-range-picker-active-border: 1px solid #1890ff; +@basic-range-picker-error-border: 1px solid #ff4d4f; +@basic-range-picker-disabled-border: 1px solid #d9d9d9; +``` + +### 交互状态 + +- **默认状态**: 二级边框色,时钟图标为四级文本色 +- **悬停状态**: 边框色变为主题色,有平滑的过渡动画 +- **聚焦状态**: 边框色为主题色,显示聚焦轮廓 +- **禁用状态**: 边框色为禁用色,背景色为禁用背景色 + +## 注意事项 + +1. **图标依赖**: 组件依赖 `@actiontech/icons` 包中的图标组件 +2. **日期格式**: 默认使用 dayjs 处理日期,确保项目中已安装 dayjs +3. **主题系统**: 组件使用 MUI 的 styled 系统,需要正确的主题上下文 +4. **弹出层定位**: 下拉面板的定位容器为组件本身,避免定位问题 +5. **国际化**: 日期格式和文本支持国际化配置 + +## 更新日志 + +### 1.0.0 +- 初始版本发布 +- 支持基础日期选择功能 +- 集成时钟图标前缀 +- 自定义导航按钮样式 +- 支持超级图标显示控制 diff --git a/packages/shared/lib/components/BasicDatePicker/__snapshots__/BasicDatePicker.test.tsx.snap b/packages/dms-kit/src/components/BasicDatePicker/__snapshots__/BasicDatePicker.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicDatePicker/__snapshots__/BasicDatePicker.test.tsx.snap rename to packages/dms-kit/src/components/BasicDatePicker/__snapshots__/BasicDatePicker.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicDatePicker/demos/basic.tsx b/packages/dms-kit/src/components/BasicDatePicker/demos/basic.tsx new file mode 100644 index 000000000..bd2028518 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDatePicker/demos/basic.tsx @@ -0,0 +1,24 @@ +import React, { useState } from 'react'; +import { BasicDatePicker, ConfigProvider } from '@actiontech/dms-kit'; +import type { Dayjs } from 'dayjs'; + +const BasicDatePickerBasicDemo: React.FC = () => { + const [date, setDate] = useState(null); + + const handleDateChange = (value: Dayjs | null) => { + setDate(value); + console.log('选择的日期:', value?.format('YYYY-MM-DD')); + }; + + return ( + + + + ); +}; + +export default BasicDatePickerBasicDemo; diff --git a/packages/dms-kit/src/components/BasicDatePicker/demos/disabled.tsx b/packages/dms-kit/src/components/BasicDatePicker/demos/disabled.tsx new file mode 100644 index 000000000..0d873b42f --- /dev/null +++ b/packages/dms-kit/src/components/BasicDatePicker/demos/disabled.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { BasicDatePicker, ConfigProvider } from '@actiontech/dms-kit'; +import dayjs from 'dayjs'; + +const BasicDatePickerDisabledDemo: React.FC = () => ( + +
+ + +
+
+); + +export default BasicDatePickerDisabledDemo; diff --git a/packages/dms-kit/src/components/BasicDatePicker/demos/format.tsx b/packages/dms-kit/src/components/BasicDatePicker/demos/format.tsx new file mode 100644 index 000000000..56aa6d33c --- /dev/null +++ b/packages/dms-kit/src/components/BasicDatePicker/demos/format.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { BasicDatePicker, ConfigProvider } from '@actiontech/dms-kit'; +import dayjs from 'dayjs'; + +const BasicDatePickerFormatDemo: React.FC = () => ( + +
+ + + +
+
+); + +export default BasicDatePickerFormatDemo; diff --git a/packages/dms-kit/src/components/BasicDatePicker/demos/range.tsx b/packages/dms-kit/src/components/BasicDatePicker/demos/range.tsx new file mode 100644 index 000000000..87819ed96 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDatePicker/demos/range.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { BasicDatePicker, ConfigProvider } from '@actiontech/dms-kit'; +import dayjs from 'dayjs'; + +const BasicDatePickerRangeDemo: React.FC = () => ( + +
+ { + // 禁用今天之前的日期 + return current && current < dayjs().startOf('day'); + }} + /> + { + const today = dayjs().startOf('day'); + const thirtyDaysAgo = today.subtract(30, 'day'); + return current && (current < thirtyDaysAgo || current > today); + }} + /> + { + // 禁用周末 + return (current && current.day() === 0) || current.day() === 6; + }} + /> +
+
+); + +export default BasicDatePickerRangeDemo; diff --git a/packages/dms-kit/src/components/BasicDatePicker/demos/size.tsx b/packages/dms-kit/src/components/BasicDatePicker/demos/size.tsx new file mode 100644 index 000000000..7803c2b4e --- /dev/null +++ b/packages/dms-kit/src/components/BasicDatePicker/demos/size.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { BasicDatePicker, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicDatePickerSizeDemo: React.FC = () => ( + +
+ + + +
+
+); + +export default BasicDatePickerSizeDemo; diff --git a/packages/dms-kit/src/components/BasicDatePicker/demos/super-icon.tsx b/packages/dms-kit/src/components/BasicDatePicker/demos/super-icon.tsx new file mode 100644 index 000000000..9615ecf20 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDatePicker/demos/super-icon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { BasicDatePicker, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicDatePickerSuperIconDemo: React.FC = () => ( + +
+ + +
+
+); + +export default BasicDatePickerSuperIconDemo; diff --git a/packages/shared/lib/components/BasicDatePicker/index.ts b/packages/dms-kit/src/components/BasicDatePicker/index.ts similarity index 100% rename from packages/shared/lib/components/BasicDatePicker/index.ts rename to packages/dms-kit/src/components/BasicDatePicker/index.ts diff --git a/packages/shared/lib/components/BasicDatePicker/style.ts b/packages/dms-kit/src/components/BasicDatePicker/style.ts similarity index 100% rename from packages/shared/lib/components/BasicDatePicker/style.ts rename to packages/dms-kit/src/components/BasicDatePicker/style.ts diff --git a/packages/shared/lib/components/BasicDrawer/BasicDrawer.test.tsx b/packages/dms-kit/src/components/BasicDrawer/BasicDrawer.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicDrawer/BasicDrawer.test.tsx rename to packages/dms-kit/src/components/BasicDrawer/BasicDrawer.test.tsx diff --git a/packages/shared/lib/components/BasicDrawer/BasicDrawer.tsx b/packages/dms-kit/src/components/BasicDrawer/BasicDrawer.tsx similarity index 100% rename from packages/shared/lib/components/BasicDrawer/BasicDrawer.tsx rename to packages/dms-kit/src/components/BasicDrawer/BasicDrawer.tsx diff --git a/packages/shared/lib/components/BasicDrawer/BasicDrawer.types.ts b/packages/dms-kit/src/components/BasicDrawer/BasicDrawer.types.ts similarity index 100% rename from packages/shared/lib/components/BasicDrawer/BasicDrawer.types.ts rename to packages/dms-kit/src/components/BasicDrawer/BasicDrawer.types.ts diff --git a/packages/dms-kit/src/components/BasicDrawer/README.md b/packages/dms-kit/src/components/BasicDrawer/README.md new file mode 100644 index 000000000..1ef112a33 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDrawer/README.md @@ -0,0 +1,132 @@ +--- +group: + title: 通用 + order: 3 +--- + +# BasicDrawer 基础抽屉 + +基于 Ant Design Drawer 组件封装的基础抽屉组件,提供了统一的样式规范和额外的功能特性,适用于侧边内容展示和操作。 + +## 何时使用 + +- 需要从右侧滑出内容面板时 +- 需要展示详细配置或表单时 +- 需要在不跳转页面的情况下展示更多内容时 +- 需要保持与设计系统一致的抽屉样式时 + +## 代码演示 + +### 基础用法 + + + +### 不同尺寸 + + + +### 自定义关闭图标 + + + +### 无内边距模式 + + + +### 表单抽屉 + + + +### 内容展示抽屉 + + + +## API + +### BasicDrawer + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| showClosedIcon | 是否显示自定义关闭图标 | `boolean` | `true` | - | +| noBodyPadding | 是否移除内容区域的内边距 | `boolean` | `false` | - | +| size | 抽屉尺寸预设 | `'default' \| 'large'` | `'default'` | - | + +### 继承属性 + +BasicDrawer 组件继承了 Ant Design Drawer 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| visible | 抽屉是否可见 | `boolean` | `false` | - | +| title | 标题 | `ReactNode` | - | - | +| children | 抽屉内容 | `ReactNode` | - | - | +| width | 宽度 | `string \| number` | `480` (default) / `720` (large) | - | +| placement | 抽屉的方向 | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | - | +| onClose | 点击遮罩层或右上角叉或取消按钮的回调 | `function(e)` | - | - | +| maskClosable | 点击蒙层是否允许关闭 | `boolean` | `false` | - | +| closable | 是否显示右上角的关闭按钮 | `boolean` | `false` | - | +| closeIcon | 自定义关闭图标 | `ReactNode` | - | - | +| className | 抽屉外层容器的类名 | `string` | - | - | +| style | 抽屉外层容器的样式 | `CSSProperties` | - | - | +| destroyOnClose | 关闭时销毁 Drawer 里的子元素 | `boolean` | `false` | - | + +## 设计规范 + +### 尺寸规范 + +- **默认尺寸 (default)**: `width: 480px` - 适用于简单表单、配置面板等 +- **大尺寸 (large)**: `width: 720px` - 适用于复杂表单、详细内容展示等 +- **自定义宽度**: 可通过 `width` 属性设置任意宽度 + +### 样式特性 + +- 统一的圆角设计 (`border-radius: 8px`) +- 标准化的内边距 (`padding: 24px`) +- 自定义关闭图标,位于右上角 +- 基于主题的色彩系统 +- 响应式设计,支持移动端适配 +- 支持无内边距模式,便于自定义布局 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicDrawer = { + // 主题配置变量 + backgroundColor: string, + border: string, + header: { + backgroundColor: string, + border: string, + title: { + color: string + } + }, + body: { + backgroundColor: string, + color: string + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `size` 属性提供预设尺寸,可通过 `width` 属性进行覆盖 +3. `showClosedIcon` 控制是否显示自定义关闭图标 +4. `noBodyPadding` 可以移除内容区域的内边距,便于自定义布局 +5. 所有 Ant Design Drawer 的属性和事件都可以正常使用 +6. 组件会自动应用统一的样式类名 `basic-drawer-wrapper` +7. 建议根据内容复杂度选择合适的尺寸预设 +8. 抽屉内容应保持简洁,避免信息过载 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Drawer 封装 +- 支持所有 Drawer 组件的属性和事件 +- 新增 `showClosedIcon` 属性支持自定义关闭图标 +- 新增 `noBodyPadding` 属性支持无内边距模式 +- 新增 `size` 属性支持预设尺寸 +- 统一的样式规范和主题系统集成 +- 自定义关闭图标和样式优化 diff --git a/packages/shared/lib/components/BasicDrawer/__snapshots__/BasicDrawer.test.tsx.snap b/packages/dms-kit/src/components/BasicDrawer/__snapshots__/BasicDrawer.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicDrawer/__snapshots__/BasicDrawer.test.tsx.snap rename to packages/dms-kit/src/components/BasicDrawer/__snapshots__/BasicDrawer.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicDrawer/demo/basic.tsx b/packages/dms-kit/src/components/BasicDrawer/demo/basic.tsx new file mode 100644 index 000000000..d936d94e7 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDrawer/demo/basic.tsx @@ -0,0 +1,35 @@ +import React, { useState } from 'react'; +import { BasicDrawer, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicDrawerDemo = () => { + const [visible, setVisible] = useState(false); + + const showDrawer = () => { + setVisible(true); + }; + + const onClose = () => { + setVisible(false); + }; + + return ( + + + 打开抽屉 + + + +

这是一个基础的抽屉示例,展示了 BasicDrawer 的基本用法。

+

抽屉内容可以包含任何 React 组件和 HTML 元素。

+

默认情况下,抽屉会从右侧滑出,宽度为 480px。

+
+
+ ); +}; + +export default BasicDrawerDemo; diff --git a/packages/dms-kit/src/components/BasicDrawer/demo/content.tsx b/packages/dms-kit/src/components/BasicDrawer/demo/content.tsx new file mode 100644 index 000000000..878ad5718 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDrawer/demo/content.tsx @@ -0,0 +1,152 @@ +import React, { useState } from 'react'; +import { BasicDrawer, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Timeline, Tag, Avatar, List } from 'antd'; + +const BasicDrawerContentDemo = () => { + const [timelineVisible, setTimelineVisible] = useState(false); + const [listVisible, setListVisible] = useState(false); + + const timelineData = [ + { + color: 'green', + children: '创建项目 2024-01-15 10:00:00' + }, + { + color: 'blue', + children: '项目初始化 2024-01-15 14:30:00' + }, + { + color: 'blue', + children: '数据库设计 2024-01-16 09:00:00' + }, + { + color: 'orange', + children: '开发阶段 2024-01-17 开始' + }, + { + color: 'red', + children: '测试阶段 2024-01-20 开始' + } + ]; + + const listData = [ + { + title: '张三', + description: '前端开发工程师', + avatar: 'https://joeschmoe.io/api/v1/random', + tags: ['React', 'TypeScript', 'UI/UX'] + }, + { + title: '李四', + description: '后端开发工程师', + avatar: 'https://joeschmoe.io/api/v1/random', + tags: ['Java', 'Spring Boot', 'MySQL'] + }, + { + title: '王五', + description: '测试工程师', + avatar: 'https://joeschmoe.io/api/v1/random', + tags: ['自动化测试', '性能测试', '安全测试'] + }, + { + title: '赵六', + description: '产品经理', + avatar: 'https://joeschmoe.io/api/v1/random', + tags: ['产品设计', '需求分析', '项目管理'] + } + ]; + + return ( + + + setTimelineVisible(true)}> + 时间线抽屉 + + setListVisible(true)}> + 列表抽屉 + + + + setTimelineVisible(false)} + > +
+

项目开发进度

+

以下是项目的关键节点和进度情况:

+ + + +
+

当前状态

+

+ 项目目前处于开发阶段,预计 2024-01-25 完成开发,2024-01-30 上线。 +

+
+
+
+ + setListVisible(false)} + > +
+

项目团队

+

以下是参与项目开发的团队成员:

+ + ( + + } + title={item.title} + description={item.description} + /> +
+ {item.tags.map((tag) => ( + + {tag} + + ))} +
+
+ )} + style={{ marginTop: 24 }} + /> + +
+

团队统计

+

团队总人数:4 人

+

开发人员:2 人

+

测试人员:1 人

+

产品人员:1 人

+
+
+
+
+ ); +}; + +export default BasicDrawerContentDemo; diff --git a/packages/dms-kit/src/components/BasicDrawer/demo/customCloseIcon.tsx b/packages/dms-kit/src/components/BasicDrawer/demo/customCloseIcon.tsx new file mode 100644 index 000000000..5bf547148 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDrawer/demo/customCloseIcon.tsx @@ -0,0 +1,48 @@ +import React, { useState } from 'react'; +import { BasicDrawer, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; + +const BasicDrawerCustomCloseIconDemo = () => { + const [withIconVisible, setWithIconVisible] = useState(false); + const [withoutIconVisible, setWithoutIconVisible] = useState(false); + + return ( + + + setWithIconVisible(true)}> + 显示关闭图标 + + setWithoutIconVisible(true)}> + 隐藏关闭图标 + + + + setWithIconVisible(false)} + > +

这个抽屉显示了自定义的关闭图标。

+

关闭图标位于右上角,点击可以关闭抽屉。

+

默认情况下,showClosedIcon 为 true,会显示关闭图标。

+
+ + setWithoutIconVisible(false)} + > +

这个抽屉隐藏了关闭图标。

+

当 showClosedIcon 设置为 false 时,不会显示关闭图标。

+

用户仍然可以通过点击遮罩层或按 ESC 键来关闭抽屉。

+

适用于需要自定义关闭逻辑的场景。

+
+
+ ); +}; + +export default BasicDrawerCustomCloseIconDemo; diff --git a/packages/dms-kit/src/components/BasicDrawer/demo/form.tsx b/packages/dms-kit/src/components/BasicDrawer/demo/form.tsx new file mode 100644 index 000000000..1b87afce4 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDrawer/demo/form.tsx @@ -0,0 +1,100 @@ +import React, { useState } from 'react'; +import { BasicDrawer, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Form, Input, Select, Switch, Space } from 'antd'; + +const BasicDrawerFormDemo = () => { + const [visible, setVisible] = useState(false); + const [form] = Form.useForm(); + + const showDrawer = () => { + setVisible(true); + }; + + const onClose = () => { + setVisible(false); + form.resetFields(); + }; + + const onFinish = (values: any) => { + console.log('Form values:', values); + setVisible(false); + form.resetFields(); + }; + + return ( + + + 表单抽屉 + + + + 取消 + form.submit()}> + 保存 + + + } + > +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ ); +}; + +export default BasicDrawerFormDemo; diff --git a/packages/dms-kit/src/components/BasicDrawer/demo/noPadding.tsx b/packages/dms-kit/src/components/BasicDrawer/demo/noPadding.tsx new file mode 100644 index 000000000..3bb522dc1 --- /dev/null +++ b/packages/dms-kit/src/components/BasicDrawer/demo/noPadding.tsx @@ -0,0 +1,72 @@ +import React, { useState } from 'react'; +import { BasicDrawer, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Card, Row, Col } from 'antd'; + +const BasicDrawerNoPaddingDemo = () => { + const [normalVisible, setNormalVisible] = useState(false); + const [noPaddingVisible, setNoPaddingVisible] = useState(false); + + return ( + + + setNormalVisible(true)}> + 标准内边距 + + setNoPaddingVisible(true)}> + 无内边距模式 + + + + setNormalVisible(false)} + > +

这是标准内边距的抽屉,内容区域有 24px 的内边距。

+

标准内边距提供了良好的视觉层次和阅读体验。

+

适用于大多数内容展示场景。

+
+ + setNoPaddingVisible(false)} + > +
+

自定义布局

+

这个抽屉使用了 noBodyPadding 模式,移除了默认的内边距。

+

可以完全自定义内容的布局和间距。

+
+ + + + +

这是第一个卡片内容

+
+ + + +

这是第二个卡片内容

+
+ +
+ +
+

这个区域使用了自定义的内边距和背景色。

+

无内边距模式让布局更加灵活。

+
+
+
+ ); +}; + +export default BasicDrawerNoPaddingDemo; diff --git a/packages/dms-kit/src/components/BasicDrawer/demo/sizes.tsx b/packages/dms-kit/src/components/BasicDrawer/demo/sizes.tsx new file mode 100644 index 000000000..4f787fffc --- /dev/null +++ b/packages/dms-kit/src/components/BasicDrawer/demo/sizes.tsx @@ -0,0 +1,48 @@ +import React, { useState } from 'react'; +import { BasicDrawer, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; + +const BasicDrawerSizesDemo = () => { + const [defaultVisible, setDefaultVisible] = useState(false); + const [largeVisible, setLargeVisible] = useState(false); + + return ( + + + setDefaultVisible(true)}> + 默认尺寸抽屉 + + setLargeVisible(true)}> + 大尺寸抽屉 + + + + setDefaultVisible(false)} + > +

这是默认尺寸抽屉 (480px),适用于简单的配置面板和信息展示。

+

内容较少时建议使用默认尺寸抽屉。

+

默认尺寸抽屉提供了合适的空间,不会占用过多的屏幕空间。

+
+ + setLargeVisible(false)} + > +

这是大尺寸抽屉 (720px),适用于复杂的内容展示和表单操作。

+

当需要展示更多内容或复杂表单时,建议使用大尺寸抽屉。

+

大尺寸抽屉提供了更宽敞的空间,可以容纳更多的信息和交互元素。

+

特别适合需要多列布局或复杂表单的场景。

+
+
+ ); +}; + +export default BasicDrawerSizesDemo; diff --git a/packages/shared/lib/components/BasicDrawer/index.ts b/packages/dms-kit/src/components/BasicDrawer/index.ts similarity index 100% rename from packages/shared/lib/components/BasicDrawer/index.ts rename to packages/dms-kit/src/components/BasicDrawer/index.ts diff --git a/packages/shared/lib/components/BasicDrawer/style.ts b/packages/dms-kit/src/components/BasicDrawer/style.ts similarity index 100% rename from packages/shared/lib/components/BasicDrawer/style.ts rename to packages/dms-kit/src/components/BasicDrawer/style.ts diff --git a/packages/shared/lib/components/BasicEmpty/BasicEmpty.test.tsx b/packages/dms-kit/src/components/BasicEmpty/BasicEmpty.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicEmpty/BasicEmpty.test.tsx rename to packages/dms-kit/src/components/BasicEmpty/BasicEmpty.test.tsx diff --git a/packages/shared/lib/components/BasicEmpty/BasicEmpty.tsx b/packages/dms-kit/src/components/BasicEmpty/BasicEmpty.tsx similarity index 100% rename from packages/shared/lib/components/BasicEmpty/BasicEmpty.tsx rename to packages/dms-kit/src/components/BasicEmpty/BasicEmpty.tsx diff --git a/packages/shared/lib/components/BasicEmpty/BasicEmpty.types.ts b/packages/dms-kit/src/components/BasicEmpty/BasicEmpty.types.ts similarity index 100% rename from packages/shared/lib/components/BasicEmpty/BasicEmpty.types.ts rename to packages/dms-kit/src/components/BasicEmpty/BasicEmpty.types.ts diff --git a/packages/dms-kit/src/components/BasicEmpty/README.md b/packages/dms-kit/src/components/BasicEmpty/README.md new file mode 100644 index 000000000..ff8cc8008 --- /dev/null +++ b/packages/dms-kit/src/components/BasicEmpty/README.md @@ -0,0 +1,122 @@ +--- +group: + title: 通用 + order: 1 +--- + +# BasicEmpty 基础空状态组件 + +基于 Ant Design Empty 组件封装的基础空状态组件,提供了统一的样式规范和额外的功能特性,支持加载状态、错误状态和自定义内容。 + +## 何时使用 + +- 需要展示空数据状态时 +- 需要展示加载状态时 +- 需要展示错误状态时 +- 需要保持与设计系统一致的空状态组件时 + +## 代码演示 + +### 基础用法 + + + +### 加载状态 + + + +### 错误状态 + + + + +### 带刷新按钮 + + + + + +## API + +### BasicEmpty + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| loading | 是否显示加载状态 | `boolean` | `false` | - | +| dataLength | 数据长度,为 0 时显示空状态 | `number` | - | - | +| errorInfo | 错误信息,可以是字符串或 ReactNode | `string \| ReactNode` | - | - | +| errorTitle | 错误标题 | `string \| ReactNode` | - | - | +| emptyCont | 自定义空状态内容 | `string \| ReactNode` | `'暂无数据'` | - | +| onRefresh | 刷新回调函数 | `() => void` | - | - | +| children | 子元素,当有数据时显示 | `ReactNode` | - | - | + +### 继承属性 + +BasicEmpty 组件继承了 Ant Design Empty 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| image | 自定义图片 | `ReactNode` | - | - | +| description | 自定义描述内容 | `ReactNode` | - | - | +| className | 容器类名 | `string` | - | - | +| style | 容器样式 | `CSSProperties` | - | - | + +## 设计规范 + +### 状态类型 + +- **加载状态 (loading)**: 显示旋转的加载图标 +- **错误状态 (errorInfo)**: 显示错误图标和错误信息 +- **空状态 (dataLength === 0)**: 显示空状态图标和提示文字 +- **有数据状态**: 显示 children 内容 + +### 样式特性 + +- 统一的图标尺寸 (`80x80px`) +- 基于主题的色彩系统 +- 支持自定义图标和内容 +- 响应式的布局设计 +- 集成的刷新按钮样式 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicEmpty = { + default: { + color, + fontSize + }, + loading: { + color + }, + error: { + color, + iconColor + }, + empty: { + color, + iconColor + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. 组件会自动应用统一的样式类名 `basic-empty-wrapper` +3. 当 `loading` 为 true 时,会覆盖其他状态的显示 +4. 当 `errorInfo` 存在时,会显示错误状态 +5. 当 `dataLength` 为 0 时,会显示空状态 +6. 当有 `children` 且数据存在时,会显示 children 内容 +7. 组件集成了国际化支持,默认文字会根据当前语言显示 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Empty 封装 +- 支持加载状态、错误状态、空状态等多种状态 +- 新增 `dataLength` 属性自动判断显示状态 +- 新增 `onRefresh` 属性支持刷新功能 +- 集成 BasicButton 组件支持操作按钮 +- 统一的样式规范和主题系统集成 diff --git a/packages/shared/lib/components/BasicEmpty/__snapshots__/BasicEmpty.test.tsx.snap b/packages/dms-kit/src/components/BasicEmpty/__snapshots__/BasicEmpty.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicEmpty/__snapshots__/BasicEmpty.test.tsx.snap rename to packages/dms-kit/src/components/BasicEmpty/__snapshots__/BasicEmpty.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicEmpty/demo/basic.tsx b/packages/dms-kit/src/components/BasicEmpty/demo/basic.tsx new file mode 100644 index 000000000..deb761d50 --- /dev/null +++ b/packages/dms-kit/src/components/BasicEmpty/demo/basic.tsx @@ -0,0 +1,56 @@ +import React, { useState } from 'react'; +import { BasicEmpty, ConfigProvider } from '@actiontech/dms-kit'; +import { Button, Space, Card } from 'antd'; + +const BasicEmptyDemo = () => { + const [dataLength, setDataLength] = useState(0); + + const addData = () => { + setDataLength(dataLength + 1); + }; + + const removeData = () => { + setDataLength(Math.max(0, dataLength - 1)); + }; + + return ( + + + +
+ + + + + + 当前数据量: {dataLength} + +
+ +
+ +
+

有数据时的内容

+

这里可以显示实际的数据内容

+
+
+
+
+
+
+ ); +}; + +export default BasicEmptyDemo; + diff --git a/packages/dms-kit/src/components/BasicEmpty/demo/error.tsx b/packages/dms-kit/src/components/BasicEmpty/demo/error.tsx new file mode 100644 index 000000000..f198fb187 --- /dev/null +++ b/packages/dms-kit/src/components/BasicEmpty/demo/error.tsx @@ -0,0 +1,110 @@ +import React, { useState } from 'react'; +import { BasicEmpty, ConfigProvider } from '@actiontech/dms-kit'; +import { Button, Space, Card, Select, Input } from 'antd'; + +const ErrorEmptyDemo = () => { + const [errorInfo, setErrorInfo] = useState(''); + const [errorTitle, setErrorTitle] = useState(''); + const [customError, setCustomError] = useState(''); + + const errorTypes = [ + { + label: '网络错误', + value: 'network', + title: '网络连接失败', + info: '请检查网络连接后重试' + }, + { + label: '权限错误', + value: 'permission', + title: '权限不足', + info: '您没有访问此资源的权限' + }, + { + label: '服务器错误', + value: 'server', + title: '服务器异常', + info: '服务器内部错误,请稍后重试' + }, + { + label: '自定义错误', + value: 'custom', + title: errorTitle, + info: customError + } + ]; + + const setError = (type: string) => { + const error = errorTypes.find((e) => e.value === type); + if (error) { + setErrorInfo(error.info); + setErrorTitle(error.title); + } + }; + + const clearError = () => { + setErrorInfo(''); + setErrorTitle(''); + }; + + return ( + + + +
+ + setErrorTitle(e.target.value)} + style={{ width: 200 }} + /> + setCustomError(e.target.value)} + style={{ width: 200 }} + /> + + +
+ +
+ +
+
+
+
+ ); +}; + +export default ErrorEmptyDemo; + diff --git a/packages/dms-kit/src/components/BasicEmpty/demo/loading.tsx b/packages/dms-kit/src/components/BasicEmpty/demo/loading.tsx new file mode 100644 index 000000000..175ced191 --- /dev/null +++ b/packages/dms-kit/src/components/BasicEmpty/demo/loading.tsx @@ -0,0 +1,69 @@ +import React, { useState } from 'react'; +import { BasicEmpty, ConfigProvider } from '@actiontech/dms-kit'; +import { Button, Space, Card, Switch } from 'antd'; + +const LoadingEmptyDemo = () => { + const [loading, setLoading] = useState(false); + const [dataLength, setDataLength] = useState(0); + + const simulateLoading = () => { + setLoading(true); + setDataLength(0); + + // 模拟异步加载 + setTimeout(() => { + setLoading(false); + setDataLength(5); + }, 3000); + }; + + const clearData = () => { + setDataLength(0); + }; + + return ( + + + +
+ + + + + + 加载状态: + {loading ? ' 加载中...' : ' 已完成'} + +
+ +
+ +
+

数据加载完成

+

共加载了 {dataLength} 条数据

+
+
+
+
+
+
+ ); +}; + +export default LoadingEmptyDemo; + diff --git a/packages/dms-kit/src/components/BasicEmpty/demo/withRefresh.tsx b/packages/dms-kit/src/components/BasicEmpty/demo/withRefresh.tsx new file mode 100644 index 000000000..1a77cc4a6 --- /dev/null +++ b/packages/dms-kit/src/components/BasicEmpty/demo/withRefresh.tsx @@ -0,0 +1,77 @@ +import React, { useState } from 'react'; +import { BasicEmpty, ConfigProvider } from '@actiontech/dms-kit'; +import { Button, Space, Card, Switch, message } from 'antd'; + +const WithRefreshEmptyDemo = () => { + const [loading, setLoading] = useState(false); + const [dataLength, setDataLength] = useState(0); + const [showRefresh, setShowRefresh] = useState(true); + + const handleRefresh = () => { + setLoading(true); + message.info('正在刷新数据...'); + + // 模拟刷新数据 + setTimeout(() => { + const newDataLength = Math.floor(Math.random() * 10) + 1; + setDataLength(newDataLength); + setLoading(false); + message.success(`刷新成功,获取到 ${newDataLength} 条数据`); + }, 2000); + }; + + const clearData = () => { + setDataLength(0); + message.info('数据已清空'); + }; + + return ( + + + +
+ + + + + + 显示刷新按钮: + +
+ +
+ +
+

数据列表

+

当前共有 {dataLength} 条数据

+ + + + +
+
+
+ +
+ 提示:当 dataLength 为 0 且 onRefresh 存在时,会自动显示刷新按钮 +
+
+
+
+ ); +}; + +export default WithRefreshEmptyDemo; + diff --git a/packages/shared/lib/components/BasicEmpty/index.ts b/packages/dms-kit/src/components/BasicEmpty/index.ts similarity index 100% rename from packages/shared/lib/components/BasicEmpty/index.ts rename to packages/dms-kit/src/components/BasicEmpty/index.ts diff --git a/packages/shared/lib/components/BasicEmpty/style.ts b/packages/dms-kit/src/components/BasicEmpty/style.ts similarity index 100% rename from packages/shared/lib/components/BasicEmpty/style.ts rename to packages/dms-kit/src/components/BasicEmpty/style.ts diff --git a/packages/shared/lib/components/BasicInfoList/BasicInfoList.test.tsx b/packages/dms-kit/src/components/BasicInfoList/BasicInfoList.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicInfoList/BasicInfoList.test.tsx rename to packages/dms-kit/src/components/BasicInfoList/BasicInfoList.test.tsx diff --git a/packages/shared/lib/components/BasicInfoList/BasicInfoList.tsx b/packages/dms-kit/src/components/BasicInfoList/BasicInfoList.tsx similarity index 100% rename from packages/shared/lib/components/BasicInfoList/BasicInfoList.tsx rename to packages/dms-kit/src/components/BasicInfoList/BasicInfoList.tsx diff --git a/packages/shared/lib/components/BasicInfoList/BasicInfoList.types.ts b/packages/dms-kit/src/components/BasicInfoList/BasicInfoList.types.ts similarity index 100% rename from packages/shared/lib/components/BasicInfoList/BasicInfoList.types.ts rename to packages/dms-kit/src/components/BasicInfoList/BasicInfoList.types.ts diff --git a/packages/dms-kit/src/components/BasicInfoList/README.md b/packages/dms-kit/src/components/BasicInfoList/README.md new file mode 100644 index 000000000..54ae19458 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInfoList/README.md @@ -0,0 +1,123 @@ +--- +group: + title: 通用 + order: 1 +--- + +# BasicInfoList 信息列表 + +基于 Ant Design Card 组件封装的信息列表组件,提供了统一的信息展示布局和错误状态处理。 + +## 何时使用 + +- 需要展示结构化信息列表时 +- 需要响应式网格布局时 +- 需要统一的错误状态和空状态处理时 +- 需要可配置列数的信息展示时 + +## 代码演示 + +### 基础用法 + + + +### 自定义列数 + + + +### 错误状态处理 + + + +### 加载状态 + + + +### 空数据状态 + + + +### 复杂内容展示 + + + +## API + +### BasicInfoList + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| data | 信息数据数组 | `BasicInfoDataType[]` | - | - | +| columnNumber | 列数配置 | `number` | `3` | - | +| errorInfo | 错误信息 | `string \| ReactNode` | - | - | +| errorTitle | 错误标题 | `string \| ReactNode` | - | - | +| loading | 加载状态 | `boolean` | `false` | - | + +### BasicInfoDataType + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| key | 信息标签 | `ReactNode` | - | - | +| value | 信息值 | `ReactNode` | - | - | + +### 继承属性 + +BasicInfoList 组件继承了 Ant Design Card 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| title | 卡片标题 | `ReactNode` | - | - | +| className | 卡片类名 | `string` | - | - | +| style | 卡片样式 | `CSSProperties` | - | - | +| size | 卡片尺寸 | `'default' \| 'small'` | `'default'` | - | + +## 设计规范 + +### 布局规范 + +- **默认列数**: 3列网格布局 +- **响应式设计**: 自动计算最后一行的列宽 +- **间距统一**: 使用 Card.Grid 的内置间距 +- **悬停效果**: 禁用默认悬停效果,保持简洁 + +### 样式特性 + +- 统一的卡片网格布局 +- 自动列宽计算,最后一行动态调整 +- 支持加载、错误、空数据等状态 +- 基于主题的色彩系统 +- 响应式设计,支持不同列数配置 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicInfoList = { + infoItem: { + title: { color, fontSize, fontWeight }, + value: { color, fontSize }, + background: { default, hover } + }, + grid: { + border: { color, style, width }, + background: { default, hover } + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `columnNumber` 建议设置为 2-4 之间的值,以获得最佳显示效果 +3. 当数据为空或出现错误时,会自动显示 `BasicEmpty` 组件 +4. 最后一行的列宽会自动调整,确保布局美观 +5. 所有 Ant Design Card 的属性和事件都可以正常使用 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Card 封装 +- 支持响应式网格布局 +- 集成 BasicEmpty 组件处理各种状态 +- 支持自定义列数配置 +- 统一的样式规范和主题系统集成 diff --git a/packages/shared/lib/components/BasicInfoList/__snapshots__/BasicInfoList.test.tsx.snap b/packages/dms-kit/src/components/BasicInfoList/__snapshots__/BasicInfoList.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicInfoList/__snapshots__/BasicInfoList.test.tsx.snap rename to packages/dms-kit/src/components/BasicInfoList/__snapshots__/BasicInfoList.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicInfoList/demo/basic.tsx b/packages/dms-kit/src/components/BasicInfoList/demo/basic.tsx new file mode 100644 index 000000000..7e7f82438 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInfoList/demo/basic.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { BasicInfoList } from '@actiontech/dms-kit'; + +const BasicInfoListBasicDemo: React.FC = () => { + const data = [ + { key: '项目名称', value: 'DMS 数据管理系统' }, + { key: '项目版本', value: 'v2.1.0' }, + { key: '创建时间', value: '2024-01-15' }, + { key: '项目状态', value: '进行中' }, + { key: '负责人', value: '张三' }, + { key: '团队规模', value: '15人' } + ]; + + return ( + + + + ); +}; + +export default BasicInfoListBasicDemo; diff --git a/packages/dms-kit/src/components/BasicInfoList/demo/columns.tsx b/packages/dms-kit/src/components/BasicInfoList/demo/columns.tsx new file mode 100644 index 000000000..bfb39c711 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInfoList/demo/columns.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; +import { BasicInfoList } from '@actiontech/dms-kit'; + +const BasicInfoListColumnsDemo: React.FC = () => { + const data = [ + { key: '服务器名称', value: 'web-server-01' }, + { key: 'IP地址', value: '192.168.1.100' }, + { key: '操作系统', value: 'Ubuntu 20.04' }, + { key: 'CPU核心数', value: '8核' }, + { key: '内存大小', value: '16GB' }, + { key: '磁盘空间', value: '500GB' }, + { key: '运行状态', value: '正常' }, + { key: '最后更新', value: '2024-01-15 10:30:00' } + ]; + + return ( + + + + + + + + ); +}; + +export default BasicInfoListColumnsDemo; diff --git a/packages/dms-kit/src/components/BasicInfoList/demo/complex.tsx b/packages/dms-kit/src/components/BasicInfoList/demo/complex.tsx new file mode 100644 index 000000000..97b368f15 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInfoList/demo/complex.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Tag, Progress, Button, Space } from 'antd'; +import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons'; +import { BasicInfoList } from '@actiontech/dms-kit'; + +const BasicInfoListComplexDemo: React.FC = () => { + const data = [ + { + key: '任务状态', + value: ( + }> + 已完成 + + ) + }, + { + key: '完成进度', + value: + }, + { + key: '优先级', + value: + }, + { + key: '负责人', + value: ( +
+ 李四 + +
+ ) + }, + { + key: '最后更新', + value: ( +
+
2024-01-15 14:30:00
+ 2小时前 +
+ ) + }, + { + key: '操作', + value: ( + + + + + ) + } + ]; + + return ( + + + + ); +}; + +export default BasicInfoListComplexDemo; diff --git a/packages/dms-kit/src/components/BasicInfoList/demo/empty.tsx b/packages/dms-kit/src/components/BasicInfoList/demo/empty.tsx new file mode 100644 index 000000000..0084706f8 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInfoList/demo/empty.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; +import { BasicInfoList } from '@actiontech/dms-kit'; + +const BasicInfoListEmptyDemo: React.FC = () => { + const emptyData: any[] = []; + + return ( + + + + + + + + ); +}; + +export default BasicInfoListEmptyDemo; diff --git a/packages/dms-kit/src/components/BasicInfoList/demo/error.tsx b/packages/dms-kit/src/components/BasicInfoList/demo/error.tsx new file mode 100644 index 000000000..c29db037f --- /dev/null +++ b/packages/dms-kit/src/components/BasicInfoList/demo/error.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; +import { BasicInfoList } from '@actiontech/dms-kit'; + +const BasicInfoListErrorDemo: React.FC = () => { + const data = [ + { key: '数据库名称', value: 'production_db' }, + { key: '连接状态', value: '已连接' }, + { key: '版本信息', value: 'MySQL 8.0' } + ]; + + return ( + + + + + + + + + + ); +}; + +export default BasicInfoListErrorDemo; diff --git a/packages/dms-kit/src/components/BasicInfoList/demo/loading.tsx b/packages/dms-kit/src/components/BasicInfoList/demo/loading.tsx new file mode 100644 index 000000000..26d0b344e --- /dev/null +++ b/packages/dms-kit/src/components/BasicInfoList/demo/loading.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Button } from 'antd'; +import { useState } from 'react'; +import { BasicInfoList } from '@actiontech/dms-kit'; + +const BasicInfoListLoadingDemo: React.FC = () => { + const [loading, setLoading] = useState(false); + const [data, setData] = useState([]); + + const mockLoadData = () => { + setLoading(true); + setData([]); + + // 模拟异步加载 + setTimeout(() => { + const mockData = [ + { key: '用户ID', value: 'U001' }, + { key: '用户名', value: 'john_doe' }, + { key: '邮箱', value: 'john@example.com' }, + { key: '注册时间', value: '2024-01-01' }, + { key: '最后登录', value: '2024-01-15' }, + { key: '账户状态', value: '活跃' } + ]; + setData(mockData); + setLoading(false); + }, 2000); + }; + + const clearData = () => { + setData([]); + }; + + return ( + + + + + + + + + + + ); +}; + +export default BasicInfoListLoadingDemo; diff --git a/packages/shared/lib/components/BasicInfoList/index.ts b/packages/dms-kit/src/components/BasicInfoList/index.ts similarity index 100% rename from packages/shared/lib/components/BasicInfoList/index.ts rename to packages/dms-kit/src/components/BasicInfoList/index.ts diff --git a/packages/shared/lib/components/BasicInfoList/style.ts b/packages/dms-kit/src/components/BasicInfoList/style.ts similarity index 100% rename from packages/shared/lib/components/BasicInfoList/style.ts rename to packages/dms-kit/src/components/BasicInfoList/style.ts diff --git a/packages/shared/lib/components/BasicInput/Input.tsx b/packages/dms-kit/src/components/BasicInput/Input.tsx similarity index 100% rename from packages/shared/lib/components/BasicInput/Input.tsx rename to packages/dms-kit/src/components/BasicInput/Input.tsx diff --git a/packages/shared/lib/components/BasicInput/Password.tsx b/packages/dms-kit/src/components/BasicInput/Password.tsx similarity index 100% rename from packages/shared/lib/components/BasicInput/Password.tsx rename to packages/dms-kit/src/components/BasicInput/Password.tsx diff --git a/packages/dms-kit/src/components/BasicInput/README.md b/packages/dms-kit/src/components/BasicInput/README.md new file mode 100644 index 000000000..dfa9a93e0 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInput/README.md @@ -0,0 +1,154 @@ +--- +group: + title: 通用 + order: 2 +--- + +# BasicInput 基础输入框 + +基于 Ant Design Input 组件封装的基础输入框组件,提供了统一的样式规范、国际化支持和增强的功能特性。 + +## 何时使用 + +- 需要统一输入框样式规范时 +- 需要支持国际化占位符文本时 +- 需要自定义清除图标样式时 +- 需要保持与设计系统一致的输入框组件时 + +## 代码演示 + +### 基础用法 + + + +### 输入框类型 + + + +### 输入框尺寸 + + + +### 带前缀和后缀 + + + +### 文本域 + + + +### 密码输入框 + + + +### 带清除功能 + + + +### 禁用状态 + + + +## API + +### BasicInput + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| className | 输入框类名 | `string` | - | - | +| allowClear | 是否显示清除按钮 | `boolean \| { clearIcon: ReactNode }` | `false` | - | + +### BasicInput.TextArea + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| className | 文本域类名 | `string` | - | - | +| rows | 文本域行数 | `number` | `4` | - | +| autoSize | 自适应内容高度 | `boolean \| { minRows: number, maxRows: number }` | `false` | - | + +### BasicInput.Password + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| className | 密码输入框类名 | `string` | - | - | +| visibilityToggle | 是否显示切换密码可见性的按钮 | `boolean` | `true` | - | + +### 继承属性 + +BasicInput 组件继承了 Ant Design Input 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| type | 输入框类型 | `'text' \| 'password' \| 'number' \| 'email' \| 'url' \| 'tel'` | `'text'` | - | +| size | 输入框大小 | `'large' \| 'middle' \| 'small'` | `'middle'` | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| placeholder | 输入框占位符 | `string` | `'请输入'` | - | +| value | 输入框的值 | `string` | - | - | +| defaultValue | 输入框的默认值 | `string` | - | - | +| prefix | 输入框前缀图标 | `ReactNode` | - | - | +| suffix | 输入框后缀图标 | `ReactNode` | - | - | +| addonBefore | 输入框前置标签 | `ReactNode` | - | - | +| addonAfter | 输入框后置标签 | `ReactNode` | - | - | +| onChange | 输入框内容变化时的回调 | `(e: ChangeEvent) => void` | - | - | +| onPressEnter | 按下回车键时的回调 | `(e: KeyboardEvent) => void` | - | - | + +## 设计规范 + +### 尺寸规范 + +- **大尺寸 (lg)**: `height: 40px, padding: 0 12px` +- **默认尺寸**: `height: 32px, padding: 0 11px` +- **小尺寸 (sm)**: `height: 24px, padding: 0 7px` + +### 样式特性 + +- 统一的圆角设计 (`border-radius: 6px`) +- 基于主题的边框和背景色 +- 支持悬停、聚焦、禁用等状态样式 +- 自定义清除图标样式 +- 国际化占位符文本支持 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicInput = { + default: { + default: { border, background, color }, + hover: { border }, + focus: { border, boxShadow }, + disabled: { border, background, color } + }, + textArea: { + default: { border, background, color }, + hover: { border }, + focus: { border, boxShadow }, + disabled: { border, background, color } + }, + password: { + default: { border, background, color }, + hover: { border }, + focus: { border, boxShadow }, + disabled: { border, background, color } + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. 组件会自动应用统一的样式类名 `basic-input-wrapper` +3. 占位符文本会自动使用国际化配置 +4. 清除图标使用自定义的 `CloseOutlined` 图标 +5. 所有 Ant Design Input 的属性和事件都可以正常使用 +6. 组件支持 `ref` 转发,可以获取原生 DOM 元素引用 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Input 封装 +- 支持所有 Input 组件的属性和事件 +- 新增国际化占位符文本支持 +- 自定义清除图标样式 +- 统一的样式规范和主题系统集成 +- 支持 TextArea 和 Password 子组件 diff --git a/packages/shared/lib/components/BasicInput/TextArea.tsx b/packages/dms-kit/src/components/BasicInput/TextArea.tsx similarity index 100% rename from packages/shared/lib/components/BasicInput/TextArea.tsx rename to packages/dms-kit/src/components/BasicInput/TextArea.tsx diff --git a/packages/shared/lib/components/BasicInput/__tests__/Input.test.tsx b/packages/dms-kit/src/components/BasicInput/__tests__/Input.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicInput/__tests__/Input.test.tsx rename to packages/dms-kit/src/components/BasicInput/__tests__/Input.test.tsx diff --git a/packages/shared/lib/components/BasicInput/__tests__/Password.test.tsx b/packages/dms-kit/src/components/BasicInput/__tests__/Password.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicInput/__tests__/Password.test.tsx rename to packages/dms-kit/src/components/BasicInput/__tests__/Password.test.tsx diff --git a/packages/shared/lib/components/BasicInput/__tests__/TextArea.test.tsx b/packages/dms-kit/src/components/BasicInput/__tests__/TextArea.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicInput/__tests__/TextArea.test.tsx rename to packages/dms-kit/src/components/BasicInput/__tests__/TextArea.test.tsx diff --git a/packages/shared/lib/components/BasicInput/__tests__/__snapshots__/Input.test.tsx.snap b/packages/dms-kit/src/components/BasicInput/__tests__/__snapshots__/Input.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicInput/__tests__/__snapshots__/Input.test.tsx.snap rename to packages/dms-kit/src/components/BasicInput/__tests__/__snapshots__/Input.test.tsx.snap diff --git a/packages/shared/lib/components/BasicInput/__tests__/__snapshots__/Password.test.tsx.snap b/packages/dms-kit/src/components/BasicInput/__tests__/__snapshots__/Password.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicInput/__tests__/__snapshots__/Password.test.tsx.snap rename to packages/dms-kit/src/components/BasicInput/__tests__/__snapshots__/Password.test.tsx.snap diff --git a/packages/shared/lib/components/BasicInput/__tests__/__snapshots__/TextArea.test.tsx.snap b/packages/dms-kit/src/components/BasicInput/__tests__/__snapshots__/TextArea.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicInput/__tests__/__snapshots__/TextArea.test.tsx.snap rename to packages/dms-kit/src/components/BasicInput/__tests__/__snapshots__/TextArea.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicInput/demo/affix.tsx b/packages/dms-kit/src/components/BasicInput/demo/affix.tsx new file mode 100644 index 000000000..69be44938 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInput/demo/affix.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { BasicInput, ConfigProvider } from '@actiontech/dms-kit'; +import { LockOutlined, SearchOutlined } from '@actiontech/icons'; + +const AffixDemo = () => { + return ( + +
+ + } placeholder="请输入密码" /> + } + suffix="搜索" + placeholder="请输入搜索关键词" + /> +
+
+ ); +}; + +export default AffixDemo; diff --git a/packages/dms-kit/src/components/BasicInput/demo/allowClear.tsx b/packages/dms-kit/src/components/BasicInput/demo/allowClear.tsx new file mode 100644 index 000000000..66214eaff --- /dev/null +++ b/packages/dms-kit/src/components/BasicInput/demo/allowClear.tsx @@ -0,0 +1,29 @@ +import React, { useState } from 'react'; +import { BasicInput, ConfigProvider } from '@actiontech/dms-kit'; + +const AllowClearDemo = () => { + const [value1, setValue1] = useState(''); + const [value2, setValue2] = useState(''); + + return ( + +
+ setValue1(e.target.value)} + /> + setValue2(e.target.value)} + /> + +
+
+ ); +}; + +export default AllowClearDemo; diff --git a/packages/dms-kit/src/components/BasicInput/demo/basic.tsx b/packages/dms-kit/src/components/BasicInput/demo/basic.tsx new file mode 100644 index 000000000..70b5dcf5e --- /dev/null +++ b/packages/dms-kit/src/components/BasicInput/demo/basic.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { BasicInput, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicInputDemo = () => { + return ( + +
+ + + +
+
+ ); +}; + +export default BasicInputDemo; diff --git a/packages/dms-kit/src/components/BasicInput/demo/disabled.tsx b/packages/dms-kit/src/components/BasicInput/demo/disabled.tsx new file mode 100644 index 000000000..2851fbf13 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInput/demo/disabled.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { BasicInput, ConfigProvider } from '@actiontech/dms-kit'; + +const DisabledDemo = () => { + return ( + +
+ + + + +
+
+ ); +}; + +export default DisabledDemo; diff --git a/packages/dms-kit/src/components/BasicInput/demo/password.tsx b/packages/dms-kit/src/components/BasicInput/demo/password.tsx new file mode 100644 index 000000000..2273f191d --- /dev/null +++ b/packages/dms-kit/src/components/BasicInput/demo/password.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { BasicInput, ConfigProvider } from '@actiontech/dms-kit'; + +const PasswordDemo = () => { + return ( + +
+ + + +
+
+ ); +}; + +export default PasswordDemo; diff --git a/packages/dms-kit/src/components/BasicInput/demo/sizes.tsx b/packages/dms-kit/src/components/BasicInput/demo/sizes.tsx new file mode 100644 index 000000000..f0dc60325 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInput/demo/sizes.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { BasicInput, ConfigProvider } from '@actiontech/dms-kit'; + +const SizesDemo = () => { + return ( + +
+ + + +
+
+ ); +}; + +export default SizesDemo; diff --git a/packages/dms-kit/src/components/BasicInput/demo/textarea.tsx b/packages/dms-kit/src/components/BasicInput/demo/textarea.tsx new file mode 100644 index 000000000..455889a5f --- /dev/null +++ b/packages/dms-kit/src/components/BasicInput/demo/textarea.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { BasicInput, ConfigProvider } from '@actiontech/dms-kit'; + +const TextAreaDemo = () => { + return ( + +
+ + + +
+
+ ); +}; + +export default TextAreaDemo; diff --git a/packages/dms-kit/src/components/BasicInput/demo/types.tsx b/packages/dms-kit/src/components/BasicInput/demo/types.tsx new file mode 100644 index 000000000..cd197faa0 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInput/demo/types.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { BasicInput, ConfigProvider } from '@actiontech/dms-kit'; + +const TypesDemo = () => { + return ( + +
+ + + + + + +
+
+ ); +}; + +export default TypesDemo; diff --git a/packages/shared/lib/components/BasicInput/index.tsx b/packages/dms-kit/src/components/BasicInput/index.tsx similarity index 100% rename from packages/shared/lib/components/BasicInput/index.tsx rename to packages/dms-kit/src/components/BasicInput/index.tsx diff --git a/packages/shared/lib/components/BasicInput/style.ts b/packages/dms-kit/src/components/BasicInput/style.ts similarity index 100% rename from packages/shared/lib/components/BasicInput/style.ts rename to packages/dms-kit/src/components/BasicInput/style.ts diff --git a/packages/shared/lib/components/BasicInputNumber/BasicInputNumber.test.tsx b/packages/dms-kit/src/components/BasicInputNumber/BasicInputNumber.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicInputNumber/BasicInputNumber.test.tsx rename to packages/dms-kit/src/components/BasicInputNumber/BasicInputNumber.test.tsx diff --git a/packages/shared/lib/components/BasicInputNumber/BasicInputNumber.tsx b/packages/dms-kit/src/components/BasicInputNumber/BasicInputNumber.tsx similarity index 100% rename from packages/shared/lib/components/BasicInputNumber/BasicInputNumber.tsx rename to packages/dms-kit/src/components/BasicInputNumber/BasicInputNumber.tsx diff --git a/packages/shared/lib/components/BasicInputNumber/BasicInputNumber.types.ts b/packages/dms-kit/src/components/BasicInputNumber/BasicInputNumber.types.ts similarity index 100% rename from packages/shared/lib/components/BasicInputNumber/BasicInputNumber.types.ts rename to packages/dms-kit/src/components/BasicInputNumber/BasicInputNumber.types.ts diff --git a/packages/dms-kit/src/components/BasicInputNumber/README.md b/packages/dms-kit/src/components/BasicInputNumber/README.md new file mode 100644 index 000000000..2f84a4cfd --- /dev/null +++ b/packages/dms-kit/src/components/BasicInputNumber/README.md @@ -0,0 +1,133 @@ +--- +group: + title: 通用 + order: 3 +--- + +# BasicInputNumber 基础数字输入框 + +基于 Ant Design InputNumber 组件封装的基础数字输入框组件,提供了统一的样式规范和增强的功能特性。 + +## 何时使用 + +- 需要统一数字输入框样式规范时 +- 需要输入数字、金额、百分比等数值时 +- 需要限制数字范围或精度时 +- 需要保持与设计系统一致的数字输入框组件时 + +## 代码演示 + +### 基础用法 + + + +### 数字范围限制 + + + +### 精度控制 + + + +### 格式化显示 + + + +### 不同尺寸 + + + +### 带前缀和后缀 + + + +### 禁用状态 + + + +## API + +### BasicInputNumber + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| className | 数字输入框类名 | `string` | - | - | +| size | 输入框大小 | `'large' \| 'middle' \| 'small'` | `'large'` | - | + +### 继承属性 + +BasicInputNumber 组件继承了 Ant Design InputNumber 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| value | 当前值 | `number \| string` | - | - | +| defaultValue | 默认值 | `number \| string` | - | - | +| min | 最小值 | `number` | `-Infinity` | - | +| max | 最大值 | `number` | `Infinity` | - | +| step | 每次改变步数 | `number \| string` | `1` | - | +| precision | 数值精度 | `number` | - | - | +| decimalSeparator | 小数点 | `string` | `.` | - | +| formatter | 指定输入框展示值的格式 | `(value: number \| string, info: { userTyping: boolean, input: string }) => string` | - | - | +| parser | 指定从 formatter 里转换回数字的方法 | `(string) => number` | - | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| placeholder | 输入框占位符 | `string` | - | - | +| addonBefore | 输入框前置标签 | `ReactNode` | - | - | +| addonAfter | 输入框后置标签 | `ReactNode` | - | - | +| prefix | 输入框前缀图标 | `ReactNode` | - | - | +| suffix | 输入框后缀图标 | `ReactNode` | - | - | +| onChange | 变化回调 | `(value: number \| string \| null, info: { type: 'up' \| 'down' \| 'input' \| 'blur' \| 'focus' }) => void` | - | - | +| onPressEnter | 按下回车键时的回调 | `(e: KeyboardEvent) => void` | - | - | + +## 设计规范 + +### 尺寸规范 + +- **大尺寸 (lg)**: `height: 40px, padding: 0 12px` (默认) +- **默认尺寸**: `height: 32px, padding: 0 11px` +- **小尺寸 (sm)**: `height: 24px, padding: 0 7px` + +### 样式特性 + +- 统一的圆角设计 (`border-radius: 6px`) +- 基于主题的边框和背景色 +- 支持悬停、聚焦、禁用等状态样式 +- 自定义上下箭头按钮样式 +- 支持前缀和后缀标签 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicInputNumber = { + default: { + default: { border, background, color }, + hover: { border }, + focus: { border, boxShadow }, + disabled: { border, background, color } + }, + controls: { + default: { background, border, color }, + hover: { background }, + active: { background } + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. 组件会自动应用统一的样式类名 `basic-inputNumber-wrapper` +3. 默认尺寸设置为 `large`,与其他基础组件保持一致 +4. 支持所有 Ant Design InputNumber 的属性和事件 +5. 数值精度控制需要同时设置 `precision` 和 `step` 属性 +6. 格式化显示时注意 `formatter` 和 `parser` 的对应关系 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design InputNumber 封装 +- 支持所有 InputNumber 组件的属性和事件 +- 统一的样式规范和主题系统集成 +- 默认大尺寸设计,提升用户体验 +- 支持数值范围限制和精度控制 +- 支持格式化显示和自定义样式 diff --git a/packages/shared/lib/components/BasicInputNumber/__snapshots__/BasicInputNumber.test.tsx.snap b/packages/dms-kit/src/components/BasicInputNumber/__snapshots__/BasicInputNumber.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicInputNumber/__snapshots__/BasicInputNumber.test.tsx.snap rename to packages/dms-kit/src/components/BasicInputNumber/__snapshots__/BasicInputNumber.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicInputNumber/demo/affix.tsx b/packages/dms-kit/src/components/BasicInputNumber/demo/affix.tsx new file mode 100644 index 000000000..fdaf04778 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInputNumber/demo/affix.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { BasicInputNumber, ConfigProvider } from '@actiontech/dms-kit'; + +const AffixDemo = () => { + return ( + +
+ + + + +
+
+ ); +}; + +export default AffixDemo; diff --git a/packages/dms-kit/src/components/BasicInputNumber/demo/basic.tsx b/packages/dms-kit/src/components/BasicInputNumber/demo/basic.tsx new file mode 100644 index 000000000..f02313561 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInputNumber/demo/basic.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { BasicInputNumber, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicInputNumberDemo = () => { + return ( + +
+ + + +
+
+ ); +}; + +export default BasicInputNumberDemo; diff --git a/packages/dms-kit/src/components/BasicInputNumber/demo/disabled.tsx b/packages/dms-kit/src/components/BasicInputNumber/demo/disabled.tsx new file mode 100644 index 000000000..bef7733a9 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInputNumber/demo/disabled.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { BasicInputNumber, ConfigProvider } from '@actiontech/dms-kit'; + +const DisabledDemo = () => { + return ( + +
+ + + +
+
+ ); +}; + +export default DisabledDemo; diff --git a/packages/dms-kit/src/components/BasicInputNumber/demo/formatter.tsx b/packages/dms-kit/src/components/BasicInputNumber/demo/formatter.tsx new file mode 100644 index 000000000..c87c0fff2 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInputNumber/demo/formatter.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { BasicInputNumber, ConfigProvider } from '@actiontech/dms-kit'; + +const FormatterDemo = () => { + return ( + +
+ `${value}%`} + parser={(value) => value!.replace('%', '')} + /> + + `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',') + } + parser={(value) => value!.replace(/\$\s?|(,*)/g, '')} + /> + + `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',') + } + parser={(value) => value!.replace(/,/g, '')} + /> +
+
+ ); +}; + +export default FormatterDemo; diff --git a/packages/dms-kit/src/components/BasicInputNumber/demo/precision.tsx b/packages/dms-kit/src/components/BasicInputNumber/demo/precision.tsx new file mode 100644 index 000000000..1d082f7d4 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInputNumber/demo/precision.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { BasicInputNumber, ConfigProvider } from '@actiontech/dms-kit'; + +const PrecisionDemo = () => { + return ( + +
+ + + + +
+
+ ); +}; + +export default PrecisionDemo; diff --git a/packages/dms-kit/src/components/BasicInputNumber/demo/range.tsx b/packages/dms-kit/src/components/BasicInputNumber/demo/range.tsx new file mode 100644 index 000000000..3d2946c78 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInputNumber/demo/range.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { BasicInputNumber, ConfigProvider } from '@actiontech/dms-kit'; + +const RangeDemo = () => { + return ( + +
+ + + + +
+
+ ); +}; + +export default RangeDemo; diff --git a/packages/dms-kit/src/components/BasicInputNumber/demo/sizes.tsx b/packages/dms-kit/src/components/BasicInputNumber/demo/sizes.tsx new file mode 100644 index 000000000..0116a7731 --- /dev/null +++ b/packages/dms-kit/src/components/BasicInputNumber/demo/sizes.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { BasicInputNumber, ConfigProvider } from '@actiontech/dms-kit'; + +const SizesDemo = () => { + return ( + +
+ + + +
+
+ ); +}; + +export default SizesDemo; diff --git a/packages/shared/lib/components/BasicInputNumber/index.ts b/packages/dms-kit/src/components/BasicInputNumber/index.ts similarity index 100% rename from packages/shared/lib/components/BasicInputNumber/index.ts rename to packages/dms-kit/src/components/BasicInputNumber/index.ts diff --git a/packages/shared/lib/components/BasicInputNumber/style.ts b/packages/dms-kit/src/components/BasicInputNumber/style.ts similarity index 56% rename from packages/shared/lib/components/BasicInputNumber/style.ts rename to packages/dms-kit/src/components/BasicInputNumber/style.ts index f6c867495..78b239e02 100644 --- a/packages/shared/lib/components/BasicInputNumber/style.ts +++ b/packages/dms-kit/src/components/BasicInputNumber/style.ts @@ -1,7 +1,17 @@ -import { styled } from '@mui/material/styles'; -import { InputNumber } from 'antd'; +import { StyledComponent } from '@emotion/styled'; +import { styled, Theme } from '@mui/material/styles'; +import { MUIStyledCommonProps } from '@mui/system/createStyled'; +import { InputNumber, InputNumberProps } from 'antd'; -export const BasicInputNumberStyleWrapper = styled(InputNumber)` +export const BasicInputNumberStyleWrapper: StyledComponent< + InputNumberProps & { + children?: React.ReactNode; + } & { + ref?: React.Ref | undefined; + } & MUIStyledCommonProps, + {}, + {} +> = styled(InputNumber)` &.basic-inputNumber-wrapper.ant-input-number { font-size: 14px; border-radius: 4px; diff --git a/packages/shared/lib/components/BasicModal/BasicModal.test.tsx b/packages/dms-kit/src/components/BasicModal/BasicModal.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicModal/BasicModal.test.tsx rename to packages/dms-kit/src/components/BasicModal/BasicModal.test.tsx diff --git a/packages/shared/lib/components/BasicModal/BasicModal.tsx b/packages/dms-kit/src/components/BasicModal/BasicModal.tsx similarity index 100% rename from packages/shared/lib/components/BasicModal/BasicModal.tsx rename to packages/dms-kit/src/components/BasicModal/BasicModal.tsx diff --git a/packages/shared/lib/components/BasicModal/BasicModal.types.ts b/packages/dms-kit/src/components/BasicModal/BasicModal.types.ts similarity index 100% rename from packages/shared/lib/components/BasicModal/BasicModal.types.ts rename to packages/dms-kit/src/components/BasicModal/BasicModal.types.ts diff --git a/packages/dms-kit/src/components/BasicModal/README.md b/packages/dms-kit/src/components/BasicModal/README.md new file mode 100644 index 000000000..446d5aa83 --- /dev/null +++ b/packages/dms-kit/src/components/BasicModal/README.md @@ -0,0 +1,134 @@ +--- +group: + title: 通用 + order: 2 +--- + +# BasicModal 基础模态框 + +基于 Ant Design Modal 组件封装的基础模态框组件,提供了统一的样式规范和尺寸预设,适用于各种弹窗场景。 + +## 何时使用 + +- 需要显示重要信息或操作确认时 +- 需要用户输入或选择时 +- 需要展示详细内容而不跳转页面时 +- 需要保持与设计系统一致的弹窗样式时 + +## 代码演示 + +### 基础用法 + + + +### 不同尺寸 + + + +### 自定义宽度 + + + +### 表单弹窗 + + + +### 确认弹窗 + + + +### 信息展示弹窗 + + + +### 复杂内容弹窗 + + + +## API + +### BasicModal + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| size | 弹窗尺寸预设 | `'small' \| 'large'` | `'small'` | - | + +### 继承属性 + +BasicModal 组件继承了 Ant Design Modal 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| visible | 对话框是否可见 | `boolean` | `false` | - | +| title | 标题 | `ReactNode` | - | - | +| children | 对话框内容 | `ReactNode` | - | - | +| width | 宽度 | `string \| number` | `480` (small) / `960` (large) | - | +| onOk | 点击确定回调 | `function(e)` | - | - | +| onCancel | 点击遮罩层或右上角叉或取消按钮的回调 | `function(e)` | - | - | +| okText | 确定按钮文字 | `string` | `'确定'` | - | +| cancelText | 取消按钮文字 | `string` | `'取消'` | - | +| confirmLoading | 确定按钮 loading | `boolean` | `false` | - | +| destroyOnClose | 关闭时销毁 Modal 里的子元素 | `boolean` | `false` | - | +| maskClosable | 点击蒙层是否允许关闭 | `boolean` | `true` | - | +| closable | 是否显示右上角的关闭按钮 | `boolean` | `true` | - | +| closeIcon | 自定义关闭图标 | `ReactNode` | `` | - | +| className | 对话框外层容器的类名 | `string` | - | - | +| style | 对话框外层容器的样式 | `CSSProperties` | - | - | + +## 设计规范 + +### 尺寸规范 + +- **小尺寸 (small)**: `width: 480px` - 适用于简单表单、确认信息等 +- **大尺寸 (large)**: `width: 960px` - 适用于复杂表单、详细内容展示等 +- **自定义宽度**: 可通过 `width` 属性覆盖预设尺寸 + +### 样式特性 + +- 统一的圆角设计 (`border-radius: 8px`) +- 标准化的内边距 (`padding: 24px`) +- 自定义关闭图标 (`CloseOutlined`,16x16px) +- 基于主题的色彩系统 +- 响应式设计,支持移动端适配 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicModal = { + content: { + backgroundColor: string, + border: string, + header: { + border: string, + title: { + color: string + } + }, + body: { + color: string + }, + footer: { + backgroundColor: string + } + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `size` 属性提供预设尺寸,可通过 `width` 属性进行覆盖 +3. 所有 Ant Design Modal 的属性和事件都可以正常使用 +4. 组件会自动应用统一的样式类名 `basic-modal-wrapper` +5. 建议根据内容复杂度选择合适的尺寸预设 +6. 弹窗内容应保持简洁,避免信息过载 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Modal 封装 +- 支持所有 Modal 组件的属性和事件 +- 新增 `size` 属性支持预设尺寸 +- 统一的样式规范和主题系统集成 +- 自定义关闭图标和样式优化 diff --git a/packages/shared/lib/components/BasicModal/__snapshots__/BasicModal.test.tsx.snap b/packages/dms-kit/src/components/BasicModal/__snapshots__/BasicModal.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicModal/__snapshots__/BasicModal.test.tsx.snap rename to packages/dms-kit/src/components/BasicModal/__snapshots__/BasicModal.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicModal/demo/basic.tsx b/packages/dms-kit/src/components/BasicModal/demo/basic.tsx new file mode 100644 index 000000000..992a5ff8c --- /dev/null +++ b/packages/dms-kit/src/components/BasicModal/demo/basic.tsx @@ -0,0 +1,37 @@ +import React, { useState } from 'react'; +import { BasicModal, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicModalDemo = () => { + const [visible, setVisible] = useState(false); + + const showModal = () => { + setVisible(true); + }; + + const handleOk = () => { + setVisible(false); + }; + + const handleCancel = () => { + setVisible(false); + }; + + return ( + + + 打开弹窗 + + +

这是一个基础的弹窗示例,展示了 BasicModal 的基本用法。

+

弹窗内容可以包含任何 React 组件和 HTML 元素。

+
+
+ ); +}; + +export default BasicModalDemo; diff --git a/packages/dms-kit/src/components/BasicModal/demo/complex.tsx b/packages/dms-kit/src/components/BasicModal/demo/complex.tsx new file mode 100644 index 000000000..b13445578 --- /dev/null +++ b/packages/dms-kit/src/components/BasicModal/demo/complex.tsx @@ -0,0 +1,152 @@ +import React, { useState } from 'react'; +import { BasicModal, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Tabs, Table, Tag, Progress } from 'antd'; + +const BasicModalComplexDemo = () => { + const [visible, setVisible] = useState(false); + + const dataSource = [ + { + key: '1', + name: '数据库 A', + status: 'running', + progress: 85, + tags: ['MySQL', '生产环境'] + }, + { + key: '2', + name: '数据库 B', + status: 'stopped', + progress: 0, + tags: ['PostgreSQL', '测试环境'] + }, + { + key: '3', + name: '数据库 C', + status: 'maintenance', + progress: 45, + tags: ['MongoDB', '开发环境'] + } + ]; + + const columns = [ + { + title: '数据库名称', + dataIndex: 'name', + key: 'name', + }, + { + title: '状态', + dataIndex: 'status', + key: 'status', + render: (status: string) => { + const statusMap = { + running: { color: 'green', text: '运行中' }, + stopped: { color: 'red', text: '已停止' }, + maintenance: { color: 'orange', text: '维护中' } + }; + const { color, text } = statusMap[status as keyof typeof statusMap]; + return {text}; + } + }, + { + title: '进度', + dataIndex: 'progress', + key: 'progress', + render: (progress: number) => + }, + { + title: '标签', + dataIndex: 'tags', + key: 'tags', + render: (tags: string[]) => ( + <> + {tags.map(tag => ( + {tag} + ))} + + ) + } + ]; + + return ( + + setVisible(true)}> + 复杂内容弹窗 + + + setVisible(false)} + onCancel={() => setVisible(false)} + okText="保存配置" + cancelText="关闭" + > + +

系统概览

+

当前系统运行状态良好,共有 3 个数据库实例。

+
+
+
3
+
总数据库数
+
+
+
1
+
运行中
+
+
+
1
+
维护中
+
+
+
1
+
已停止
+
+
+
+ ) + }, + { + key: 'databases', + label: '数据库列表', + children: ( +
+

数据库实例

+ + + ) + }, + { + key: 'settings', + label: '配置设置', + children: ( +
+

系统配置

+

这里可以配置各种系统参数和选项。

+

包括数据库连接池、缓存策略、日志级别等。

+
+ ) + } + ]} + /> + + + ); +}; + +export default BasicModalComplexDemo; diff --git a/packages/dms-kit/src/components/BasicModal/demo/confirm.tsx b/packages/dms-kit/src/components/BasicModal/demo/confirm.tsx new file mode 100644 index 000000000..ac5ffb2e4 --- /dev/null +++ b/packages/dms-kit/src/components/BasicModal/demo/confirm.tsx @@ -0,0 +1,74 @@ +import React, { useState } from 'react'; +import { BasicModal, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; +import { ExclamationCircleOutlined } from '@ant-design/icons'; + +const BasicModalConfirmDemo = () => { + const [deleteVisible, setDeleteVisible] = useState(false); + const [confirmVisible, setConfirmVisible] = useState(false); + + const showDeleteModal = () => { + setDeleteVisible(true); + }; + + const showConfirmModal = () => { + setConfirmVisible(true); + }; + + const handleDelete = () => { + console.log('删除操作已确认'); + setDeleteVisible(false); + }; + + const handleConfirm = () => { + console.log('操作已确认'); + setConfirmVisible(false); + }; + + return ( + + + + 删除确认 + + + 操作确认 + + + + + + 删除确认 + + } + visible={deleteVisible} + size="small" + onOk={handleDelete} + onCancel={() => setDeleteVisible(false)} + okText="删除" + cancelText="取消" + okButtonProps={{ danger: true }} + > +

确定要删除这条记录吗?此操作不可恢复。

+

删除后,相关的数据将永久丢失。

+
+ + setConfirmVisible(false)} + okText="确认" + cancelText="取消" + > +

请确认您要执行此操作。

+

操作完成后,系统将发送通知到您的邮箱。

+
+
+ ); +}; + +export default BasicModalConfirmDemo; diff --git a/packages/dms-kit/src/components/BasicModal/demo/customWidth.tsx b/packages/dms-kit/src/components/BasicModal/demo/customWidth.tsx new file mode 100644 index 000000000..456877f35 --- /dev/null +++ b/packages/dms-kit/src/components/BasicModal/demo/customWidth.tsx @@ -0,0 +1,28 @@ +import React, { useState } from 'react'; +import { BasicModal, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicModalCustomWidthDemo = () => { + const [customVisible, setCustomVisible] = useState(false); + + return ( + + setCustomVisible(true)}> + 自定义宽度弹窗 + + + setCustomVisible(false)} + onCancel={() => setCustomVisible(false)} + > +

这个弹窗使用了自定义宽度 600px,覆盖了预设的尺寸。

+

当预设尺寸不满足需求时,可以通过 width 属性设置任意宽度。

+

自定义宽度适用于特殊的布局需求,如侧边栏弹窗、宽屏内容展示等。

+
+
+ ); +}; + +export default BasicModalCustomWidthDemo; diff --git a/packages/dms-kit/src/components/BasicModal/demo/form.tsx b/packages/dms-kit/src/components/BasicModal/demo/form.tsx new file mode 100644 index 000000000..8f8685c16 --- /dev/null +++ b/packages/dms-kit/src/components/BasicModal/demo/form.tsx @@ -0,0 +1,78 @@ +import React, { useState } from 'react'; +import { BasicModal, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Form, Input, Select } from 'antd'; + +const BasicModalFormDemo = () => { + const [visible, setVisible] = useState(false); + const [form] = Form.useForm(); + + const showModal = () => { + setVisible(true); + }; + + const handleOk = () => { + form.validateFields().then((values) => { + console.log('Form values:', values); + setVisible(false); + form.resetFields(); + }); + }; + + const handleCancel = () => { + setVisible(false); + form.resetFields(); + }; + + return ( + + + 表单弹窗 + + + +
+ + + + + + + + + + + + +
+
+ ); +}; + +export default BasicModalFormDemo; diff --git a/packages/dms-kit/src/components/BasicModal/demo/info.tsx b/packages/dms-kit/src/components/BasicModal/demo/info.tsx new file mode 100644 index 000000000..2a6421ec2 --- /dev/null +++ b/packages/dms-kit/src/components/BasicModal/demo/info.tsx @@ -0,0 +1,76 @@ +import React, { useState } from 'react'; +import { BasicModal, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; +import { InfoCircleOutlined } from '@ant-design/icons'; + +const BasicModalInfoDemo = () => { + const [infoVisible, setInfoVisible] = useState(false); + const [helpVisible, setHelpVisible] = useState(false); + + return ( + + + setInfoVisible(true)}> + 信息展示 + + setHelpVisible(true)}> + 帮助信息 + + + + + + 系统通知 + + } + visible={infoVisible} + size="small" + onOk={() => setInfoVisible(false)} + onCancel={() => setInfoVisible(false)} + okText="知道了" + cancelText={null} + closable={false} + maskClosable={false} + > +
+ +

系统维护通知

+

系统将于今晚 22:00-24:00 进行维护升级,期间可能影响正常使用。

+

给您带来的不便,敬请谅解。

+
+
+ + setHelpVisible(false)} + onCancel={() => setHelpVisible(false)} + okText="关闭" + cancelText={null} + > +
+

功能介绍

+

本系统提供了完整的数据库管理功能,包括:

+
    +
  • 数据库连接管理
  • +
  • SQL 查询执行
  • +
  • 数据导入导出
  • +
  • 用户权限管理
  • +
  • 系统配置管理
  • +
+ +

使用说明

+

1. 首次使用请先配置数据库连接

+

2. 确保有足够的操作权限

+

3. 定期备份重要数据

+

4. 如遇问题请联系技术支持

+
+
+
+ ); +}; + +export default BasicModalInfoDemo; diff --git a/packages/dms-kit/src/components/BasicModal/demo/sizes.tsx b/packages/dms-kit/src/components/BasicModal/demo/sizes.tsx new file mode 100644 index 000000000..2a4d4cb3a --- /dev/null +++ b/packages/dms-kit/src/components/BasicModal/demo/sizes.tsx @@ -0,0 +1,46 @@ +import React, { useState } from 'react'; +import { BasicModal, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; + +const BasicModalSizesDemo = () => { + const [smallVisible, setSmallVisible] = useState(false); + const [largeVisible, setLargeVisible] = useState(false); + + return ( + + + setSmallVisible(true)}> + 小尺寸弹窗 + + setLargeVisible(true)}> + 大尺寸弹窗 + + + + setSmallVisible(false)} + onCancel={() => setSmallVisible(false)} + > +

这是小尺寸弹窗 (480px),适用于简单的信息展示和确认操作。

+

内容较少时建议使用小尺寸弹窗。

+
+ + setLargeVisible(false)} + onCancel={() => setLargeVisible(false)} + > +

这是大尺寸弹窗 (960px),适用于复杂的内容展示和表单操作。

+

当需要展示更多内容或复杂表单时,建议使用大尺寸弹窗。

+

大尺寸弹窗提供了更宽敞的空间,可以容纳更多的信息和交互元素。

+
+
+ ); +}; + +export default BasicModalSizesDemo; diff --git a/packages/shared/lib/components/BasicModal/index.ts b/packages/dms-kit/src/components/BasicModal/index.ts similarity index 100% rename from packages/shared/lib/components/BasicModal/index.ts rename to packages/dms-kit/src/components/BasicModal/index.ts diff --git a/packages/shared/lib/components/BasicModal/style.ts b/packages/dms-kit/src/components/BasicModal/style.ts similarity index 100% rename from packages/shared/lib/components/BasicModal/style.ts rename to packages/dms-kit/src/components/BasicModal/style.ts diff --git a/packages/shared/lib/components/BasicRangePicker/BasicRangePicker.test.tsx b/packages/dms-kit/src/components/BasicRangePicker/BasicRangePicker.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicRangePicker/BasicRangePicker.test.tsx rename to packages/dms-kit/src/components/BasicRangePicker/BasicRangePicker.test.tsx diff --git a/packages/shared/lib/components/BasicRangePicker/BasicRangePicker.tsx b/packages/dms-kit/src/components/BasicRangePicker/BasicRangePicker.tsx similarity index 100% rename from packages/shared/lib/components/BasicRangePicker/BasicRangePicker.tsx rename to packages/dms-kit/src/components/BasicRangePicker/BasicRangePicker.tsx diff --git a/packages/shared/lib/components/BasicRangePicker/BasicRangePicker.types.ts b/packages/dms-kit/src/components/BasicRangePicker/BasicRangePicker.types.ts similarity index 100% rename from packages/shared/lib/components/BasicRangePicker/BasicRangePicker.types.ts rename to packages/dms-kit/src/components/BasicRangePicker/BasicRangePicker.types.ts diff --git a/packages/dms-kit/src/components/BasicRangePicker/README.md b/packages/dms-kit/src/components/BasicRangePicker/README.md new file mode 100644 index 000000000..9266b4204 --- /dev/null +++ b/packages/dms-kit/src/components/BasicRangePicker/README.md @@ -0,0 +1,160 @@ +--- +group: + title: 通用 + order: 1 +--- + +# BasicRangePicker 基础日期范围选择器组件 + +## 组件介绍 + +BasicRangePicker 是一个基于 Ant Design RangePicker 组件封装的基础日期范围选择器,提供了统一的样式风格、自定义分隔符、前缀图标等功能。它是 dms-kit 中常用的日期范围输入组件。 + +## 何时使用 + +- 需要选择日期范围时(如开始日期到结束日期) +- 需要统一的日期范围选择器样式风格 +- 需要自定义分隔符和清除图标的日期范围选择器 +- 需要前缀图标的日期范围输入框 + +## 代码演示 + +### 基础用法 + +最简单的日期范围选择器用法,支持基本的日期范围选择功能。 + + + +### 不同尺寸 + +支持三种尺寸:small、middle、large。 + + + +### 自定义格式 + +支持自定义日期显示格式和输入格式。 + + + +### 禁用状态 + +当不需要用户输入时,可以禁用日期范围选择器。通过设置 `disabled` 属性为 `true` 即可禁用组件。 + +### 范围限制 + +可以设置日期的选择范围,限制用户只能选择特定时间段的日期。通过 `disabledDate` 属性可以禁用指定的日期。 + +### 前缀图标 + +通过 prefix 属性添加前缀图标,当同时存在 suffixIcon 和 prefix 时,prefix 会被覆盖。 + + + +### 自定义分隔符 + +使用自定义的分隔符图标,默认为右箭头图标。 + + + +### 显示超级图标 + +控制是否显示年份和月份的快速跳转按钮。通过 `hideSuperIcon` 属性控制,默认为 `true`(隐藏)。 + +### 自定义样式 + +通过 className 属性添加自定义样式类。 + +## API 文档 + +### BasicRangePickerProps + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| prefix | 前缀图标,当 suffixIcon 存在时会被覆盖 | ReactNode | - | - | +| hideSuperIcon | 是否隐藏年份和月份的快速跳转按钮 | boolean | true | - | +| className | 自定义 CSS 类名 | string | - | - | + +### 继承属性 + +BasicRangePicker 继承了 Ant Design RangePicker 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| value | 当前选中的日期范围 | [Dayjs, Dayjs] | - | - | +| defaultValue | 默认选中的日期范围 | [Dayjs, Dayjs] | - | - | +| onChange | 日期范围变化回调 | (dates: [Dayjs, Dayjs] \| null, dateStrings: [string, string]) => void | - | - | +| placeholder | 输入框提示文字 | [string, string] | - | - | +| format | 日期格式 | string | 'YYYY-MM-DD' | - | +| size | 输入框大小 | 'large' \| 'middle' \| 'small' | 'middle' | - | +| disabled | 是否禁用 | boolean | false | - | +| allowClear | 是否显示清除按钮 | boolean | true | - | +| showTime | 是否显示时间选择 | boolean \| object | false | - | +| disabledDate | 不可选择的日期 | (current: Dayjs) => boolean | - | - | +| onOpenChange | 弹出层展开/收起回调 | (open: boolean) => void | - | - | +| separator | 分隔符 | ReactNode | \ | - | + +## 设计规范 + +### 样式特点 + +- **统一边框**: 使用主题的边框色,hover 和 focus 状态有相应的边框变化 +- **自定义分隔符**: 默认使用右箭头图标作为日期范围分隔符 +- **清除图标**: 使用自定义的关闭图标,支持主题色配置 +- **前缀图标**: 支持添加前缀图标,与 suffixIcon 互斥 +- **圆角设计**: 输入框使用 4px 圆角,保持与其他组件的一致性 + +### 主题配置 + +BasicRangePicker 支持以下主题变量: + +```less +// 日期范围选择器样式变量 +@color-border: #d9d9d9; +@color-bg-layout: #fafafa; +@color-default-icon: #8c8c8c; + +// 状态样式 +@basic-range-picker-default-border: 1px solid #d9d9d9; +@basic-range-picker-hover-border: 1px solid #40a9ff; +@basic-range-picker-active-border: 1px solid #1890ff; +@basic-range-picker-error-border: 1px solid #ff4d4f; +@basic-range-picker-disabled-border: 1px solid #d9d9d9; + +// 占位符样式 +@basic-range-picker-default-placeholder-color: #bfbfbf; +``` + +### 交互状态 + +- **默认状态**: 使用主题的默认边框色 +- **悬停状态**: 边框色变为主题色,有平滑的过渡动画 +- **聚焦状态**: 边框色为主题色,显示聚焦轮廓 +- **错误状态**: 边框色为错误色,用于表单验证失败时 +- **禁用状态**: 边框色为禁用色,背景色为禁用背景色 + +### 布局特点 + +- **前缀图标**: 当存在 prefix 且没有 suffixIcon 时,prefix 会显示在右侧 +- **分隔符**: 日期范围之间的分隔符使用右箭头图标 +- **清除按钮**: 清除按钮使用自定义的关闭图标 +- **导航按钮**: 左右箭头按钮使用自定义图标,支持主题色配置 + +## 注意事项 + +1. **图标依赖**: 组件依赖 `@actiontech/icons` 包中的图标组件 +2. **日期格式**: 默认使用 dayjs 处理日期,确保项目中已安装 dayjs +3. **主题系统**: 组件使用 MUI 的 styled 系统,需要正确的主题上下文 +4. **前缀图标**: 当同时存在 suffixIcon 和 prefix 时,prefix 会被 suffixIcon 覆盖 +5. **弹出层定位**: 下拉面板的定位容器为触发器本身,避免定位问题 +6. **国际化**: 日期格式和文本支持国际化配置 + +## 更新日志 + +### 1.0.0 +- 初始版本发布 +- 支持基础日期范围选择功能 +- 集成自定义分隔符和清除图标 +- 支持前缀图标显示 +- 自定义导航按钮样式 +- 支持超级图标显示控制 diff --git a/packages/shared/lib/components/BasicRangePicker/__snapshots__/BasicRangePicker.test.tsx.snap b/packages/dms-kit/src/components/BasicRangePicker/__snapshots__/BasicRangePicker.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicRangePicker/__snapshots__/BasicRangePicker.test.tsx.snap rename to packages/dms-kit/src/components/BasicRangePicker/__snapshots__/BasicRangePicker.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicRangePicker/demos/basic.tsx b/packages/dms-kit/src/components/BasicRangePicker/demos/basic.tsx new file mode 100644 index 000000000..b1a75ea9b --- /dev/null +++ b/packages/dms-kit/src/components/BasicRangePicker/demos/basic.tsx @@ -0,0 +1,34 @@ +import React, { useState } from 'react'; +import { BasicRangePicker, ConfigProvider } from '@actiontech/dms-kit'; +import type { Dayjs } from 'dayjs'; + +const BasicRangePickerBasicDemo: React.FC = () => { + const [dateRange, setDateRange] = useState< + [Dayjs | null, Dayjs | null] | null + >(null); + + const handleRangeChange = ( + dates: [Dayjs | null, Dayjs | null] | null, + dateStrings: [string, string] + ) => { + setDateRange(dates); + if (dates && dates[0] && dates[1]) { + console.log('开始日期:', dates[0].format('YYYY-MM-DD')); + console.log('结束日期:', dates[1].format('YYYY-MM-DD')); + console.log('开始日期字符串:', dateStrings[0]); + console.log('结束日期字符串:', dateStrings[1]); + } + }; + + return ( + + + + ); +}; + +export default BasicRangePickerBasicDemo; diff --git a/packages/dms-kit/src/components/BasicRangePicker/demos/format.tsx b/packages/dms-kit/src/components/BasicRangePicker/demos/format.tsx new file mode 100644 index 000000000..a3edb3884 --- /dev/null +++ b/packages/dms-kit/src/components/BasicRangePicker/demos/format.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { BasicRangePicker, ConfigProvider } from '@actiontech/dms-kit'; +import dayjs from 'dayjs'; + +const BasicRangePickerFormatDemo: React.FC = () => ( + +
+ + + +
+
+); + +export default BasicRangePickerFormatDemo; diff --git a/packages/dms-kit/src/components/BasicRangePicker/demos/prefix.tsx b/packages/dms-kit/src/components/BasicRangePicker/demos/prefix.tsx new file mode 100644 index 000000000..bfcc380de --- /dev/null +++ b/packages/dms-kit/src/components/BasicRangePicker/demos/prefix.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { BasicRangePicker, ConfigProvider } from '@actiontech/dms-kit'; +import { + CalendarOutlined, + ClockCircleOutlined, + UserOutlined +} from '@ant-design/icons'; + +const BasicRangePickerPrefixDemo: React.FC = () => ( + +
+ } + placeholder={['开始日期', '结束日期']} + /> + } + placeholder={['开始时间', '结束时间']} + /> + } + placeholder={['入职开始日期', '入职结束日期']} + /> +
+
+); + +export default BasicRangePickerPrefixDemo; diff --git a/packages/dms-kit/src/components/BasicRangePicker/demos/separator.tsx b/packages/dms-kit/src/components/BasicRangePicker/demos/separator.tsx new file mode 100644 index 000000000..d83897f63 --- /dev/null +++ b/packages/dms-kit/src/components/BasicRangePicker/demos/separator.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { BasicRangePicker, ConfigProvider } from '@actiontech/dms-kit'; +import { + ArrowRightOutlined, + MinusOutlined, + SwapOutlined, + DoubleRightOutlined +} from '@ant-design/icons'; + +const BasicRangePickerSeparatorDemo: React.FC = () => ( + +
+ } + placeholder={['开始日期', '结束日期']} + /> + } + placeholder={['开始日期', '结束日期']} + /> + } + placeholder={['开始日期', '结束日期']} + /> + } + placeholder={['开始日期', '结束日期']} + /> +
+
+); + +export default BasicRangePickerSeparatorDemo; diff --git a/packages/dms-kit/src/components/BasicRangePicker/demos/size.tsx b/packages/dms-kit/src/components/BasicRangePicker/demos/size.tsx new file mode 100644 index 000000000..127f49353 --- /dev/null +++ b/packages/dms-kit/src/components/BasicRangePicker/demos/size.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { BasicRangePicker, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicRangePickerSizeDemo: React.FC = () => ( + +
+ + + +
+
+); + +export default BasicRangePickerSizeDemo; diff --git a/packages/shared/lib/components/BasicRangePicker/index.ts b/packages/dms-kit/src/components/BasicRangePicker/index.ts similarity index 100% rename from packages/shared/lib/components/BasicRangePicker/index.ts rename to packages/dms-kit/src/components/BasicRangePicker/index.ts diff --git a/packages/shared/lib/components/BasicRangePicker/style.ts b/packages/dms-kit/src/components/BasicRangePicker/style.ts similarity index 100% rename from packages/shared/lib/components/BasicRangePicker/style.ts rename to packages/dms-kit/src/components/BasicRangePicker/style.ts diff --git a/packages/shared/lib/components/BasicResult/BasicResult.test.tsx b/packages/dms-kit/src/components/BasicResult/BasicResult.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicResult/BasicResult.test.tsx rename to packages/dms-kit/src/components/BasicResult/BasicResult.test.tsx diff --git a/packages/shared/lib/components/BasicResult/BasicResult.tsx b/packages/dms-kit/src/components/BasicResult/BasicResult.tsx similarity index 100% rename from packages/shared/lib/components/BasicResult/BasicResult.tsx rename to packages/dms-kit/src/components/BasicResult/BasicResult.tsx diff --git a/packages/shared/lib/components/BasicResult/BasicResult.types.ts b/packages/dms-kit/src/components/BasicResult/BasicResult.types.ts similarity index 100% rename from packages/shared/lib/components/BasicResult/BasicResult.types.ts rename to packages/dms-kit/src/components/BasicResult/BasicResult.types.ts diff --git a/packages/dms-kit/src/components/BasicResult/README.md b/packages/dms-kit/src/components/BasicResult/README.md new file mode 100644 index 000000000..8a3808bc3 --- /dev/null +++ b/packages/dms-kit/src/components/BasicResult/README.md @@ -0,0 +1,119 @@ +--- +group: + title: 通用 + order: 4 +--- + +# BasicResult 基础结果页 + +基于 Ant Design Result 组件封装的基础结果页组件,提供了统一的样式规范和自定义图标支持,适用于各种操作结果的展示。 + +## 何时使用 + +- 提交表单后需要展示操作结果时 +- 操作成功或失败后需要给用户反馈时 +- 需要展示空状态或错误状态时 +- 需要保持与设计系统一致的结果页样式时 + +## 代码演示 + +### 基础用法 + + + +### 不同状态 + + + +### 自定义图标 + + + +### 带操作按钮 + + + +### 空状态展示 + + + +### 错误状态展示 + + + +## API + +### BasicResult + +BasicResult 组件继承了 Ant Design Result 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| status | 结果的状态,决定图标和颜色 | `'success' \| 'error' \| 'info' \| 'warning' \| '404' \| '403' \| '500'` | `'info'` | - | +| title | 标题 | `ReactNode` | - | - | +| subTitle | 副标题 | `ReactNode` | - | - | +| icon | 自定义图标 | `ReactNode` | - | - | +| extra | 操作区 | `ReactNode` | - | - | +| className | 结果页类名 | `string` | - | - | +| style | 结果页样式 | `CSSProperties` | - | - | + +## 设计规范 + +### 状态规范 + +- **success**: 成功状态,绿色图标,适用于操作成功场景 +- **error**: 错误状态,红色图标,适用于操作失败场景 +- **info**: 信息状态,蓝色图标,适用于信息展示场景 +- **warning**: 警告状态,橙色图标,适用于警告提示场景 +- **404**: 页面不存在,适用于 404 错误页面 +- **403**: 无权限访问,适用于权限不足场景 +- **500**: 服务器错误,适用于系统错误场景 + +### 样式特性 + +- 统一的图标设计,支持所有 Ant Design Result 状态 +- 标准化的标题和副标题样式 +- 基于主题的色彩系统 +- 响应式设计,支持移动端适配 +- 支持自定义图标和操作区域 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicResult = { + // 主题配置变量 + title: { + color: string, + fontSize: string, + fontWeight: string + }, + subTitle: { + color: string, + fontSize: string + }, + icon: { + fontSize: string + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `status` 属性决定了图标的样式和颜色 +3. 可以通过 `icon` 属性自定义图标 +4. `extra` 属性可以添加操作按钮 +5. 所有 Ant Design Result 的属性和事件都可以正常使用 +6. 组件会自动应用统一的样式类名 `basic-result-wrapper` +7. 建议根据操作结果选择合适的状态 +8. 结果页内容应简洁明了,避免信息过载 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Result 封装 +- 支持所有 Result 组件的属性和事件 +- 统一的样式规范和主题系统集成 +- 自定义图标支持 +- 响应式设计和移动端适配 diff --git a/packages/shared/lib/components/BasicResult/ResultIcon.tsx b/packages/dms-kit/src/components/BasicResult/ResultIcon.tsx similarity index 100% rename from packages/shared/lib/components/BasicResult/ResultIcon.tsx rename to packages/dms-kit/src/components/BasicResult/ResultIcon.tsx diff --git a/packages/shared/lib/components/BasicResult/__snapshots__/BasicResult.test.tsx.snap b/packages/dms-kit/src/components/BasicResult/__snapshots__/BasicResult.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicResult/__snapshots__/BasicResult.test.tsx.snap rename to packages/dms-kit/src/components/BasicResult/__snapshots__/BasicResult.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicResult/demo/basic.tsx b/packages/dms-kit/src/components/BasicResult/demo/basic.tsx new file mode 100644 index 000000000..919187c73 --- /dev/null +++ b/packages/dms-kit/src/components/BasicResult/demo/basic.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { BasicResult, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicResultDemo = () => { + return ( + + + + ); +}; + +export default BasicResultDemo; diff --git a/packages/dms-kit/src/components/BasicResult/demo/customIcon.tsx b/packages/dms-kit/src/components/BasicResult/demo/customIcon.tsx new file mode 100644 index 000000000..8788c015b --- /dev/null +++ b/packages/dms-kit/src/components/BasicResult/demo/customIcon.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { BasicResult, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; +import { SmileOutlined, HeartOutlined, StarOutlined } from '@ant-design/icons'; + +const BasicResultCustomIconDemo = () => { + return ( + + + } + title="自定义图标 - 笑脸" + subTitle="使用自定义的笑脸图标,表达愉悦的心情。" + /> + + } + title="自定义图标 - 爱心" + subTitle="使用自定义的爱心图标,表达喜爱之情。" + /> + + } + title="自定义图标 - 星星" + subTitle="使用自定义的星星图标,表达优秀之意。" + /> + + + DMS + + } + title="自定义图标 - 文字图标" + subTitle="使用自定义的文字图标,展示品牌标识。" + /> + + + ); +}; + +export default BasicResultCustomIconDemo; diff --git a/packages/dms-kit/src/components/BasicResult/demo/empty.tsx b/packages/dms-kit/src/components/BasicResult/demo/empty.tsx new file mode 100644 index 000000000..57f1fab47 --- /dev/null +++ b/packages/dms-kit/src/components/BasicResult/demo/empty.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { BasicResult, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; + +const BasicResultEmptyDemo = () => { + const handleCreateAction = () => { + console.log('创建新项目'); + }; + + const handleImportAction = () => { + console.log('导入项目'); + }; + + const handleRefreshAction = () => { + console.log('刷新页面'); + }; + + return ( + + + + 创建新项目 + , + + 导入项目 + + ]} + /> + + + 刷新页面 + , + console.log('清除搜索条件')}> + 清除搜索条件 + + ]} + /> + + console.log('联系管理员')}> + 联系管理员 + , + console.log('返回首页')}> + 返回首页 + + ]} + /> + + + 重试 + , + console.log('离线模式')}> + 离线模式 + + ]} + /> + + + ); +}; + +export default BasicResultEmptyDemo; diff --git a/packages/dms-kit/src/components/BasicResult/demo/error.tsx b/packages/dms-kit/src/components/BasicResult/demo/error.tsx new file mode 100644 index 000000000..81c275e51 --- /dev/null +++ b/packages/dms-kit/src/components/BasicResult/demo/error.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { BasicResult, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; + +const BasicResultErrorDemo = () => { + const handleRetryAction = () => { + console.log('重试操作'); + }; + + const handleReportAction = () => { + console.log('报告问题'); + }; + + const handleBackAction = () => { + console.log('返回上一页'); + }; + + return ( + + + + 重试 + , + + 报告问题 + + ]} + /> + + console.log('联系管理员')}> + 联系管理员 + , + + 返回上一页 + + ]} + /> + + console.log('返回首页')}> + 返回首页 + , + console.log('搜索页面')}> + 搜索页面 + + ]} + /> + + + 重试操作 + , + console.log('获取帮助')}> + 获取帮助 + + ]} + /> + + console.log('继续操作')}> + 继续操作 + , + console.log('取消操作')}> + 取消操作 + + ]} + /> + + + ); +}; + +export default BasicResultErrorDemo; diff --git a/packages/dms-kit/src/components/BasicResult/demo/statuses.tsx b/packages/dms-kit/src/components/BasicResult/demo/statuses.tsx new file mode 100644 index 000000000..d1b1798a3 --- /dev/null +++ b/packages/dms-kit/src/components/BasicResult/demo/statuses.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { BasicResult, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; + +const BasicResultStatusesDemo = () => { + return ( + + + + + + + + + + + + + + + + + + ); +}; + +export default BasicResultStatusesDemo; diff --git a/packages/dms-kit/src/components/BasicResult/demo/withActions.tsx b/packages/dms-kit/src/components/BasicResult/demo/withActions.tsx new file mode 100644 index 000000000..619247e9d --- /dev/null +++ b/packages/dms-kit/src/components/BasicResult/demo/withActions.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { BasicResult, BasicButton, ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; + +const BasicResultWithActionsDemo = () => { + const handlePrimaryAction = () => { + console.log('主要操作被点击'); + }; + + const handleSecondaryAction = () => { + console.log('次要操作被点击'); + }; + + const handleBackAction = () => { + console.log('返回操作被点击'); + }; + + return ( + + + + 查看详情 + , + + 继续提交 + + ]} + /> + + + 重新提交 + , + + 保存草稿 + , + + 返回修改 + + ]} + /> + + + 确认信息 + , + + 修改信息 + + ]} + /> + + + 继续操作 + , + + 取消操作 + + ]} + /> + + + ); +}; + +export default BasicResultWithActionsDemo; diff --git a/packages/shared/lib/components/BasicResult/index.ts b/packages/dms-kit/src/components/BasicResult/index.ts similarity index 100% rename from packages/shared/lib/components/BasicResult/index.ts rename to packages/dms-kit/src/components/BasicResult/index.ts diff --git a/packages/shared/lib/components/BasicResult/style.ts b/packages/dms-kit/src/components/BasicResult/style.ts similarity index 100% rename from packages/shared/lib/components/BasicResult/style.ts rename to packages/dms-kit/src/components/BasicResult/style.ts diff --git a/packages/shared/lib/components/BasicSegmented/BasicSegmented.test.tsx b/packages/dms-kit/src/components/BasicSegmented/BasicSegmented.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicSegmented/BasicSegmented.test.tsx rename to packages/dms-kit/src/components/BasicSegmented/BasicSegmented.test.tsx diff --git a/packages/shared/lib/components/BasicSegmented/BasicSegmented.tsx b/packages/dms-kit/src/components/BasicSegmented/BasicSegmented.tsx similarity index 100% rename from packages/shared/lib/components/BasicSegmented/BasicSegmented.tsx rename to packages/dms-kit/src/components/BasicSegmented/BasicSegmented.tsx diff --git a/packages/shared/lib/components/BasicSegmented/BasicSegmented.types.ts b/packages/dms-kit/src/components/BasicSegmented/BasicSegmented.types.ts similarity index 100% rename from packages/shared/lib/components/BasicSegmented/BasicSegmented.types.ts rename to packages/dms-kit/src/components/BasicSegmented/BasicSegmented.types.ts diff --git a/packages/dms-kit/src/components/BasicSegmented/README.md b/packages/dms-kit/src/components/BasicSegmented/README.md new file mode 100644 index 000000000..f62c305e1 --- /dev/null +++ b/packages/dms-kit/src/components/BasicSegmented/README.md @@ -0,0 +1,116 @@ +--- +group: + title: 通用 + order: 1 +--- + +# BasicSegmented 分段控制器 + +基于 Ant Design Segmented 组件封装的分段控制器组件,提供了统一的样式规范和主题系统集成。 + +## 何时使用 + +- 需要在一组互斥且相关的选项中进行选择时 +- 需要展示不同视图或模式切换时 +- 需要保持与设计系统一致的分段控制器组件时 +- 需要响应式的选项切换界面时 + +## 代码演示 + +### 基础用法 + + + +### 不同尺寸 + + + +### 图标分段控制器 + + + +### 禁用状态 + + + +### 自定义样式 + + + +### 响应式选项 + + + +## API + +### BasicSegmented + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| className | 自定义类名 | `string` | - | - | + +### 继承属性 + +BasicSegmented 组件继承了 Ant Design Segmented 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| options | 分段控制器选项 | `SegmentedOptions` | - | - | +| value | 当前选中的值 | `string \| number` | - | - | +| defaultValue | 默认选中的值 | `string \| number` | - | - | +| onChange | 选项变化时的回调 | `(value: string \| number) => void` | - | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| size | 分段控制器大小 | `'large' \| 'middle' \| 'small'` | `'middle'` | - | +| block | 是否撑满父容器 | `boolean` | `false` | - | +| className | 自定义类名 | `string` | - | - | +| style | 自定义样式 | `CSSProperties` | - | - | + +## 设计规范 + +### 尺寸规范 + +- **大尺寸 (large)**: 适合页面级的分段控制器 +- **默认尺寸 (middle)**: 适合组件内的分段控制器 +- **小尺寸 (small)**: 适合紧凑布局的分段控制器 + +### 样式特性 + +- 统一的圆角设计 +- 基于主题的色彩系统 +- 支持悬停、激活、禁用等状态样式 +- 响应式设计,支持不同屏幕尺寸 +- 自动应用统一的样式类名 `basic-segmented-wrapper` + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicSegmented = { + default: { + background: { default, hover, active, disabled }, + color: { default, hover, active, disabled }, + border: { color, style, width } + }, + selected: { + background: { default, hover, active }, + color: { default, hover, active } + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. 所有 Ant Design Segmented 的属性和事件都可以正常使用 +3. 组件会自动应用统一的样式类名 +4. 支持响应式设计,在不同屏幕尺寸下自动调整 +5. 可以通过 `className` 和 `style` 属性进行自定义样式调整 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Segmented 封装 +- 支持所有 Segmented 组件的属性和事件 +- 统一的样式规范和主题系统集成 +- 响应式设计支持 +- 自动样式类名应用 diff --git a/packages/shared/lib/components/BasicSegmented/__snapshots__/BasicSegmented.test.tsx.snap b/packages/dms-kit/src/components/BasicSegmented/__snapshots__/BasicSegmented.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicSegmented/__snapshots__/BasicSegmented.test.tsx.snap rename to packages/dms-kit/src/components/BasicSegmented/__snapshots__/BasicSegmented.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicSegmented/demo/basic.tsx b/packages/dms-kit/src/components/BasicSegmented/demo/basic.tsx new file mode 100644 index 000000000..5c573b9a4 --- /dev/null +++ b/packages/dms-kit/src/components/BasicSegmented/demo/basic.tsx @@ -0,0 +1,25 @@ +import React, { useState } from 'react'; +import { Space } from 'antd'; +import { ConfigProvider, BasicSegmented } from '@actiontech/dms-kit'; + +const BasicSegmentedBasicDemo: React.FC = () => { + const [value, setValue] = useState('List'); + + return ( + + + + +
+ 当前选择: {value} +
+
+
+ ); +}; + +export default BasicSegmentedBasicDemo; diff --git a/packages/dms-kit/src/components/BasicSegmented/demo/custom.tsx b/packages/dms-kit/src/components/BasicSegmented/demo/custom.tsx new file mode 100644 index 000000000..0822fdf4b --- /dev/null +++ b/packages/dms-kit/src/components/BasicSegmented/demo/custom.tsx @@ -0,0 +1,59 @@ +import React, { useState } from 'react'; +import { Space } from 'antd'; +import { ConfigProvider, BasicSegmented } from '@actiontech/dms-kit'; + +const BasicSegmentedCustomDemo: React.FC = () => { + const [value, setValue] = useState('light'); + + return ( + + +
+

撑满容器宽度

+ +
+ +
+

自定义样式

+ +
+ +
+

紧凑布局

+ +
+ +
+ 当前选择: {value} +
+
+
+ ); +}; + +export default BasicSegmentedCustomDemo; diff --git a/packages/dms-kit/src/components/BasicSegmented/demo/disabled.tsx b/packages/dms-kit/src/components/BasicSegmented/demo/disabled.tsx new file mode 100644 index 000000000..57c5dd0b4 --- /dev/null +++ b/packages/dms-kit/src/components/BasicSegmented/demo/disabled.tsx @@ -0,0 +1,53 @@ +import React, { useState } from 'react'; +import { Space, Switch } from 'antd'; +import { ConfigProvider, BasicSegmented } from '@actiontech/dms-kit'; + +const BasicSegmentedDisabledDemo: React.FC = () => { + const [disabled, setDisabled] = useState(false); + const [value, setValue] = useState('all'); + + return ( + + +
+ + + 分段控制器状态: {disabled ? '禁用' : '启用'} + +
+ + + +
+ 当前选择: {value} +
+ +
+

部分选项禁用

+ +
+
+
+ ); +}; + +export default BasicSegmentedDisabledDemo; diff --git a/packages/dms-kit/src/components/BasicSegmented/demo/dynamic.tsx b/packages/dms-kit/src/components/BasicSegmented/demo/dynamic.tsx new file mode 100644 index 000000000..e7b34109f --- /dev/null +++ b/packages/dms-kit/src/components/BasicSegmented/demo/dynamic.tsx @@ -0,0 +1,91 @@ +import React, { useState } from 'react'; +import { BasicSegmented, ConfigProvider } from '@actiontech/dms-kit'; +import { Button, Space, Input, Card } from 'antd'; +import { PlusOutlined, MinusOutlined } from '@ant-design/icons'; + +const DynamicSegmentedDemo = () => { + const [options, setOptions] = useState([ + { label: '选项 1', value: 'option1' }, + { label: '选项 2', value: 'option2' }, + { label: '选项 3', value: 'option3' } + ]); + const [value, setValue] = useState('option1'); + const [newOption, setNewOption] = useState(''); + + const addOption = () => { + if (newOption.trim()) { + const optionValue = `option${options.length + 1}`; + setOptions([...options, { label: newOption.trim(), value: optionValue }]); + setNewOption(''); + } + }; + + const removeOption = (index: number) => { + const newOptions = options.filter((_, i) => i !== index); + setOptions(newOptions); + if (value === options[index].value && newOptions.length > 0) { + setValue(newOptions[0].value); + } + }; + + return ( + + + +
+ + setNewOption(e.target.value)} + style={{ width: 200 }} + /> + + +
+ + setValue(v as string)} + block + /> + +
+
当前选项:
+ + {options.map((option, index) => ( +
+ {option.label} +
+ ))} +
+
+ +
+ 当前选择: {value} +
+
+
+
+ ); +}; + +export default DynamicSegmentedDemo; diff --git a/packages/dms-kit/src/components/BasicSegmented/demo/form.tsx b/packages/dms-kit/src/components/BasicSegmented/demo/form.tsx new file mode 100644 index 000000000..badd7ec57 --- /dev/null +++ b/packages/dms-kit/src/components/BasicSegmented/demo/form.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import { BasicSegmented, ConfigProvider } from '@actiontech/dms-kit'; +import { Form, Button, Card, Space, Input, Select } from 'antd'; + +const FormSegmentedDemo = () => { + const [form] = Form.useForm(); + + const viewOptions = [ + { + label: '列表视图', + value: 'list' + }, + { + label: '卡片视图', + value: 'card' + }, + { + label: '表格视图', + value: 'table' + } + ]; + + const onFinish = (values: any) => { + console.log('表单提交:', values); + alert(`表单数据: ${JSON.stringify(values, null, 2)}`); + }; + + const onReset = () => { + form.resetFields(); + }; + + return ( + + +
+ + + + + + + + + + setEditInputValue(e.target.value)} + onBlur={handleEditInputConfirm} + onPressEnter={handleEditInputConfirm} + /> + ); + } + return ( + handleClose(tag)} + onDoubleClick={() => { + setEditInputIndex(index); + setEditInputValue(tag.text); + }} + > + {tag.text} + + ); + })} + {inputVisible ? ( + setInputValue(e.target.value)} + onBlur={handleInputConfirm} + onPressEnter={handleInputConfirm} + /> + ) : ( + + 新标签 + + )} + + +
+ ); +}; + +export default BasicTagDynamicDemo; diff --git a/packages/dms-kit/src/components/BasicTag/demos/icon.tsx b/packages/dms-kit/src/components/BasicTag/demos/icon.tsx new file mode 100644 index 000000000..dd109edcf --- /dev/null +++ b/packages/dms-kit/src/components/BasicTag/demos/icon.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { BasicTag } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space } from 'antd'; +import { + CheckCircleOutlined, + ExclamationCircleOutlined, + ClockCircleOutlined, + UserOutlined, + TagOutlined +} from '@ant-design/icons'; + +const BasicTagIconDemo = () => { + return ( + +
+ + }> + 已完成 + + + }> + 有错误 + + + }> + 处理中 + + + }> + 用户标签 + + + }> + 分类标签 + + +
+
+ ); +}; + +export default BasicTagIconDemo; diff --git a/packages/dms-kit/src/components/BasicTag/demos/size.tsx b/packages/dms-kit/src/components/BasicTag/demos/size.tsx new file mode 100644 index 000000000..5416346ab --- /dev/null +++ b/packages/dms-kit/src/components/BasicTag/demos/size.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { BasicTag } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Typography } from 'antd'; + +const { Text } = Typography; + +const BasicTagSizeDemo = () => { + return ( + +
+ +
+ 小尺寸: + + + 小标签 + + + 小标签 + + +
+ +
+ 默认尺寸: + + 默认标签 + 默认标签 + +
+ +
+ 大尺寸: + + + 大标签 + + + 大标签 + + +
+
+
+
+ ); +}; + +export default BasicTagSizeDemo; diff --git a/packages/dms-kit/src/components/BasicTag/demos/status.tsx b/packages/dms-kit/src/components/BasicTag/demos/status.tsx new file mode 100644 index 000000000..bf5b4eec7 --- /dev/null +++ b/packages/dms-kit/src/components/BasicTag/demos/status.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { BasicTag } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Typography } from 'antd'; + +const { Title } = Typography; + +const BasicTagStatusDemo = () => { + const statusData = [ + { status: 'success', text: '成功', count: 12 }, + { status: 'processing', text: '处理中', count: 5 }, + { status: 'error', text: '失败', count: 2 }, + { status: 'default', text: '待处理', count: 8 } + ]; + + const getStatusColor = (status: string) => { + const colorMap: Record = { + success: 'green', + processing: 'blue', + error: 'red', + default: 'default' + }; + return colorMap[status] || 'default'; + }; + + return ( + +
+ 状态标签 + + {statusData.map((item) => ( + + {item.text} ({item.count}) + + ))} + +
+
+ ); +}; + +export default BasicTagStatusDemo; diff --git a/packages/shared/lib/components/BasicTag/index.ts b/packages/dms-kit/src/components/BasicTag/index.ts similarity index 100% rename from packages/shared/lib/components/BasicTag/index.ts rename to packages/dms-kit/src/components/BasicTag/index.ts diff --git a/packages/shared/lib/components/BasicTag/style.ts b/packages/dms-kit/src/components/BasicTag/style.ts similarity index 100% rename from packages/shared/lib/components/BasicTag/style.ts rename to packages/dms-kit/src/components/BasicTag/style.ts diff --git a/packages/shared/lib/components/BasicToolTip/BasicToolTip.test.tsx b/packages/dms-kit/src/components/BasicToolTip/BasicToolTip.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicToolTip/BasicToolTip.test.tsx rename to packages/dms-kit/src/components/BasicToolTip/BasicToolTip.test.tsx diff --git a/packages/shared/lib/components/BasicToolTip/BasicToolTip.tsx b/packages/dms-kit/src/components/BasicToolTip/BasicToolTip.tsx similarity index 100% rename from packages/shared/lib/components/BasicToolTip/BasicToolTip.tsx rename to packages/dms-kit/src/components/BasicToolTip/BasicToolTip.tsx diff --git a/packages/shared/lib/components/BasicToolTip/BasicToolTip.types.ts b/packages/dms-kit/src/components/BasicToolTip/BasicToolTip.types.ts similarity index 100% rename from packages/shared/lib/components/BasicToolTip/BasicToolTip.types.ts rename to packages/dms-kit/src/components/BasicToolTip/BasicToolTip.types.ts diff --git a/packages/dms-kit/src/components/BasicToolTip/README.md b/packages/dms-kit/src/components/BasicToolTip/README.md new file mode 100644 index 000000000..c8dece51b --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/README.md @@ -0,0 +1,169 @@ +--- +group: + title: 通用 + order: 1 +--- + +# BasicToolTip 文字提示组件 + +## 组件介绍 + +BasicToolTip 是一个基于 Ant Design Tooltip 组件的封装,提供了统一的样式主题和增强的功能特性。该组件主要用于在鼠标悬停时显示额外的提示信息,支持前缀图标、后缀图标、自定义宽度等特性,适用于帮助说明、操作提示、信息补充等场景。 + +## 何时使用 + +- **帮助说明**:为复杂操作或功能提供说明文字 +- **操作提示**:显示按钮、链接等交互元素的用途 +- **信息补充**:在空间有限时展示完整信息 +- **状态说明**:解释系统状态、错误信息等 +- **引导提示**:为新用户提供操作指导 + +## 代码演示 + +### 基础用法 + +最简单的文字提示,鼠标悬停时显示提示内容。 + + + +### 带图标的提示 + +在提示内容前添加图标,增强视觉效果和信息传达。 + + + +### 不同位置 + +支持 12 个不同方向的提示显示位置。 + + + +### 自定义宽度 + +通过 `titleWidth` 属性控制提示框的宽度,适应不同长度的内容。 + + + +### 复杂内容提示 + +支持在提示中显示复杂的内容,如列表、表格等。 + + + +### 条件显示提示 + +根据条件决定是否显示提示,或者显示不同的提示内容。 + + + +### 表单字段提示 + +在表单字段旁添加提示,帮助用户理解字段的含义和要求。 + + + +### 操作按钮提示 + +为操作按钮添加提示,说明按钮的功能和注意事项。 + + + +## API 文档 + +### BasicTooltipProps + +继承自 Ant Design 的 `TooltipProps`,并扩展了以下属性: + +| 属性 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| className | 额外的 CSS 类名 | string | - | - | +| title | 提示内容 | ReactNode \| (() => ReactNode) | - | - | +| titleWidth | 提示框宽度 | number | - | - | +| prefixIcon | 前缀图标 | boolean \| ReactNode | false | - | +| suffixIcon | 后缀图标 | boolean \| ReactNode | false | - | +| placement | 提示框出现位置 | TooltipPlacement | 'top' | - | +| trigger | 触发行为 | 'hover' \| 'focus' \| 'click' | 'hover' | - | +| mouseEnterDelay | 鼠标移入后延时多少才显示 | number | 0.5 | - | +| mouseLeaveDelay | 鼠标移出后延时多少才隐藏 | number | 0.1 | - | +| overlayClassName | 卡片类名 | string | - | - | +| overlayStyle | 卡片样式 | CSSProperties | - | - | +| children | 触发元素 | ReactNode | - | - | + +### TooltipPlacement + +提示框出现位置: + +```tsx +type TooltipPlacement = + | 'top' | 'topLeft' | 'topRight' + | 'bottom' | 'bottomLeft' | 'bottomRight' + | 'left' | 'leftTop' | 'leftBottom' + | 'right' | 'rightTop' | 'rightBottom'; +``` + +## 设计规范 + +### 主题配置 + +BasicToolTip 组件支持通过主题系统进行样式定制: + +```tsx +// 主题配置示例 +const theme = { + sharedTheme: { + uiToken: { + colorBgBase: '#ffffff', // 背景色 + colorBorderSecondary: '#d9d9d9', // 边框颜色 + colorTextBase: '#000000' // 文字颜色 + } + } +}; +``` + +### 样式规范 + +- **背景色**: 使用主题的 `colorBgBase` 颜色 +- **边框**: 1px 实线边框,使用主题的 `colorBorderSecondary` 颜色 +- **圆角**: 6px 圆角,提供现代化的视觉效果 +- **内边距**: 8px 12px,确保内容有足够的呼吸空间 +- **最大宽度**: 默认最大宽度 640px,可通过 `titleWidth` 自定义 + +### 图标规范 + +- **默认图标**: 当 `prefixIcon={true}` 时,显示 `InfoCircleOutlined` 图标 +- **图标颜色**: 默认使用警告色 `#faad14` +- **图标大小**: 14px,与文字大小保持一致 +- **图标间距**: 图标与文字之间使用适当的间距 + +### 交互规范 + +- **触发方式**: 默认鼠标悬停触发,支持点击和焦点触发 +- **显示延迟**: 鼠标移入后 0.5 秒显示,移出后 0.1 秒隐藏 +- **箭头指示**: 默认不显示箭头,保持简洁的视觉效果 +- **自动定位**: 根据位置自动调整显示方向,避免超出视口 + +### 内容规范 + +- **文字长度**: 建议提示内容控制在 100 字符以内 +- **内容结构**: 可以使用标题、列表、标签等元素组织内容 +- **信息层次**: 重要信息优先显示,次要信息适当弱化 +- **操作指导**: 提供具体的操作步骤和注意事项 + +## 注意事项 + +1. **内容长度**: 避免提示内容过长,影响用户体验 +2. **触发时机**: 合理设置触发方式,避免干扰用户操作 +3. **位置选择**: 选择合适的显示位置,避免遮挡重要内容 +4. **图标使用**: 合理使用图标,增强信息的可读性 +5. **响应式设计**: 在不同屏幕尺寸下保持良好的显示效果 +6. **无障碍支持**: 确保提示内容对屏幕阅读器友好 + +## 更新日志 + +### 1.0.0 +- 初始版本发布 +- 基于 Ant Design Tooltip 组件封装 +- 支持前缀图标和后缀图标 +- 支持自定义提示框宽度 +- 集成主题系统 +- 提供统一的样式规范 diff --git a/packages/shared/lib/components/BasicToolTip/__snapshots__/BasicToolTip.test.tsx.snap b/packages/dms-kit/src/components/BasicToolTip/__snapshots__/BasicToolTip.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicToolTip/__snapshots__/BasicToolTip.test.tsx.snap rename to packages/dms-kit/src/components/BasicToolTip/__snapshots__/BasicToolTip.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicToolTip/demos/action.tsx b/packages/dms-kit/src/components/BasicToolTip/demos/action.tsx new file mode 100644 index 000000000..e60ba007d --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/demos/action.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { BasicToolTip } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Button, message } from 'antd'; +import { + DeleteOutlined, + EditOutlined, + DownloadOutlined, + UploadOutlined, + ReloadOutlined, + ExclamationCircleOutlined +} from '@ant-design/icons'; + +const BasicToolTipActionDemo = () => { + const handleAction = (action: string) => { + message.success(`执行了 ${action} 操作`); + }; + + return ( + +
+ + + + + + } + > + + + + + + + + } + > + + + + + + + +
+
+ ); +}; + +export default BasicToolTipActionDemo; diff --git a/packages/dms-kit/src/components/BasicToolTip/demos/basic.tsx b/packages/dms-kit/src/components/BasicToolTip/demos/basic.tsx new file mode 100644 index 000000000..2cc2e3254 --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/demos/basic.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { BasicToolTip } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Button } from 'antd'; + +const BasicToolTipDemo = () => { + return ( + +
+ + + +
+
+ ); +}; + +export default BasicToolTipDemo; diff --git a/packages/dms-kit/src/components/BasicToolTip/demos/complex.tsx b/packages/dms-kit/src/components/BasicToolTip/demos/complex.tsx new file mode 100644 index 000000000..3aa72f7c9 --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/demos/complex.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { BasicToolTip } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Button, List, Tag, Space } from 'antd'; +import { InfoCircleOutlined } from '@ant-design/icons'; + +const BasicToolTipComplexDemo = () => { + const userInfo = ( +
+

用户信息

+ ( + + + {item.label}: + + {item.value} + + )} + /> +
+ ); + + const systemStatus = ( +
+

系统状态

+ +
+ CPU: 正常 + 内存: 正常 +
+
+ 网络: 正常 + 磁盘: 正常 +
+
+
+ ); + + return ( + +
+ + } + > + + + + } + > + + + +
+
+ ); +}; + +export default BasicToolTipComplexDemo; diff --git a/packages/dms-kit/src/components/BasicToolTip/demos/conditional.tsx b/packages/dms-kit/src/components/BasicToolTip/demos/conditional.tsx new file mode 100644 index 000000000..ed819ada3 --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/demos/conditional.tsx @@ -0,0 +1,95 @@ +import React, { useState } from 'react'; +import { BasicToolTip } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Button, Input, Typography } from 'antd'; +import { + InfoCircleOutlined, + ExclamationCircleOutlined +} from '@ant-design/icons'; + +const { Text } = Typography; + +const BasicToolTipConditionalDemo = () => { + const [inputValue, setInputValue] = useState(''); + const [showTooltip, setShowTooltip] = useState(false); + + const getTooltipContent = (value: string) => { + if (!value) { + return '请输入内容'; + } + if (value.length < 3) { + return '内容太短,至少需要3个字符'; + } + if (value.length > 20) { + return '内容太长,最多允许20个字符'; + } + return '内容长度符合要求'; + }; + + const getTooltipIcon = (value: string) => { + if (!value) { + return ; + } + if (value.length < 3 || value.length > 20) { + return ; + } + return ; + }; + + const getTooltipColor = (value: string) => { + if (!value) { + return 'default'; + } + if (value.length < 3 || value.length > 20) { + return 'error'; + } + return 'success'; + }; + + return ( + +
+ +
+ 输入验证提示: + + setInputValue(e.target.value)} + style={{ width: 200 }} + /> + +
+ +
+ 当前状态: + + + {inputValue || '未输入'} + + +
+
+
+
+ ); +}; + +export default BasicToolTipConditionalDemo; diff --git a/packages/dms-kit/src/components/BasicToolTip/demos/form.tsx b/packages/dms-kit/src/components/BasicToolTip/demos/form.tsx new file mode 100644 index 000000000..bf1dda932 --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/demos/form.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { BasicToolTip } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Form, Input, Button, Space } from 'antd'; +import { QuestionCircleOutlined, InfoCircleOutlined } from '@ant-design/icons'; + +const BasicToolTipFormDemo = () => { + const [form] = Form.useForm(); + + const onFinish = (values: any) => { + console.log('表单数据:', values); + }; + + return ( + +
+ + + 用户名 + } + > + + + + } + name="username" + rules={[{ required: true, message: '请输入用户名' }]} + > + + + + + 邮箱地址 + } + > + + + + } + name="email" + rules={[ + { required: true, message: '请输入邮箱地址' }, + { type: 'email', message: '请输入正确的邮箱地址' } + ]} + > + + + + + 密码 + } + > + + + + } + name="password" + rules={[ + { required: true, message: '请输入密码' }, + { min: 8, message: '密码长度至少8位' } + ]} + > + + + + + + + +
+
+ ); +}; + +export default BasicToolTipFormDemo; diff --git a/packages/dms-kit/src/components/BasicToolTip/demos/icon.tsx b/packages/dms-kit/src/components/BasicToolTip/demos/icon.tsx new file mode 100644 index 000000000..1fbf6fbbc --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/demos/icon.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { BasicToolTip } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Button } from 'antd'; +import { + InfoCircleOutlined, + ExclamationCircleOutlined, + QuestionCircleOutlined, + CheckCircleOutlined +} from '@ant-design/icons'; + +const BasicToolTipIconDemo = () => { + return ( + +
+ + + + + + } + > + + + + } + > + + + + } + > + + + +
+
+ ); +}; + +export default BasicToolTipIconDemo; diff --git a/packages/dms-kit/src/components/BasicToolTip/demos/index.ts b/packages/dms-kit/src/components/BasicToolTip/demos/index.ts new file mode 100644 index 000000000..0ab72b5c6 --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/demos/index.ts @@ -0,0 +1,8 @@ +export { default as BasicToolTipDemo } from './basic'; +export { default as BasicToolTipIconDemo } from './icon'; +export { default as BasicToolTipPlacementDemo } from './placement'; +export { default as BasicToolTipWidthDemo } from './width'; +export { default as BasicToolTipComplexDemo } from './complex'; +export { default as BasicToolTipConditionalDemo } from './conditional'; +export { default as BasicToolTipFormDemo } from './form'; +export { default as BasicToolTipActionDemo } from './action'; diff --git a/packages/dms-kit/src/components/BasicToolTip/demos/placement.tsx b/packages/dms-kit/src/components/BasicToolTip/demos/placement.tsx new file mode 100644 index 000000000..8e7a24f25 --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/demos/placement.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { BasicToolTip } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Button } from 'antd'; + +const BasicToolTipPlacementDemo = () => { + const placements = [ + 'top', + 'topLeft', + 'topRight', + 'bottom', + 'bottomLeft', + 'bottomRight', + 'left', + 'leftTop', + 'leftBottom', + 'right', + 'rightTop', + 'rightBottom' + ]; + + return ( + +
+
+

提示位置演示

+

点击按钮查看不同位置的提示效果

+
+ +
+ {placements.map((placement) => ( + + + + ))} +
+
+
+ ); +}; + +export default BasicToolTipPlacementDemo; diff --git a/packages/dms-kit/src/components/BasicToolTip/demos/width.tsx b/packages/dms-kit/src/components/BasicToolTip/demos/width.tsx new file mode 100644 index 000000000..0ea5e4336 --- /dev/null +++ b/packages/dms-kit/src/components/BasicToolTip/demos/width.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { BasicToolTip } from '@actiontech/dms-kit'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Button, Typography } from 'antd'; + +const { Text } = Typography; + +const BasicToolTipWidthDemo = () => { + const shortText = '短文本提示'; + const longText = + '这是一个非常长的提示文本,包含了大量的信息内容,需要足够的宽度来显示,避免文字换行影响阅读体验。'; + const veryLongText = + '这是一个超级长的提示文本,包含了极其详细的信息内容,涵盖了多个方面的说明,需要更大的宽度来确保所有内容都能完整显示,同时保持良好的可读性和视觉效果。'; + + return ( + +
+ +
+ 默认宽度: + + + +
+ +
+ 自定义宽度 300px: + + + +
+ +
+ 自定义宽度 500px: + + + +
+
+
+
+ ); +}; + +export default BasicToolTipWidthDemo; diff --git a/packages/shared/lib/components/BasicToolTip/index.ts b/packages/dms-kit/src/components/BasicToolTip/index.ts similarity index 100% rename from packages/shared/lib/components/BasicToolTip/index.ts rename to packages/dms-kit/src/components/BasicToolTip/index.ts diff --git a/packages/shared/lib/components/BasicToolTip/style.ts b/packages/dms-kit/src/components/BasicToolTip/style.ts similarity index 100% rename from packages/shared/lib/components/BasicToolTip/style.ts rename to packages/dms-kit/src/components/BasicToolTip/style.ts diff --git a/packages/shared/lib/components/BasicToolTip/utils/index.tsx b/packages/dms-kit/src/components/BasicToolTip/utils/index.tsx similarity index 100% rename from packages/shared/lib/components/BasicToolTip/utils/index.tsx rename to packages/dms-kit/src/components/BasicToolTip/utils/index.tsx diff --git a/packages/shared/lib/components/BasicTreeSelect/BasicTreeSelect.test.tsx b/packages/dms-kit/src/components/BasicTreeSelect/BasicTreeSelect.test.tsx similarity index 100% rename from packages/shared/lib/components/BasicTreeSelect/BasicTreeSelect.test.tsx rename to packages/dms-kit/src/components/BasicTreeSelect/BasicTreeSelect.test.tsx diff --git a/packages/shared/lib/components/BasicTreeSelect/BasicTreeSelect.tsx b/packages/dms-kit/src/components/BasicTreeSelect/BasicTreeSelect.tsx similarity index 100% rename from packages/shared/lib/components/BasicTreeSelect/BasicTreeSelect.tsx rename to packages/dms-kit/src/components/BasicTreeSelect/BasicTreeSelect.tsx diff --git a/packages/shared/lib/components/BasicTreeSelect/BasicTreeSelect.types.ts b/packages/dms-kit/src/components/BasicTreeSelect/BasicTreeSelect.types.ts similarity index 100% rename from packages/shared/lib/components/BasicTreeSelect/BasicTreeSelect.types.ts rename to packages/dms-kit/src/components/BasicTreeSelect/BasicTreeSelect.types.ts diff --git a/packages/dms-kit/src/components/BasicTreeSelect/README.md b/packages/dms-kit/src/components/BasicTreeSelect/README.md new file mode 100644 index 000000000..ee8e364d0 --- /dev/null +++ b/packages/dms-kit/src/components/BasicTreeSelect/README.md @@ -0,0 +1,128 @@ +--- +group: + title: 通用 + order: 1 +--- + +# BasicTreeSelect 基础树形选择器 + +基于 Ant Design TreeSelect 组件封装的基础树形选择器组件,提供了统一的样式规范和额外的功能特性。 + +## 何时使用 + +- 需要从树形结构中选择一个或多个节点时 +- 需要展示层级数据的选择器时 +- 需要保持与设计系统一致的树形选择器组件时 + +## 代码演示 + +### 基础用法 + + + +### 多选模式 + + + +### 搜索功能 + + + +### 自定义图标 + + + +### 加载状态 + + + +### 表单集成 + + + +## API + +### BasicTreeSelect + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| allowClear | 是否显示清除按钮 | `boolean` | `true` | - | +| loading | 是否显示加载状态 | `boolean` | `false` | - | +| placeholder | 选择框默认文字 | `string` | `'请选择'` | - | + +### 继承属性 + +BasicTreeSelect 组件继承了 Ant Design TreeSelect 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| value | 指定当前选中的条目 | `string \| string[] \| number \| number[]` | - | - | +| defaultValue | 指定默认选中的条目 | `string \| string[] \| number \| number[]` | - | - | +| treeData | 树形数据 | `TreeNode[]` | `[]` | - | +| multiple | 是否支持多选 | `boolean` | `false` | - | +| treeCheckable | 显示 checkbox | `boolean` | `false` | - | +| showSearch | 是否支持搜索 | `boolean` | `false` | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| size | 选择框大小 | `'large' \| 'middle' \| 'small'` | `'middle'` | - | +| className | 选择框类名 | `string` | - | - | +| style | 选择框样式 | `CSSProperties` | - | - | +| onChange | 选择变化时触发 | `(value, labelList, extra) => void` | - | - | +| onSearch | 搜索时触发 | `(value: string) => void` | - | - | + +## 设计规范 + +### 尺寸规范 + +- **大尺寸 (lg)**: `height: 40px` +- **默认尺寸**: `height: 32px` +- **小尺寸 (sm)**: `height: 24px` + +### 样式特性 + +- 统一的圆角设计 (`border-radius: 4px`) +- 基于主题的色彩系统 +- 自定义的展开/收起图标 +- 支持悬停、聚焦、禁用等状态样式 +- 统一的清除按钮样式 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicTreeSelect = { + default: { + borderColor, + backgroundColor, + color + }, + hover: { + borderColor + }, + focus: { + borderColor, + boxShadow + }, + disabled: { + backgroundColor, + color, + borderColor + } +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. 组件会自动应用统一的样式类名 `basic-tree-select-wrapper` +3. 所有 Ant Design TreeSelect 的属性和事件都可以正常使用 +4. 组件集成了国际化支持,placeholder 会自动使用当前语言 +5. 当 `loading` 为 true 时,会显示加载状态的空状态组件 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design TreeSelect 封装 +- 支持所有 TreeSelect 组件的属性和事件 +- 新增自定义展开/收起图标 +- 集成 BasicEmpty 组件支持加载状态 +- 统一的样式规范和主题系统集成 diff --git a/packages/shared/lib/components/BasicTreeSelect/__snapshots__/BasicTreeSelect.test.tsx.snap b/packages/dms-kit/src/components/BasicTreeSelect/__snapshots__/BasicTreeSelect.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/BasicTreeSelect/__snapshots__/BasicTreeSelect.test.tsx.snap rename to packages/dms-kit/src/components/BasicTreeSelect/__snapshots__/BasicTreeSelect.test.tsx.snap diff --git a/packages/dms-kit/src/components/BasicTreeSelect/demo/basic.tsx b/packages/dms-kit/src/components/BasicTreeSelect/demo/basic.tsx new file mode 100644 index 000000000..833c06a8e --- /dev/null +++ b/packages/dms-kit/src/components/BasicTreeSelect/demo/basic.tsx @@ -0,0 +1,67 @@ +import React, { useState } from 'react'; +import { BasicTreeSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { TreeSelectProps } from 'antd'; + +const BasicTreeSelectDemo = () => { + const [value, setValue] = useState(); + + const treeData: TreeSelectProps['treeData'] = [ + { + title: '前端开发', + value: 'frontend', + children: [ + { + title: 'React', + value: 'react' + }, + { + title: 'Vue', + value: 'vue' + }, + { + title: 'Angular', + value: 'angular' + } + ] + }, + { + title: '后端开发', + value: 'backend', + children: [ + { + title: 'Node.js', + value: 'nodejs' + }, + { + title: 'Java', + value: 'java' + }, + { + title: 'Python', + value: 'python' + } + ] + } + ]; + + const onChange = (newValue: string) => { + setValue(newValue); + }; + + return ( + + + + ); +}; + +export default BasicTreeSelectDemo; + diff --git a/packages/dms-kit/src/components/BasicTreeSelect/demo/customIcon.tsx b/packages/dms-kit/src/components/BasicTreeSelect/demo/customIcon.tsx new file mode 100644 index 000000000..c24aabc0a --- /dev/null +++ b/packages/dms-kit/src/components/BasicTreeSelect/demo/customIcon.tsx @@ -0,0 +1,71 @@ +import React, { useState } from 'react'; +import { BasicTreeSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { TreeSelectProps } from 'antd'; +import { FolderOutlined, FileOutlined } from '@ant-design/icons'; + +const CustomIconTreeSelectDemo = () => { + const [value, setValue] = useState(); + + const treeData: TreeSelectProps['treeData'] = [ + { + title: '项目结构', + value: 'project', + icon: , + children: [ + { + title: '源代码', + value: 'src', + icon: , + children: [ + { + title: '组件', + value: 'components', + icon: + }, + { + title: '页面', + value: 'pages', + icon: + }, + { + title: '工具函数', + value: 'utils', + icon: + } + ] + }, + { + title: '配置文件', + value: 'config', + icon: + }, + { + title: '文档', + value: 'docs', + icon: + } + ] + } + ]; + + const onChange = (newValue: string) => { + setValue(newValue); + }; + + return ( + + + + ); +}; + +export default CustomIconTreeSelectDemo; diff --git a/packages/dms-kit/src/components/BasicTreeSelect/demo/form.tsx b/packages/dms-kit/src/components/BasicTreeSelect/demo/form.tsx new file mode 100644 index 000000000..14d0b3940 --- /dev/null +++ b/packages/dms-kit/src/components/BasicTreeSelect/demo/form.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import { BasicTreeSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { Form, Button, Card, Space } from 'antd'; +import { TreeSelectProps } from 'antd'; + +const FormTreeSelectDemo = () => { + const [form] = Form.useForm(); + + const treeData: TreeSelectProps['treeData'] = [ + { + title: '部门管理', + value: 'dept', + children: [ + { + title: '技术部', + value: 'tech', + children: [ + { + title: '前端组', + value: 'frontend' + }, + { + title: '后端组', + value: 'backend' + }, + { + title: '测试组', + value: 'qa' + } + ] + }, + { + title: '产品部', + value: 'product', + children: [ + { + title: '产品设计', + value: 'design' + }, + { + title: '产品运营', + value: 'operation' + } + ] + } + ] + } + ]; + + const onFinish = (values: any) => { + console.log('表单提交:', values); + alert(`选择的部门: ${values.department}`); + }; + + const onReset = () => { + form.resetFields(); + }; + + return ( + + +
+ + + + + + + + + + + +
+
+ ); +}; + +export default FormTreeSelectDemo; + diff --git a/packages/dms-kit/src/components/BasicTreeSelect/demo/loading.tsx b/packages/dms-kit/src/components/BasicTreeSelect/demo/loading.tsx new file mode 100644 index 000000000..992e9ec10 --- /dev/null +++ b/packages/dms-kit/src/components/BasicTreeSelect/demo/loading.tsx @@ -0,0 +1,60 @@ +import React, { useState } from 'react'; +import { BasicTreeSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { Button, Space } from 'antd'; + +const LoadingTreeSelectDemo = () => { + const [loading, setLoading] = useState(false); + const [treeData, setTreeData] = useState([]); + + const loadData = () => { + setLoading(true); + // 模拟异步加载数据 + setTimeout(() => { + setTreeData([ + { + title: '加载完成的数据', + value: 'loaded', + children: [ + { + title: '子项 1', + value: 'child1' + }, + { + title: '子项 2', + value: 'child2' + } + ] + } + ]); + setLoading(false); + }, 2000); + }; + + const clearData = () => { + setTreeData([]); + }; + + return ( + + + + + + + + + + + ); +}; + +export default LoadingTreeSelectDemo; + diff --git a/packages/dms-kit/src/components/BasicTreeSelect/demo/multiple.tsx b/packages/dms-kit/src/components/BasicTreeSelect/demo/multiple.tsx new file mode 100644 index 000000000..68b10f3c4 --- /dev/null +++ b/packages/dms-kit/src/components/BasicTreeSelect/demo/multiple.tsx @@ -0,0 +1,63 @@ +import React, { useState } from 'react'; +import { BasicTreeSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { TreeSelectProps } from 'antd'; + +const MultipleTreeSelectDemo = () => { + const [value, setValue] = useState(); + + const treeData: TreeSelectProps['treeData'] = [ + { + title: '数据库', + value: 'database', + children: [ + { + title: 'MySQL', + value: 'mysql' + }, + { + title: 'PostgreSQL', + value: 'postgresql' + }, + { + title: 'MongoDB', + value: 'mongodb' + } + ] + }, + { + title: '缓存', + value: 'cache', + children: [ + { + title: 'Redis', + value: 'redis' + }, + { + title: 'Memcached', + value: 'memcached' + } + ] + } + ]; + + const onChange = (newValue: string) => { + setValue(newValue); + }; + + return ( + + + + ); +}; + +export default MultipleTreeSelectDemo; diff --git a/packages/dms-kit/src/components/BasicTreeSelect/demo/search.tsx b/packages/dms-kit/src/components/BasicTreeSelect/demo/search.tsx new file mode 100644 index 000000000..40fd8a1a5 --- /dev/null +++ b/packages/dms-kit/src/components/BasicTreeSelect/demo/search.tsx @@ -0,0 +1,91 @@ +import React, { useState } from 'react'; +import { BasicTreeSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { TreeSelectProps } from 'antd'; + +const SearchTreeSelectDemo = () => { + const [value, setValue] = useState(); + + const treeData: TreeSelectProps['treeData'] = [ + { + title: '开发工具', + value: 'devtools', + children: [ + { + title: '代码编辑器', + value: 'editor', + children: [ + { + title: 'VS Code', + value: 'vscode' + }, + { + title: 'WebStorm', + value: 'webstorm' + }, + { + title: 'Sublime Text', + value: 'sublime' + } + ] + }, + { + title: '版本控制', + value: 'vcs', + children: [ + { + title: 'Git', + value: 'git' + }, + { + title: 'SVN', + value: 'svn' + } + ] + } + ] + }, + { + title: '部署工具', + value: 'deploy', + children: [ + { + title: 'Docker', + value: 'docker' + }, + { + title: 'Kubernetes', + value: 'kubernetes' + } + ] + } + ]; + + const onChange = (newValue: string) => { + setValue(newValue); + }; + + return ( + + { + return ( + (treeNode?.title + ?.toString() + ?.toLowerCase() + ?.indexOf(inputValue.toLowerCase()) ?? 0) > 0 + ); + }} + /> + + ); +}; + +export default SearchTreeSelectDemo; diff --git a/packages/shared/lib/components/BasicTreeSelect/index.ts b/packages/dms-kit/src/components/BasicTreeSelect/index.ts similarity index 100% rename from packages/shared/lib/components/BasicTreeSelect/index.ts rename to packages/dms-kit/src/components/BasicTreeSelect/index.ts diff --git a/packages/shared/lib/components/BasicTreeSelect/style.ts b/packages/dms-kit/src/components/BasicTreeSelect/style.ts similarity index 85% rename from packages/shared/lib/components/BasicTreeSelect/style.ts rename to packages/dms-kit/src/components/BasicTreeSelect/style.ts index 8c5b7a8fa..08bd9c1f8 100644 --- a/packages/shared/lib/components/BasicTreeSelect/style.ts +++ b/packages/dms-kit/src/components/BasicTreeSelect/style.ts @@ -1,7 +1,17 @@ -import { styled } from '@mui/material/styles'; -import { TreeSelect } from 'antd'; - -export const BasicTreeSelectStyleWrapper = styled(TreeSelect)` +import { StyledComponent } from '@emotion/styled'; +import { styled, Theme } from '@mui/material/styles'; +import { MUIStyledCommonProps } from '@mui/system/createStyled'; +import { TreeSelect, TreeSelectProps } from 'antd'; + +export const BasicTreeSelectStyleWrapper: StyledComponent< + TreeSelectProps & { + children?: React.ReactNode; + } & { + ref?: React.Ref | undefined; + } & MUIStyledCommonProps, + {}, + {} +> = styled(TreeSelect)` &.ant-select.basic-tree-select-wrapper { .ant-select-clear { width: 14px; diff --git a/packages/dms-kit/src/components/BasicTypographyEllipsis/BasicTypographyEllipsis.tsx b/packages/dms-kit/src/components/BasicTypographyEllipsis/BasicTypographyEllipsis.tsx new file mode 100644 index 000000000..4b09799e1 --- /dev/null +++ b/packages/dms-kit/src/components/BasicTypographyEllipsis/BasicTypographyEllipsis.tsx @@ -0,0 +1,48 @@ +import { useMemo } from 'react'; +import { TypographyStyleWrapper } from './style'; +import classNames from 'classnames'; +import { EllipsisConfig } from 'antd/es/typography/Base'; +import { basicTooltipCommonProps } from '../BasicToolTip/utils'; +import { BasicTypographyEllipsisProps } from './BasicTypographyEllipsis.types'; + +// 外层需要一个 max-width 容器 "例如:.ellipsis-column-width" +const BasicTypographyEllipsis: React.FC = ({ + textCont, + tooltipLimitLength = 500, + tooltipsMaxWidth = 640, + copyable = true, + tooltips = true, + className +}) => { + const mergeTooltips = useMemo(() => { + if (tooltips === true) { + return { + placement: 'topLeft', + ...basicTooltipCommonProps( + textCont.length > tooltipLimitLength ? ( + {`${textCont.slice(0, tooltipLimitLength)}...`} + ) : ( + {textCont} + ), + tooltipsMaxWidth + ) + }; + } + return tooltips; + }, [textCont, tooltipLimitLength, tooltips, tooltipsMaxWidth]); + + return ( + + {textCont} + + ); +}; + +export default BasicTypographyEllipsis; diff --git a/packages/dms-kit/src/components/BasicTypographyEllipsis/BasicTypographyEllipsis.types.ts b/packages/dms-kit/src/components/BasicTypographyEllipsis/BasicTypographyEllipsis.types.ts new file mode 100644 index 000000000..256fbab8a --- /dev/null +++ b/packages/dms-kit/src/components/BasicTypographyEllipsis/BasicTypographyEllipsis.types.ts @@ -0,0 +1,10 @@ +import { EllipsisConfig } from 'antd/es/typography/Base'; + +export interface BasicTypographyEllipsisProps { + textCont: string; + tooltipLimitLength?: number; + tooltipsMaxWidth?: number; + copyable?: boolean; + tooltips?: EllipsisConfig['tooltip']; + className?: string; +} diff --git a/packages/shared/lib/components/BasicButton/README.md b/packages/dms-kit/src/components/BasicTypographyEllipsis/README.md similarity index 59% rename from packages/shared/lib/components/BasicButton/README.md rename to packages/dms-kit/src/components/BasicTypographyEllipsis/README.md index bb338d94c..d1877a691 100644 --- a/packages/shared/lib/components/BasicButton/README.md +++ b/packages/dms-kit/src/components/BasicTypographyEllipsis/README.md @@ -7,4 +7,6 @@ category: lib ``` TODO + +dms-kit 版本移除 linkData 功能 ``` diff --git a/packages/dms-kit/src/components/BasicTypographyEllipsis/index.ts b/packages/dms-kit/src/components/BasicTypographyEllipsis/index.ts new file mode 100644 index 000000000..66f84e4fa --- /dev/null +++ b/packages/dms-kit/src/components/BasicTypographyEllipsis/index.ts @@ -0,0 +1,2 @@ +export { default as BasicTypographyEllipsis } from './BasicTypographyEllipsis'; +export type * from './BasicTypographyEllipsis.types'; diff --git a/packages/dms-kit/src/components/BasicTypographyEllipsis/style.ts b/packages/dms-kit/src/components/BasicTypographyEllipsis/style.ts new file mode 100644 index 000000000..a7e3bbb3d --- /dev/null +++ b/packages/dms-kit/src/components/BasicTypographyEllipsis/style.ts @@ -0,0 +1,40 @@ +import { styled } from '@mui/material/styles'; +import { Typography } from 'antd'; + +export const TypographyStyleWrapper = styled(Typography.Paragraph)` + max-width: 100%; + + &.ant-typography.ant-typography-ellipsis { + margin-bottom: 0; + display: flex; + align-items: center; + + span:not(.anticon-copy):first-of-type { + display: inline-flex; + overflow: hidden; + word-break: keep-all; + } + + .ant-typography-copy { + height: 18px; + width: 18px; + opacity: 0; + border-radius: 4px; + margin-inline-start: 10px; + + &:hover { + opacity: 1; + color: ${({ theme }) => theme.sharedTheme.uiToken.colorPrimary}; + background-color: ${({ theme }) => + theme.sharedTheme.basic.colorPrimaryBgHover} !important; + } + } + + &:hover { + .ant-typography-copy { + opacity: 1; + color: ${({ theme }) => theme.sharedTheme.uiToken.colorPrimary}; + } + } + } +`; diff --git a/packages/shared/lib/components/ConfigItem/ConfigItem.tsx b/packages/dms-kit/src/components/ConfigItem/ConfigItem.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/ConfigItem.tsx rename to packages/dms-kit/src/components/ConfigItem/ConfigItem.tsx diff --git a/packages/shared/lib/components/ConfigItem/ConfigItem.types.ts b/packages/dms-kit/src/components/ConfigItem/ConfigItem.types.ts similarity index 100% rename from packages/shared/lib/components/ConfigItem/ConfigItem.types.ts rename to packages/dms-kit/src/components/ConfigItem/ConfigItem.types.ts diff --git a/packages/dms-kit/src/components/ConfigItem/README.md b/packages/dms-kit/src/components/ConfigItem/README.md new file mode 100644 index 000000000..7bc48cc32 --- /dev/null +++ b/packages/dms-kit/src/components/ConfigItem/README.md @@ -0,0 +1,141 @@ +--- +group: + title: 业务组件 + order: 3 +--- + +# ConfigItem 配置项 + +用于展示和编辑系统配置项的组件,提供统一的配置项展示样式和交互模式。 + +## 何时使用 + +- 需要展示系统配置信息时 +- 需要提供配置项的就地编辑功能时 +- 需要统一配置项的展示样式时 +- 构建系统设置页面时 + +## 代码演示 + + +### 可编辑文本输入 + + + +### 可编辑数字输入 + + + +### 图片上传 + + + + +### 自定义内容 + + + +## API + +### ConfigItem + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| label | 配置项标签 | `string \| ReactNode` | - | - | +| inputNode | 编辑状态下显示的输入组件 | `ReactNode` | - | - | +| descNode | 只读状态下显示的描述内容 | `string \| ReactNode` | - | - | +| fieldVisible | 是否显示编辑字段 | `boolean` | `false` | - | +| showField | 显示编辑字段的回调 | `() => void` | - | - | +| hideField | 隐藏编辑字段的回调 | `() => void` | - | - | +| needEditButton | 是否需要编辑按钮 | `boolean` | `true` | - | + +### EditInput + +配置项的可编辑文本输入组件,支持验证和键盘快捷键。 + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| fieldValue | 字段当前值 | `string` | - | - | +| hideField | 隐藏编辑字段的回调 | `() => void` | - | - | +| validator | 输入验证函数 | `(value: string) => boolean` | - | - | +| onSubmit | 提交回调 | `(value: string) => void` | - | - | +| submitLoading | 是否正在提交 | `boolean` | `false` | - | + +**键盘快捷键**: +- `Enter` - 提交输入 +- `Esc` - 取消编辑 + +### EditInputNumber + +配置项的可编辑数字输入组件,支持验证和键盘快捷键。 + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| fieldValue | 字段当前值 | `number` | - | - | +| hideField | 隐藏编辑字段的回调 | `() => void` | - | - | +| validator | 输入验证函数 | `(value: number) => boolean` | - | - | +| onSubmit | 提交回调 | `(value: number) => void` | - | - | +| submitLoading | 是否正在提交 | `boolean` | `false` | - | + +**键盘快捷键**: +- `Enter` - 提交输入 +- `Esc` - 取消编辑 + +### ImageUploader + +配置项的图片上传组件,支持拖拽上传和预览。 + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| submitLoading | 是否正在提交 | `boolean` | - | - | +| onSubmit | 上传提交回调 | `UploadProps['customRequest']` | - | - | +| url | 图片地址 | `string` | - | - | +| disabled | 是否禁用上传 | `boolean` | `false` | - | + +## 设计规范 + +### 布局结构 + +- **左侧标签区域**: 占比 45%,显示配置项名称 +- **右侧内容区域**: 占比 55%,显示配置值或编辑组件 +- **编辑按钮**: 悬停时显示,点击进入编辑模式 + +### 交互规范 + +- **悬停效果**: 鼠标悬停时显示编辑按钮 +- **编辑模式**: 点击编辑按钮进入编辑状态 +- **自动隐藏**: 点击空白区域自动隐藏编辑组件 +- **键盘操作**: 支持 Enter 提交,Esc 取消 + +### 样式特性 + +- 统一的行高和间距 (`min-height: 48px`) +- 左右布局,标签左对齐,内容右对齐 +- 编辑按钮淡入淡出效果 +- 支持主题色彩系统 + +### 状态样式 + +- **默认状态**: 显示描述内容 +- **悬停状态**: 显示编辑按钮 +- **编辑状态**: 显示输入组件 +- **加载状态**: 显示加载动画 +- **错误状态**: 输入验证失败时的错误样式 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `fieldVisible` 控制是否显示编辑字段,需要配合 `showField` 和 `hideField` 使用 +3. `EditInput` 和 `EditInputNumber` 组件内置了点击空白区域自动隐藏的逻辑 +4. 图片上传组件需要自定义 `customRequest` 来处理实际的上传逻辑 +5. 输入组件支持自定义验证器,验证失败时会显示错误样式 +6. 建议为复杂的配置项提供合适的描述文本来提升用户体验 + +## 更新日志 + +- **1.0.0**: 初始版本 + - 基础配置项展示功能 + - 支持文本、数字、图片三种编辑类型 + - 内置编辑按钮和交互逻辑 + - 支持自定义验证和键盘快捷键 + - 完整的主题样式系统集成 \ No newline at end of file diff --git a/packages/shared/lib/components/ConfigItem/__tests__/ConfigItem.test.tsx b/packages/dms-kit/src/components/ConfigItem/__tests__/ConfigItem.test.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/ConfigItem.test.tsx rename to packages/dms-kit/src/components/ConfigItem/__tests__/ConfigItem.test.tsx diff --git a/packages/shared/lib/components/ConfigItem/__tests__/EditInput.test.tsx b/packages/dms-kit/src/components/ConfigItem/__tests__/EditInput.test.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/EditInput.test.tsx rename to packages/dms-kit/src/components/ConfigItem/__tests__/EditInput.test.tsx diff --git a/packages/shared/lib/components/ConfigItem/__tests__/EditInputNumber.test.tsx b/packages/dms-kit/src/components/ConfigItem/__tests__/EditInputNumber.test.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/EditInputNumber.test.tsx rename to packages/dms-kit/src/components/ConfigItem/__tests__/EditInputNumber.test.tsx diff --git a/packages/shared/lib/components/ConfigItem/__tests__/ImageUploader.test.tsx b/packages/dms-kit/src/components/ConfigItem/__tests__/ImageUploader.test.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/ImageUploader.test.tsx rename to packages/dms-kit/src/components/ConfigItem/__tests__/ImageUploader.test.tsx diff --git a/packages/shared/lib/components/ConfigItem/__tests__/LabelContent.test.tsx b/packages/dms-kit/src/components/ConfigItem/__tests__/LabelContent.test.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/LabelContent.test.tsx rename to packages/dms-kit/src/components/ConfigItem/__tests__/LabelContent.test.tsx diff --git a/packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/ConfigItem.test.tsx.snap b/packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/ConfigItem.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/ConfigItem.test.tsx.snap rename to packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/ConfigItem.test.tsx.snap diff --git a/packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/EditInput.test.tsx.snap b/packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/EditInput.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/EditInput.test.tsx.snap rename to packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/EditInput.test.tsx.snap diff --git a/packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/EditInputNumber.test.tsx.snap b/packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/EditInputNumber.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/EditInputNumber.test.tsx.snap rename to packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/EditInputNumber.test.tsx.snap diff --git a/packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/ImageUploader.test.tsx.snap b/packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/ImageUploader.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/ImageUploader.test.tsx.snap rename to packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/ImageUploader.test.tsx.snap diff --git a/packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/LabelContent.test.tsx.snap b/packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/LabelContent.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/ConfigItem/__tests__/__snapshots__/LabelContent.test.tsx.snap rename to packages/dms-kit/src/components/ConfigItem/__tests__/__snapshots__/LabelContent.test.tsx.snap diff --git a/packages/shared/lib/components/ConfigItem/components/EditInput.tsx b/packages/dms-kit/src/components/ConfigItem/components/EditInput.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/components/EditInput.tsx rename to packages/dms-kit/src/components/ConfigItem/components/EditInput.tsx diff --git a/packages/shared/lib/components/ConfigItem/components/EditInputNumber.tsx b/packages/dms-kit/src/components/ConfigItem/components/EditInputNumber.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/components/EditInputNumber.tsx rename to packages/dms-kit/src/components/ConfigItem/components/EditInputNumber.tsx diff --git a/packages/shared/lib/components/ConfigItem/components/ImageUploader.tsx b/packages/dms-kit/src/components/ConfigItem/components/ImageUploader.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/components/ImageUploader.tsx rename to packages/dms-kit/src/components/ConfigItem/components/ImageUploader.tsx diff --git a/packages/shared/lib/components/ConfigItem/components/LabelContent.tsx b/packages/dms-kit/src/components/ConfigItem/components/LabelContent.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/components/LabelContent.tsx rename to packages/dms-kit/src/components/ConfigItem/components/LabelContent.tsx diff --git a/packages/dms-kit/src/components/ConfigItem/demo/custom.tsx b/packages/dms-kit/src/components/ConfigItem/demo/custom.tsx new file mode 100644 index 000000000..f201e9fa8 --- /dev/null +++ b/packages/dms-kit/src/components/ConfigItem/demo/custom.tsx @@ -0,0 +1,71 @@ +import React from 'react'; +import { + ConfigItem, + ConfigProvider, + BasicSelect, + BasicSwitch +} from '@actiontech/dms-kit'; +import { useBoolean } from 'ahooks'; +import { Tag, Space } from 'antd'; + +const ConfigItemCustomDemo = () => { + const [fieldVisible1, { setTrue: showField1, setFalse: hideField1 }] = + useBoolean(false); + const [fieldVisible2, { setTrue: showField2, setFalse: hideField2 }] = + useBoolean(false); + + return ( + +
+ {/* 自定义标签内容 */} + + 数据库类型 + 必填 + + } + descNode="MySQL 8.0" + inputNode={ + + } + fieldVisible={fieldVisible1} + showField={showField1} + hideField={hideField1} + /> + + {/* 开关类型的配置项 */} + + + 推荐启用以提高安全性 + + } + fieldVisible={fieldVisible2} + showField={showField2} + hideField={hideField2} + /> +
+
+ ); +}; + +export default ConfigItemCustomDemo; diff --git a/packages/dms-kit/src/components/ConfigItem/demo/editInput.tsx b/packages/dms-kit/src/components/ConfigItem/demo/editInput.tsx new file mode 100644 index 000000000..1f6b310a6 --- /dev/null +++ b/packages/dms-kit/src/components/ConfigItem/demo/editInput.tsx @@ -0,0 +1,55 @@ +import React, { useState } from 'react'; +import { ConfigItem, ConfigProvider, EditInput } from '@actiontech/dms-kit'; +import { useBoolean } from 'ahooks'; +import { message } from 'antd'; + +const ConfigItemEditInputDemo = () => { + const [fieldVisible, { setTrue: showField, setFalse: hideField }] = + useBoolean(false); + const [ + submitLoading, + { setTrue: setSubmitLoading, setFalse: setSubmitLoadingFalse } + ] = useBoolean(false); + const [currentValue, setCurrentValue] = useState('example@company.com'); + + const handleSubmit = (value: string) => { + setSubmitLoading(); + // 模拟提交 + setTimeout(() => { + setCurrentValue(value); + setSubmitLoadingFalse(); + hideField(); + message.success('保存成功'); + }, 1000); + }; + + const validator = (value: string) => { + // 简单的邮箱验证 + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value); + }; + + return ( + +
+ + } + fieldVisible={fieldVisible} + showField={showField} + hideField={hideField} + /> +
+
+ ); +}; + +export default ConfigItemEditInputDemo; diff --git a/packages/dms-kit/src/components/ConfigItem/demo/editInputNumber.tsx b/packages/dms-kit/src/components/ConfigItem/demo/editInputNumber.tsx new file mode 100644 index 000000000..f8f0a34ed --- /dev/null +++ b/packages/dms-kit/src/components/ConfigItem/demo/editInputNumber.tsx @@ -0,0 +1,59 @@ +import React, { useState } from 'react'; +import { + ConfigItem, + ConfigProvider, + EditInputNumber +} from '@actiontech/dms-kit'; +import { useBoolean } from 'ahooks'; +import { message } from 'antd'; + +const ConfigItemEditInputNumberDemo = () => { + const [fieldVisible, { setTrue: showField, setFalse: hideField }] = + useBoolean(false); + const [ + submitLoading, + { setTrue: setSubmitLoading, setFalse: setSubmitLoadingFalse } + ] = useBoolean(false); + const [currentValue, setCurrentValue] = useState(30); + + const handleSubmit = (value: number) => { + setSubmitLoading(); + // 模拟提交 + setTimeout(() => { + setCurrentValue(value); + setSubmitLoadingFalse(); + hideField(); + message.success('保存成功'); + }, 1000); + }; + + const validator = (value: number) => { + // 验证范围在 10-300 之间 + return value >= 10 && value <= 300; + }; + + return ( + +
+ + } + fieldVisible={fieldVisible} + showField={showField} + hideField={hideField} + /> +
+
+ ); +}; + +export default ConfigItemEditInputNumberDemo; diff --git a/packages/dms-kit/src/components/ConfigItem/demo/imageUploader.tsx b/packages/dms-kit/src/components/ConfigItem/demo/imageUploader.tsx new file mode 100644 index 000000000..88dca5ef9 --- /dev/null +++ b/packages/dms-kit/src/components/ConfigItem/demo/imageUploader.tsx @@ -0,0 +1,54 @@ +import React, { useState } from 'react'; +import { ConfigItem, ConfigProvider, ImageUploader } from '@actiontech/dms-kit'; +import { useBoolean } from 'ahooks'; +import { message } from 'antd'; +import type { UploadProps } from 'antd'; + +const ConfigItemImageUploaderDemo = () => { + const [fieldVisible, { setTrue: showField, setFalse: hideField }] = + useBoolean(false); + const [ + submitLoading, + { setTrue: setSubmitLoading, setFalse: setSubmitLoadingFalse } + ] = useBoolean(false); + const [logoUrl, setLogoUrl] = useState( + 'https://via.placeholder.com/100x50/4583FF/ffffff?text=LOGO' + ); + + const handleUpload: UploadProps['customRequest'] = (options) => { + setSubmitLoading(); + // 模拟上传 + setTimeout(() => { + // 这里通常会调用真实的上传API + const newUrl = URL.createObjectURL(options.file as File); + setLogoUrl(newUrl); + setSubmitLoadingFalse(); + hideField(); + message.success('上传成功'); + options.onSuccess?.(newUrl); + }, 2000); + }; + + return ( + +
+ + } + fieldVisible={fieldVisible} + showField={showField} + hideField={hideField} + /> +
+
+ ); +}; + +export default ConfigItemImageUploaderDemo; diff --git a/packages/shared/lib/components/ConfigItem/hooks/useHideConfigInputNode.tsx b/packages/dms-kit/src/components/ConfigItem/hooks/useHideConfigInputNode.tsx similarity index 100% rename from packages/shared/lib/components/ConfigItem/hooks/useHideConfigInputNode.tsx rename to packages/dms-kit/src/components/ConfigItem/hooks/useHideConfigInputNode.tsx diff --git a/packages/shared/lib/components/ConfigItem/index.ts b/packages/dms-kit/src/components/ConfigItem/index.ts similarity index 100% rename from packages/shared/lib/components/ConfigItem/index.ts rename to packages/dms-kit/src/components/ConfigItem/index.ts diff --git a/packages/shared/lib/components/ConfigItem/style.ts b/packages/dms-kit/src/components/ConfigItem/style.ts similarity index 100% rename from packages/shared/lib/components/ConfigItem/style.ts rename to packages/dms-kit/src/components/ConfigItem/style.ts diff --git a/packages/shared/lib/components/CopyIcon/CopyIcon.test.tsx b/packages/dms-kit/src/components/CopyIcon/CopyIcon.test.tsx similarity index 100% rename from packages/shared/lib/components/CopyIcon/CopyIcon.test.tsx rename to packages/dms-kit/src/components/CopyIcon/CopyIcon.test.tsx diff --git a/packages/shared/lib/components/CopyIcon/CopyIcon.tsx b/packages/dms-kit/src/components/CopyIcon/CopyIcon.tsx similarity index 100% rename from packages/shared/lib/components/CopyIcon/CopyIcon.tsx rename to packages/dms-kit/src/components/CopyIcon/CopyIcon.tsx diff --git a/packages/shared/lib/components/CopyIcon/CopyIcon.types.ts b/packages/dms-kit/src/components/CopyIcon/CopyIcon.types.ts similarity index 100% rename from packages/shared/lib/components/CopyIcon/CopyIcon.types.ts rename to packages/dms-kit/src/components/CopyIcon/CopyIcon.types.ts diff --git a/packages/dms-kit/src/components/CopyIcon/README.md b/packages/dms-kit/src/components/CopyIcon/README.md new file mode 100644 index 000000000..5a218e5d1 --- /dev/null +++ b/packages/dms-kit/src/components/CopyIcon/README.md @@ -0,0 +1,93 @@ +--- +group: + title: 工具 + order: 1 +--- + +# CopyIcon 复制图标 + +一个功能完整的复制图标组件,支持文本复制、自定义复制逻辑、复制状态反馈等功能。 + +## 何时使用 + +- 需要复制文本内容到剪贴板时 +- 需要显示复制操作的状态反馈时 +- 需要自定义复制逻辑时 +- 在代码块、配置项等场景中提供复制功能时 + +## 代码演示 + +### 基础用法 + + + +### 自定义复制逻辑 + + + +### 禁用提示 + + + +### 自定义提示内容 + + + +### 复制完成回调 + + + +## API + +### CopyIcon + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| text | 要复制的文本内容 | `string` | - | - | +| children | 自定义图标内容 | `ReactNode` | - | - | +| tooltips | 是否显示提示,或自定义提示内容。当为 true 时显示默认提示,当为其他值时在复制成功时显示该内容 | `boolean \| ReactNode` | `true` | - | +| onCopyComplete | 复制完成后的回调函数 | `(event?: React.MouseEvent) => void` | - | - | +| className | 自定义类名 | `string` | - | - | +| onCustomCopy | 自定义复制逻辑 | `(event?: React.MouseEvent) => void` | - | - | + +## 设计规范 + +### 图标状态 + +- **默认状态**: 显示复制图标 (`CopyOutlined`),主题色 +- **复制成功状态**: 显示成功图标 (`CheckOutlined`),成功色 +- **悬停效果**: 鼠标悬停时显示提示信息 + +### 样式特性 + +- 图标大小: `14px` +- 颜色过渡: `transition: color 0.3s` +- 左边距: `margin-left: 4px` +- 鼠标指针: `cursor: pointer` + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.uiToken = { + colorPrimary: '#1890ff', // 默认图标颜色 + colorSuccess: '#52c41a' // 复制成功图标颜色 +} +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. 如果不提供 `text` 属性,会尝试从 `children` 中获取文本内容 +3. 复制成功后,图标会在 3 秒后自动恢复到默认状态 +4. 使用 `onCustomCopy` 时,组件不会自动执行默认的复制逻辑 +5. 组件会自动处理复制失败的情况,使用降级方案 +6. `tooltips` 属性支持布尔值和 ReactNode,当为 true 时显示默认提示,当为其他值时在复制成功时显示该内容 + +## 更新日志 + +- **1.0.0**: 初始版本,支持基础文本复制功能 +- 支持自定义复制逻辑和复制完成回调 +- 支持提示信息的自定义配置 +- 集成主题系统,支持主题切换 diff --git a/packages/shared/lib/components/CopyIcon/__snapshots__/CopyIcon.test.tsx.snap b/packages/dms-kit/src/components/CopyIcon/__snapshots__/CopyIcon.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CopyIcon/__snapshots__/CopyIcon.test.tsx.snap rename to packages/dms-kit/src/components/CopyIcon/__snapshots__/CopyIcon.test.tsx.snap diff --git a/packages/dms-kit/src/components/CopyIcon/demo/basic.tsx b/packages/dms-kit/src/components/CopyIcon/demo/basic.tsx new file mode 100644 index 000000000..bd356ea8a --- /dev/null +++ b/packages/dms-kit/src/components/CopyIcon/demo/basic.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { CopyIcon } from '@actiontech/dms-kit'; +import { Space, Typography } from 'antd'; + +const { Text } = Typography; + +const BasicDemo: React.FC = () => { + return ( + + +
+ 复制文本内容: + +
+ +
+ 复制配置信息: + +
+ +
+ 复制 SQL 语句: + +
+
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/CopyIcon/demo/customCopy.tsx b/packages/dms-kit/src/components/CopyIcon/demo/customCopy.tsx new file mode 100644 index 000000000..b8b16dd9e --- /dev/null +++ b/packages/dms-kit/src/components/CopyIcon/demo/customCopy.tsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { message } from 'antd'; +import { CopyIcon } from '@actiontech/dms-kit'; +import { Space, Typography } from 'antd'; + +const { Text } = Typography; + +const CustomCopyDemo: React.FC = () => { + const handleCustomCopy = async () => { + try { + // 模拟自定义复制逻辑 + await navigator.clipboard.writeText('自定义复制的内容'); + message.success('使用自定义逻辑复制成功!'); + } catch (error) { + message.error('自定义复制失败,使用降级方案'); + // 降级到默认复制逻辑 + return false; + } + }; + + const handleApiKeyCopy = async () => { + try { + await navigator.clipboard.writeText('sk-1234567890abcdef'); + message.success('API 密钥已复制到剪贴板'); + } catch (error) { + message.error('复制失败'); + } + }; + + return ( + + +
+ 自定义复制逻辑: + +
+ +
+ API 密钥复制: + +
+ +
+ 带验证的复制: + { + const confirmed = window.confirm('确认复制此敏感信息?'); + if (confirmed) { + await navigator.clipboard.writeText('需要验证的敏感信息'); + message.success('敏感信息已复制'); + } + }} + /> +
+
+
+ ); +}; + +export default CustomCopyDemo; diff --git a/packages/dms-kit/src/components/CopyIcon/demo/customTooltip.tsx b/packages/dms-kit/src/components/CopyIcon/demo/customTooltip.tsx new file mode 100644 index 000000000..ced006d37 --- /dev/null +++ b/packages/dms-kit/src/components/CopyIcon/demo/customTooltip.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Tag } from 'antd'; +import { CopyIcon } from '@actiontech/dms-kit'; +import { Space, Typography } from 'antd'; + +const { Text } = Typography; + +const CustomTooltipDemo: React.FC = () => { + return ( + + +
+ 自定义提示文本: + +
+ +
+ 带标签的提示: + + 提示 + 点击复制此内容 +
+ } + /> + + +
+ 状态相关提示: + +
+ +
+ 多语言提示: + +
+
+
+ ); +}; + +export default CustomTooltipDemo; diff --git a/packages/dms-kit/src/components/CopyIcon/demo/noTooltip.tsx b/packages/dms-kit/src/components/CopyIcon/demo/noTooltip.tsx new file mode 100644 index 000000000..f75655243 --- /dev/null +++ b/packages/dms-kit/src/components/CopyIcon/demo/noTooltip.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { CopyIcon } from '@actiontech/dms-kit'; +import { Space, Typography, Card } from 'antd'; + +const { Text } = Typography; + +const NoTooltipDemo: React.FC = () => { + return ( + + +
+ 禁用提示(tooltips=false): + +
+ +
+ 在卡片中使用(无提示): + +
+ 配置项: + +
+
+
+ +
+ 在表格行中使用(无提示): +
+ 用户 ID: + +
+
+
+
+ ); +}; + +export default NoTooltipDemo; diff --git a/packages/dms-kit/src/components/CopyIcon/demo/onCopyComplete.tsx b/packages/dms-kit/src/components/CopyIcon/demo/onCopyComplete.tsx new file mode 100644 index 000000000..f83440dcb --- /dev/null +++ b/packages/dms-kit/src/components/CopyIcon/demo/onCopyComplete.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { message, notification } from 'antd'; +import { CopyIcon } from '@actiontech/dms-kit'; +import { Space, Typography, Card } from 'antd'; + +const { Text } = Typography; + +const OnCopyCompleteDemo: React.FC = () => { + const handleCopyComplete = (event?: React.MouseEvent) => { + message.success('复制完成!'); + console.log('复制完成事件:', event); + }; + + const handleApiKeyCopyComplete = () => { + notification.success({ + message: 'API 密钥已复制', + description: '密钥已安全复制到剪贴板,请注意保护信息安全', + duration: 4 + }); + }; + + const handleConfigCopyComplete = () => { + message.info('配置信息已复制,可在配置文件中使用'); + }; + + const handleLogCopyComplete = () => { + message.warning('日志内容已复制,请及时处理相关问题'); + }; + + return ( + + +
+ 基础复制完成回调: + +
+ +
+ API 密钥复制完成: + +
+ +
+ 配置信息复制完成: + +
+ +
+ 日志内容复制完成: + +
+ + + 复制统计: +
+ 点击上方任意复制按钮,查看控制台输出和消息提示 +
+
+
+
+ ); +}; + +export default OnCopyCompleteDemo; diff --git a/packages/shared/lib/components/CopyIcon/index.tsx b/packages/dms-kit/src/components/CopyIcon/index.tsx similarity index 100% rename from packages/shared/lib/components/CopyIcon/index.tsx rename to packages/dms-kit/src/components/CopyIcon/index.tsx diff --git a/packages/shared/lib/components/CopyIcon/style.ts b/packages/dms-kit/src/components/CopyIcon/style.ts similarity index 100% rename from packages/shared/lib/components/CopyIcon/style.ts rename to packages/dms-kit/src/components/CopyIcon/style.ts diff --git a/packages/shared/lib/components/CronInput/CronInput.data.ts b/packages/dms-kit/src/components/CronInput/CronInput.data.ts similarity index 100% rename from packages/shared/lib/components/CronInput/CronInput.data.ts rename to packages/dms-kit/src/components/CronInput/CronInput.data.ts diff --git a/packages/shared/lib/components/CronInput/CronInput.enum.ts b/packages/dms-kit/src/components/CronInput/CronInput.enum.ts similarity index 100% rename from packages/shared/lib/components/CronInput/CronInput.enum.ts rename to packages/dms-kit/src/components/CronInput/CronInput.enum.ts diff --git a/packages/shared/lib/components/CronInput/CronInput.test.tsx b/packages/dms-kit/src/components/CronInput/CronInput.test.tsx similarity index 100% rename from packages/shared/lib/components/CronInput/CronInput.test.tsx rename to packages/dms-kit/src/components/CronInput/CronInput.test.tsx diff --git a/packages/shared/lib/components/CronInput/CronInput.tsx b/packages/dms-kit/src/components/CronInput/CronInput.tsx similarity index 100% rename from packages/shared/lib/components/CronInput/CronInput.tsx rename to packages/dms-kit/src/components/CronInput/CronInput.tsx diff --git a/packages/shared/lib/components/CronInput/CronInput.types.ts b/packages/dms-kit/src/components/CronInput/CronInput.types.ts similarity index 100% rename from packages/shared/lib/components/CronInput/CronInput.types.ts rename to packages/dms-kit/src/components/CronInput/CronInput.types.ts diff --git a/packages/dms-kit/src/components/CronInput/README.md b/packages/dms-kit/src/components/CronInput/README.md new file mode 100644 index 000000000..451f629e8 --- /dev/null +++ b/packages/dms-kit/src/components/CronInput/README.md @@ -0,0 +1,120 @@ +--- +group: + title: 工具 + order: 2 +--- + +# CronInput Cron 表达式输入 + +一个功能完整的 Cron 表达式输入组件,支持手动输入和可视化选择两种模式,适用于定时任务配置场景。 + +## 何时使用 + +- 需要配置定时任务的 Cron 表达式时 +- 需要提供用户友好的 Cron 表达式输入界面时 +- 在任务调度、定时备份等场景中使用时 +- 需要验证 Cron 表达式格式时 + +## 代码演示 + +### 基础用法 + + + +### 手动输入模式 + + + +### 禁用状态 + + + +### 错误处理 + + + +### 自定义频率 + + + +## API + +### CronInput + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| value | Cron 表达式的值 | `string` | - | - | +| onChange | 值变化时的回调函数 | `(value: string) => void` | - | - | +| defaultFrequency | 默认频率类型 | `CronFrequencyEnum` | - | - | +| inputMode | 输入模式 | `CronInputModeEnum` | `'Manual'` | - | +| onModeChange | 模式变化时的回调函数 | `(mode: CronInputModeEnum) => void` | - | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| onError | 错误信息回调函数 | `(errorMessage: string) => void` | - | - | + +### CronFrequencyEnum + +```typescript +enum CronFrequencyEnum { + Daily = 'daily', // 每日 + Weekly = 'weekly' // 每周 +} +``` + +### CronInputModeEnum + +```typescript +enum CronInputModeEnum { + Manual = 'Manual', // 手动输入 + Select = 'Select' // 可视化选择 +} +``` + +### CronWeekDayEnum + +```typescript +enum CronWeekDayEnum { + Sun = 0, // 周日 + Mon = 1, // 周一 + Tue = 2, // 周二 + Wed = 3, // 周三 + Thu = 4, // 周四 + Fri = 5, // 周五 + Sat = 6 // 周六 +} +``` + +## 设计规范 + +### 输入框样式 + +- 支持 Ant Design Input 组件的所有样式属性 +- 占位符文本: "请输入 Cron 表达式" +- 支持错误状态显示 + +### 弹出层样式 + +- 使用 Popover 组件实现 +- 内边距: `0` +- 箭头: `false` +- 触发方式: `click` + +### 布局结构 + +- 输入框 + 日历图标 +- 点击日历图标打开选择面板 +- 支持手动输入和可视化选择两种模式 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. 可视化选择模式会覆盖手动输入的内容 +3. 错误信息通过 `onError` 回调返回,需要自行处理显示 +4. 组件会自动验证 Cron 表达式的格式 +5. 支持键盘快捷键操作(ESC 关闭选择面板) + +## 更新日志 + +- **1.0.0**: 初始版本,支持基础 Cron 表达式输入 +- 支持手动输入和可视化选择两种模式 +- 集成错误验证和回调机制 +- 支持自定义频率类型和输入模式 diff --git a/packages/shared/lib/components/CronInput/__snapshots__/CronInput.test.tsx.snap b/packages/dms-kit/src/components/CronInput/__snapshots__/CronInput.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CronInput/__snapshots__/CronInput.test.tsx.snap rename to packages/dms-kit/src/components/CronInput/__snapshots__/CronInput.test.tsx.snap diff --git a/packages/dms-kit/src/components/CronInput/demo/basic.tsx b/packages/dms-kit/src/components/CronInput/demo/basic.tsx new file mode 100644 index 000000000..e78883dfd --- /dev/null +++ b/packages/dms-kit/src/components/CronInput/demo/basic.tsx @@ -0,0 +1,65 @@ +import React, { useState } from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Typography, Card } from 'antd'; +import { CronInput } from '@actiontech/dms-kit'; + +const { Text, Title } = Typography; + +const BasicDemo: React.FC = () => { + const [cronValue, setCronValue] = useState('0 0 * * *'); + const [error, setError] = useState(''); + + const handleChange = (value: string) => { + setCronValue(value); + console.log('Cron 表达式变化:', value); + }; + + const handleError = (errorMessage: string) => { + setError(errorMessage); + console.log('Cron 表达式错误:', errorMessage); + }; + + return ( + + + + 基础 Cron 表达式输入 + +
+ 当前值: + {cronValue} +
+ + + + {error && 错误信息:{error}} +
+
+ + + 预设 Cron 表达式 + +
+ 每日执行: + 0 0 * * * +
+
+ 每小时执行: + 0 * * * * +
+
+ 每周一执行: + 0 0 * * 1 +
+
+
+
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/CronInput/demo/customFrequency.tsx b/packages/dms-kit/src/components/CronInput/demo/customFrequency.tsx new file mode 100644 index 000000000..859c35625 --- /dev/null +++ b/packages/dms-kit/src/components/CronInput/demo/customFrequency.tsx @@ -0,0 +1,136 @@ +import React, { useState } from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Typography, Card, Radio, Alert } from 'antd'; +import { CronInput } from '@actiontech/dms-kit'; +import { CronFrequencyEnum } from '@actiontech/dms-kit'; + +const { Text, Title } = Typography; + +const CustomFrequencyDemo: React.FC = () => { + const [cronValue, setCronValue] = useState('0 0 * * *'); + const [frequency, setFrequency] = useState( + CronFrequencyEnum.Daily + ); + + const handleChange = (value: string) => { + setCronValue(value); + console.log('Cron 表达式变化:', value); + }; + + const handleFrequencyChange = (e: any) => { + const newFrequency = e.target.value; + setFrequency(newFrequency); + console.log('频率类型变化:', newFrequency); + + // 根据频率类型设置默认的 Cron 表达式 + if (newFrequency === CronFrequencyEnum.Daily) { + setCronValue('0 0 * * *'); + } else if (newFrequency === CronFrequencyEnum.Weekly) { + setCronValue('0 0 * * 1'); + } + }; + + return ( + + + + + + 频率类型选择 + +
+ 选择频率类型: + + + 每日 + + + 每周 + + +
+ +
+ 当前频率: + + {frequency === CronFrequencyEnum.Daily + ? '每日执行' + : '每周执行'} + +
+ +
+ 当前值: + {cronValue} +
+ + +
+
+ + + 频率类型说明 + +
+ 每日频率 (Daily): +
+
+ • 适用于需要每天执行的任务 +
+
+ • 默认表达式:0 0 * * *(每天午夜执行) +
+
+ • 可配置具体的小时和分钟 +
+ +
+ 每周频率 (Weekly): +
+
+ • 适用于需要每周执行的任务 +
+
+ • 默认表达式:0 0 * * 1(每周一午夜执行) +
+
+ • 可配置具体的星期几、小时和分钟 +
+
+
+ + + 使用建议 + +
+ 频率选择建议: +
+
+ • 数据备份任务:建议使用每日频率 +
+
+ • 系统维护任务:建议使用每周频率 +
+
+ • 报表生成任务:根据业务需求选择频率 +
+
+ • 数据清理任务:建议使用每日频率 +
+
+
+
+
+ ); +}; + +export default CustomFrequencyDemo; diff --git a/packages/dms-kit/src/components/CronInput/demo/disabled.tsx b/packages/dms-kit/src/components/CronInput/demo/disabled.tsx new file mode 100644 index 000000000..22a10649f --- /dev/null +++ b/packages/dms-kit/src/components/CronInput/demo/disabled.tsx @@ -0,0 +1,95 @@ +import React, { useState } from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Typography, Card, Switch, Alert } from 'antd'; +import { CronInput } from '@actiontech/dms-kit'; + +const { Text, Title } = Typography; + +const DisabledDemo: React.FC = () => { + const [cronValue, setCronValue] = useState('0 0 * * *'); + const [isDisabled, setIsDisabled] = useState(true); + + const handleChange = (value: string) => { + setCronValue(value); + console.log('Cron 表达式变化:', value); + }; + + return ( + + + + + + 禁用状态控制 + +
+ 禁用状态: + +
+ +
+ 当前值: + {cronValue} +
+ + + + + 状态:{isDisabled ? '已禁用(不可编辑)' : '已启用(可编辑)'} + +
+
+ + + 禁用状态使用场景 + +
+ 适用场景: +
+
+ • 只读展示:在详情页面展示定时任务配置 +
+
+ • 权限控制:用户没有修改权限时禁用编辑 +
+
+ • 状态锁定:任务正在执行时锁定配置 +
+
+ • 审核流程:等待审核的配置不允许修改 +
+
+
+ + + 禁用状态样式 + +
+ 禁用状态的 CronInput 组件: +
+ + + 禁用状态下,输入框呈现灰色,无法点击和编辑 + +
+
+
+
+ ); +}; + +export default DisabledDemo; diff --git a/packages/dms-kit/src/components/CronInput/demo/errorHandling.tsx b/packages/dms-kit/src/components/CronInput/demo/errorHandling.tsx new file mode 100644 index 000000000..8e5339785 --- /dev/null +++ b/packages/dms-kit/src/components/CronInput/demo/errorHandling.tsx @@ -0,0 +1,118 @@ +import React, { useState } from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Typography, Card, Alert, List } from 'antd'; +import { CronInput } from '@actiontech/dms-kit'; + +const { Text, Title } = Typography; + +const ErrorHandlingDemo: React.FC = () => { + const [cronValue, setCronValue] = useState('0 0 * * *'); + const [errorHistory, setErrorHistory] = useState([]); + + const handleChange = (value: string) => { + setCronValue(value); + console.log('Cron 表达式变化:', value); + }; + + const handleError = (errorMessage: string) => { + console.log('Cron 表达式错误:', errorMessage); + setErrorHistory((prev) => [errorMessage, ...prev.slice(0, 4)]); + }; + + const invalidCronExamples = [ + 'invalid cron expression', + '99 99 * * *', + '0 0 32 2 *', + '* * * * * *', + '0 0 * * 8' + ]; + + return ( + + + + + + 错误信息收集 + +
+ 当前值: + {cronValue} +
+ + + + {errorHistory.length > 0 && ( +
+ 错误历史: + ( + + + {index + 1}. {error} + + + )} + /> +
+ )} +
+
+ + + 常见错误示例 + + 尝试输入以下无效的 Cron 表达式来测试错误处理: + ( + + {example} + - 复制到上方输入框测试 + + )} + /> + + + + + 错误处理最佳实践 + +
+ 错误处理建议: +
+
+ • 在 onError 回调中收集错误信息 +
+
+ • 向用户显示友好的错误提示 +
+
+ • 记录错误日志用于问题排查 +
+
+ • 提供正确的 Cron 表达式示例 +
+
+ • 在表单提交前验证表达式有效性 +
+
+
+
+
+ ); +}; + +export default ErrorHandlingDemo; diff --git a/packages/dms-kit/src/components/CronInput/demo/manualMode.tsx b/packages/dms-kit/src/components/CronInput/demo/manualMode.tsx new file mode 100644 index 000000000..1fe919292 --- /dev/null +++ b/packages/dms-kit/src/components/CronInput/demo/manualMode.tsx @@ -0,0 +1,94 @@ +import React, { useState } from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Space, Typography, Card, Alert } from 'antd'; +import { CronInput } from '@actiontech/dms-kit'; +import { CronInputModeEnum } from '@actiontech/dms-kit'; + +const { Text, Title } = Typography; + +const ManualModeDemo: React.FC = () => { + const [cronValue, setCronValue] = useState('0 0 * * *'); + const [currentMode, setCurrentMode] = useState( + CronInputModeEnum.Manual + ); + + const handleChange = (value: string) => { + setCronValue(value); + console.log('手动输入 Cron 表达式:', value); + }; + + const handleModeChange = (mode: CronInputModeEnum) => { + setCurrentMode(mode); + console.log('输入模式变化:', mode); + }; + + return ( + + + + + + 手动输入 Cron 表达式 + +
+ 当前模式: + + {currentMode === CronInputModeEnum.Manual + ? '手动输入' + : '可视化选择'} + +
+ +
+ 当前值: + {cronValue} +
+ + +
+
+ + + Cron 表达式格式说明 + +
+ 格式: + 分钟 小时 日期 月份 星期 +
+
+ 示例: +
+
+ 0 0 * * * + - 每天午夜执行 +
+
+ 0 */2 * * * + - 每2小时执行 +
+
+ 30 9 * * 1-5 + - 工作日9:30执行 +
+
+ 0 12 1 * * + - 每月1号中午执行 +
+
+
+
+
+ ); +}; + +export default ManualModeDemo; diff --git a/packages/shared/lib/components/CronInput/index.ts b/packages/dms-kit/src/components/CronInput/index.ts similarity index 100% rename from packages/shared/lib/components/CronInput/index.ts rename to packages/dms-kit/src/components/CronInput/index.ts diff --git a/packages/shared/lib/components/CronInput/style.ts b/packages/dms-kit/src/components/CronInput/style.ts similarity index 100% rename from packages/shared/lib/components/CronInput/style.ts rename to packages/dms-kit/src/components/CronInput/style.ts diff --git a/packages/shared/lib/components/CronInput/useCron/cron.tool.test.ts b/packages/dms-kit/src/components/CronInput/useCron/cron.tool.test.ts similarity index 100% rename from packages/shared/lib/components/CronInput/useCron/cron.tool.test.ts rename to packages/dms-kit/src/components/CronInput/useCron/cron.tool.test.ts diff --git a/packages/shared/lib/components/CronInput/useCron/cron.tool.ts b/packages/dms-kit/src/components/CronInput/useCron/cron.tool.ts similarity index 100% rename from packages/shared/lib/components/CronInput/useCron/cron.tool.ts rename to packages/dms-kit/src/components/CronInput/useCron/cron.tool.ts diff --git a/packages/shared/lib/components/CronInput/useCron/index.test.tsx b/packages/dms-kit/src/components/CronInput/useCron/index.test.tsx similarity index 100% rename from packages/shared/lib/components/CronInput/useCron/index.test.tsx rename to packages/dms-kit/src/components/CronInput/useCron/index.test.tsx diff --git a/packages/shared/lib/components/CronInput/useCron/index.tsx b/packages/dms-kit/src/components/CronInput/useCron/index.tsx similarity index 100% rename from packages/shared/lib/components/CronInput/useCron/index.tsx rename to packages/dms-kit/src/components/CronInput/useCron/index.tsx diff --git a/packages/shared/lib/components/CronInput/useCron/index.type.ts b/packages/dms-kit/src/components/CronInput/useCron/index.type.ts similarity index 100% rename from packages/shared/lib/components/CronInput/useCron/index.type.ts rename to packages/dms-kit/src/components/CronInput/useCron/index.type.ts diff --git a/packages/shared/lib/components/CustomAvatar/CustomAvatar.test.tsx b/packages/dms-kit/src/components/CustomAvatar/CustomAvatar.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomAvatar/CustomAvatar.test.tsx rename to packages/dms-kit/src/components/CustomAvatar/CustomAvatar.test.tsx diff --git a/packages/shared/lib/components/CustomAvatar/CustomAvatar.tsx b/packages/dms-kit/src/components/CustomAvatar/CustomAvatar.tsx similarity index 100% rename from packages/shared/lib/components/CustomAvatar/CustomAvatar.tsx rename to packages/dms-kit/src/components/CustomAvatar/CustomAvatar.tsx diff --git a/packages/shared/lib/components/CustomAvatar/CustomAvatar.types.ts b/packages/dms-kit/src/components/CustomAvatar/CustomAvatar.types.ts similarity index 100% rename from packages/shared/lib/components/CustomAvatar/CustomAvatar.types.ts rename to packages/dms-kit/src/components/CustomAvatar/CustomAvatar.types.ts diff --git a/packages/dms-kit/src/components/CustomAvatar/README.md b/packages/dms-kit/src/components/CustomAvatar/README.md new file mode 100644 index 000000000..c307d63b8 --- /dev/null +++ b/packages/dms-kit/src/components/CustomAvatar/README.md @@ -0,0 +1,139 @@ +--- +group: + title: 自定义组件 + order: 11 +--- + +# CustomAvatar 自定义头像 + +基于 Ant Design Avatar 组件封装的自定义头像组件,提供了统一的样式规范和增强的功能特性,包括自动生成文字头像和智能提示。 + +## 何时使用 + +- 需要显示用户头像时 +- 需要自动生成文字头像(当没有图片时)时 +- 需要显示用户姓名提示时 +- 需要保持与设计系统一致的头像组件样式时 + +## 代码演示 + +### 基础用法 + + + +### 头像尺寸 + + + + + +## API + +### CustomAvatar + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| name | 用户姓名,用于生成文字头像和提示 | `string` | - | - | +| src | 头像图片地址 | `string` | - | - | +| noTips | 是否禁用提示 | `boolean` | `false` | - | +| size | 头像大小 | `'large' \| 'default' \| 'small' \| number` | `'default'` | - | +| toolTipsWrapperClassName | 提示框包装器的类名 | `string` | - | - | + +### 继承属性 + +CustomAvatar 组件继承了 Ant Design Avatar 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| alt | 图片无法显示时的替代文本 | `string` | - | - | +| gap | 字符类型头像之间的距离 | `number` | `4` | - | +| icon | 设置头像的图标类型 | `ReactNode` | - | - | +| shape | 指定头像的形状 | `'circle' \| 'square'` | `'circle'` | - | +| className | 头像类名 | `string` | - | - | +| style | 头像样式 | `CSSProperties` | - | - | + +## 设计规范 + +### 样式特性 + +- 统一的圆形设计 (`border-radius: 50%`) +- 自动文字头像生成 +- 基于主题的色彩系统 +- 智能提示功能集成 +- 响应式尺寸支持 + +### 尺寸规范 + +- **大尺寸 (large)**: `40px × 40px` +- **默认尺寸 (default)**: `32px × 32px` +- **小尺寸 (small)**: `24px × 24px` +- **自定义尺寸**: 支持数字值 + +### 文字头像规范 + +- 自动提取姓名的第一个字符 +- 转换为大写字母显示 +- 使用主题色彩系统 +- 默认背景色: `#fde3cf` +- 默认文字色: `#f56a00` + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.customAvatar = { + backgroundColor: string, // 文字头像背景色 + color: string, // 文字头像文字色 + hoverColor: string // 悬停状态颜色 +} +``` + +## 功能特性 + +### 自动文字头像 + +当没有提供 `src` 属性时,组件会自动: +1. 提取 `name` 属性的第一个字符 +2. 转换为大写字母 +3. 应用默认的文字头像样式 +4. 显示在圆形背景中 + +### 智能提示 + +- 默认显示用户姓名提示 +- 可通过 `noTips` 属性禁用 +- 支持自定义提示框样式 +- 基于 BasicToolTip 组件实现 + +### 响应式支持 + +- 支持所有标准头像尺寸 +- 自动适应容器大小 +- 保持宽高比例 +- 支持自定义尺寸值 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `name` 属性用于生成文字头像,建议提供有意义的用户名 +3. `src` 属性优先级高于 `name` 属性 +4. 文字头像会自动提取姓名的第一个字符 +5. 提示功能基于 BasicToolTip 组件,确保依赖正确 + +## 最佳实践 + +1. **命名规范**: 使用有意义的用户名,便于生成文字头像 +2. **图片优化**: 提供适当尺寸的头像图片,避免过大文件 +3. **提示内容**: 在需要时显示用户完整信息 +4. **尺寸选择**: 根据使用场景选择合适的头像尺寸 +5. **样式一致性**: 保持与整体设计系统的风格一致 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Avatar 封装 +- 支持所有 Avatar 组件的属性和事件 +- 新增 `name` 属性支持自动文字头像生成 +- 新增 `noTips` 属性控制提示显示 +- 集成 BasicToolTip 组件提供智能提示 +- 统一的样式规范和主题系统集成 \ No newline at end of file diff --git a/packages/shared/lib/components/CustomAvatar/__snapshots__/CustomAvatar.test.tsx.snap b/packages/dms-kit/src/components/CustomAvatar/__snapshots__/CustomAvatar.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomAvatar/__snapshots__/CustomAvatar.test.tsx.snap rename to packages/dms-kit/src/components/CustomAvatar/__snapshots__/CustomAvatar.test.tsx.snap diff --git a/packages/dms-kit/src/components/CustomAvatar/demo/basic.tsx b/packages/dms-kit/src/components/CustomAvatar/demo/basic.tsx new file mode 100644 index 000000000..64e448eb8 --- /dev/null +++ b/packages/dms-kit/src/components/CustomAvatar/demo/basic.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { Space, Card } from 'antd'; +import { CustomAvatar, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicDemo: React.FC = () => { + return ( + +
+

基础用法

+ + + +
+ +
张三
+
+
+ +
李四
+
+
+ +
王五
+
+
+
+ + + +
+ +
用户A
+
+
+ +
用户B
+
+
+ +
用户C
+
+
+
+
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/CustomAvatar/demo/sizes.tsx b/packages/dms-kit/src/components/CustomAvatar/demo/sizes.tsx new file mode 100644 index 000000000..eb701ad6f --- /dev/null +++ b/packages/dms-kit/src/components/CustomAvatar/demo/sizes.tsx @@ -0,0 +1,178 @@ +import React from 'react'; +import { Space, Card, Divider } from 'antd'; +import { CustomAvatar, ConfigProvider } from '@actiontech/dms-kit'; + +const SizesDemo: React.FC = () => { + return ( + +
+

头像尺寸

+ + + +
+ +
+ large (40px) +
+
+
+ +
+ default (32px) +
+
+
+ +
+ small (24px) +
+
+
+
+ + + +
+ +
+ 64px +
+
+
+ +
+ 80px +
+
+
+ +
+ 100px +
+
+
+ +
+ 120px +
+
+
+
+ + + +
+ +
+ large (40px) +
+
+
+ +
+ default (32px) +
+
+
+ +
+ small (24px) +
+
+
+ +
+ 64px +
+
+
+
+
+
+ ); +}; + +export default SizesDemo; diff --git a/packages/shared/lib/components/CustomAvatar/index.ts b/packages/dms-kit/src/components/CustomAvatar/index.ts similarity index 100% rename from packages/shared/lib/components/CustomAvatar/index.ts rename to packages/dms-kit/src/components/CustomAvatar/index.ts diff --git a/packages/shared/lib/components/CustomAvatar/style.ts b/packages/dms-kit/src/components/CustomAvatar/style.ts similarity index 100% rename from packages/shared/lib/components/CustomAvatar/style.ts rename to packages/dms-kit/src/components/CustomAvatar/style.ts diff --git a/packages/shared/lib/components/CustomDraggerUpload/CustomDraggerUpload.test.tsx b/packages/dms-kit/src/components/CustomDraggerUpload/CustomDraggerUpload.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomDraggerUpload/CustomDraggerUpload.test.tsx rename to packages/dms-kit/src/components/CustomDraggerUpload/CustomDraggerUpload.test.tsx diff --git a/packages/shared/lib/components/CustomDraggerUpload/CustomDraggerUpload.tsx b/packages/dms-kit/src/components/CustomDraggerUpload/CustomDraggerUpload.tsx similarity index 100% rename from packages/shared/lib/components/CustomDraggerUpload/CustomDraggerUpload.tsx rename to packages/dms-kit/src/components/CustomDraggerUpload/CustomDraggerUpload.tsx diff --git a/packages/shared/lib/components/CustomDraggerUpload/CustomDraggerUpload.types.ts b/packages/dms-kit/src/components/CustomDraggerUpload/CustomDraggerUpload.types.ts similarity index 100% rename from packages/shared/lib/components/CustomDraggerUpload/CustomDraggerUpload.types.ts rename to packages/dms-kit/src/components/CustomDraggerUpload/CustomDraggerUpload.types.ts diff --git a/packages/dms-kit/src/components/CustomDraggerUpload/README.md b/packages/dms-kit/src/components/CustomDraggerUpload/README.md new file mode 100644 index 000000000..d1bf2426e --- /dev/null +++ b/packages/dms-kit/src/components/CustomDraggerUpload/README.md @@ -0,0 +1,132 @@ +--- +group: + title: 自定义组件 + order: 10 +--- + +# CustomDraggerUpload 自定义拖拽上传 + +基于 Ant Design Upload.Dragger 组件封装的自定义拖拽上传组件,提供了统一的样式规范和增强的视觉效果。 + +## 何时使用 + +- 需要拖拽上传文件时 +- 需要自定义上传区域的图标和标题时 +- 需要保持与设计系统一致的上传组件样式时 +- 需要隐藏上传区域(当有文件列表时)时 + +## 代码演示 + +### 基础用法 + + + +### 自定义图标和标题 + + + +### 文件类型限制 + + + +### 上传进度和状态 + + + +### 多文件上传 + + + +### 图片预览上传 + + + +## API + +### CustomDraggerUpload + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| title | 自定义上传区域标题 | `ReactNode` | `t('common.tips.selectFile')` | - | +| icon | 自定义上传区域图标 | `ReactNode` | `` | - | + +### 继承属性 + +CustomDraggerUpload 组件继承了 Ant Design Upload.Dragger 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| accept | 接受上传的文件类型 | `string` | - | - | +| action | 上传的地址 | `string \| ((file) => string) \| ((file) => Promise)` | - | - | +| beforeUpload | 上传文件之前的钩子 | `(file, fileList) => boolean \| Promise` | - | - | +| data | 上传时附带的额外参数 | `object \| ((file) => object) \| ((file) => Promise)` | - | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| fileList | 已经上传的文件列表 | `UploadFile[]` | - | - | +| headers | 设置上传的请求头部 | `object` | - | - | +| listType | 上传列表的内建样式 | `'text' \| 'picture' \| 'picture-card'` | `'text'` | - | +| maxCount | 限制最多可以上传多少个文件 | `number` | - | - | +| multiple | 是否支持多选文件 | `boolean` | `false` | - | +| name | 发到后台的文件参数名 | `string` | `'file'` | - | +| showUploadList | 是否显示 uploadList | `boolean \| ShowUploadListInterface` | `true` | - | +| onChange | 上传文件改变时的状态 | `(info: UploadChangeParam) => void` | - | - | +| onDrop | 文件被拖拽时触发 | `(e: React.DragEvent) => void` | - | - | +| onRemove | 点击移除文件时的回调 | `(file: UploadFile) => boolean \| Promise` | - | - | + +## 设计规范 + +### 样式特性 + +- 统一的圆角设计 (`border-radius: 8px`) +- 虚线边框样式 (`border: 1px dashed`) +- 居中对齐的图标和文字 +- 基于主题的色彩系统 +- 支持悬停、拖拽等交互状态 + +### 尺寸规范 + +- **默认高度**: `400px` +- **图标尺寸**: `40px × 40px` +- **标题字体**: `13px, 400 weight` +- **标题行高**: `20px` + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.customDraggerUpload = { + backgroundColor: string, // 背景颜色 + color: string, // 文字颜色 + border: string // 边框颜色 +} +``` + +### 响应式行为 + +- 当 `fileList` 有内容时,自动隐藏拖拽区域 +- 支持自定义图标和标题内容 +- 继承所有 Ant Design Upload 的响应式特性 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `title` 属性支持国际化,默认使用 `t('common.tips.selectFile')` +3. `icon` 属性支持自定义图标,默认使用 `UploadCloudOutlined` +4. 当 `fileList` 有内容时,拖拽区域会自动隐藏 +5. 所有 Ant Design Upload.Dragger 的属性和事件都可以正常使用 + +## 最佳实践 + +1. **文件类型限制**: 使用 `accept` 属性限制可上传的文件类型 +2. **文件大小限制**: 在 `beforeUpload` 中检查文件大小 +3. **自定义验证**: 在 `beforeUpload` 中添加业务逻辑验证 +4. **错误处理**: 监听 `onChange` 事件处理上传状态变化 +5. **用户体验**: 提供清晰的上传提示和进度反馈 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Upload.Dragger 封装 +- 支持所有 Upload.Dragger 组件的属性和事件 +- 新增 `title` 和 `icon` 属性支持自定义内容 +- 统一的样式规范和主题系统集成 +- 自动隐藏拖拽区域功能 diff --git a/packages/shared/lib/components/CustomDraggerUpload/__snapshots__/CustomDraggerUpload.test.tsx.snap b/packages/dms-kit/src/components/CustomDraggerUpload/__snapshots__/CustomDraggerUpload.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomDraggerUpload/__snapshots__/CustomDraggerUpload.test.tsx.snap rename to packages/dms-kit/src/components/CustomDraggerUpload/__snapshots__/CustomDraggerUpload.test.tsx.snap diff --git a/packages/dms-kit/src/components/CustomDraggerUpload/demo/basic.tsx b/packages/dms-kit/src/components/CustomDraggerUpload/demo/basic.tsx new file mode 100644 index 000000000..ac7fbd043 --- /dev/null +++ b/packages/dms-kit/src/components/CustomDraggerUpload/demo/basic.tsx @@ -0,0 +1,47 @@ +import React, { useState } from 'react'; +import { message, UploadFile } from 'antd'; +import { CustomDraggerUpload, ConfigProvider } from '@actiontech/dms-kit'; +import { InboxOutlined } from '@ant-design/icons'; + +const BasicDemo: React.FC = () => { + const [fileList, setFileList] = useState([]); + + const handleChange = (info: any) => { + const { status } = info.file; + + if (status === 'done') { + message.success(`${info.file.name} 文件上传成功`); + } else if (status === 'error') { + message.error(`${info.file.name} 文件上传失败`); + } + + setFileList(info.fileList); + }; + + const beforeUpload = (file: File) => { + const isLt2M = file.size / 1024 / 1024 < 2; + if (!isLt2M) { + message.error('文件大小不能超过 2MB!'); + return false; + } + return true; + }; + + return ( + +
+

基础拖拽上传

+ +
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/CustomDraggerUpload/demo/customIcon.tsx b/packages/dms-kit/src/components/CustomDraggerUpload/demo/customIcon.tsx new file mode 100644 index 000000000..ee2c2034d --- /dev/null +++ b/packages/dms-kit/src/components/CustomDraggerUpload/demo/customIcon.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { CustomDraggerUpload, ConfigProvider } from '@actiontech/dms-kit'; +import { + CloudUploadOutlined, + FileTextOutlined, + PictureOutlined +} from '@ant-design/icons'; + +const CustomIconDemo: React.FC = () => { + return ( + +
+

自定义图标和标题

+ +
+

默认样式

+ +
+ +
+

自定义图标和标题

+ + } + title="点击或拖拽文件到此区域上传" + action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6e2188" + /> +
+ +
+

文档上传样式

+ + } + title="拖拽文档文件到此处上传" + accept=".doc,.docx,.pdf,.txt" + action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6e2188" + /> +
+ +
+

图片上传样式

+ + } + title="拖拽图片文件到此处上传" + accept="image/*" + action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6e2188" + /> +
+
+
+ ); +}; + +export default CustomIconDemo; diff --git a/packages/dms-kit/src/components/CustomDraggerUpload/demo/fileTypes.tsx b/packages/dms-kit/src/components/CustomDraggerUpload/demo/fileTypes.tsx new file mode 100644 index 000000000..770f5a4e1 --- /dev/null +++ b/packages/dms-kit/src/components/CustomDraggerUpload/demo/fileTypes.tsx @@ -0,0 +1,124 @@ +import React, { useState } from 'react'; +import { message, UploadFile, Tag } from 'antd'; +import { CustomDraggerUpload, ConfigProvider } from '@actiontech/dms-kit'; +import { + FileTextOutlined, + PictureOutlined, + FileZipOutlined +} from '@ant-design/icons'; + +const FileTypesDemo: React.FC = () => { + const [fileList, setFileList] = useState([]); + + const handleChange = (info: any) => { + const { status } = info.file; + + if (status === 'done') { + message.success(`${info.file.name} 文件上传成功`); + } else if (status === 'error') { + message.error(`${info.file.name} 文件上传失败`); + } + + setFileList(info.fileList); + }; + + const beforeUpload = (file: File) => { + // 检查文件大小 + const isLt10M = file.size / 1024 / 1024 < 10; + if (!isLt10M) { + message.error('文件大小不能超过 10MB!'); + return false; + } + + // 检查文件类型 + const allowedTypes = [ + 'image/jpeg', + 'image/png', + 'image/gif', + 'application/pdf', + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/zip', + 'application/x-rar-compressed' + ]; + + if (!allowedTypes.includes(file.type)) { + message.error('不支持的文件类型!'); + return false; + } + + return true; + }; + + return ( + +
+

文件类型限制

+ +
+

支持的文件类型

+
+ 图片文件: JPG, PNG, GIF + 文档文件: PDF, DOC, DOCX + 压缩文件: ZIP, RAR +
+

+ 文件大小限制: 10MB 以内 +

+
+ +
+

图片上传

+ + } + title="拖拽图片文件到此处上传" + accept="image/*" + fileList={fileList} + onChange={handleChange} + beforeUpload={beforeUpload} + action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6e2188" + /> +
+ +
+

文档上传

+ + } + title="拖拽文档文件到此处上传" + accept=".pdf,.doc,.docx" + fileList={fileList} + onChange={handleChange} + beforeUpload={beforeUpload} + action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6e2188" + /> +
+ +
+

压缩包上传

+ + } + title="拖拽压缩文件到此处上传" + accept=".zip,.rar" + fileList={fileList} + onChange={handleChange} + beforeUpload={beforeUpload} + action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6e2188" + /> +
+
+
+ ); +}; + +export default FileTypesDemo; diff --git a/packages/dms-kit/src/components/CustomDraggerUpload/demo/imageUpload.tsx b/packages/dms-kit/src/components/CustomDraggerUpload/demo/imageUpload.tsx new file mode 100644 index 000000000..07bbd79ef --- /dev/null +++ b/packages/dms-kit/src/components/CustomDraggerUpload/demo/imageUpload.tsx @@ -0,0 +1,126 @@ +import React, { useState } from 'react'; +import { message, UploadFile, Image, Space, Tag, Button } from 'antd'; +import { CustomDraggerUpload, ConfigProvider } from '@actiontech/dms-kit'; +import { PictureOutlined, DeleteOutlined } from '@ant-design/icons'; + +const ImageUploadDemo: React.FC = () => { + const [fileList, setFileList] = useState([]); + + const handleChange = (info: any) => { + const { file, fileList: fileListInfo } = info; + + if (file.status === 'done') { + message.success(`${file.name} 图片上传成功`); + } else if (file.status === 'error') { + message.error(`${file.name} 图片上传失败`); + } + + setFileList(fileListInfo); + }; + + const beforeUpload = (file: File) => { + const isImage = file.type.startsWith('image/'); + if (!isImage) { + message.error('只能上传图片文件!'); + return false; + } + + const isLt5M = file.size / 1024 / 1024 < 5; + if (!isLt5M) { + message.error('图片大小不能超过 5MB!'); + return false; + } + return true; + }; + + const handleRemove = (file: UploadFile) => { + const newFileList = fileList.filter((item) => item.uid !== file.uid); + setFileList(newFileList); + message.success(`${file.name} 图片已移除`); + }; + + return ( + +
+

图片预览上传

+ +
+ + } + title="拖拽图片文件到此处上传" + accept="image/*" + listType="picture-card" + maxCount={6} + /> +
+ + {fileList.length > 0 && ( +
+

图片预览

+ + {fileList.map((file) => ( +
+ +
+
+ {file.name} +
+ + {file.status === 'done' && ( + 已完成 + )} + {file.status === 'uploading' && ( + 上传中 + )} + {file.status === 'error' && ( + 上传失败 + )} +
+
+ ))} +
+
+ )} +
+
+ ); +}; + +export default ImageUploadDemo; diff --git a/packages/dms-kit/src/components/CustomDraggerUpload/demo/multipleFiles.tsx b/packages/dms-kit/src/components/CustomDraggerUpload/demo/multipleFiles.tsx new file mode 100644 index 000000000..27ada4269 --- /dev/null +++ b/packages/dms-kit/src/components/CustomDraggerUpload/demo/multipleFiles.tsx @@ -0,0 +1,191 @@ +import React, { useState } from 'react'; +import { message, UploadFile, Button, Space, Tag, List, Avatar } from 'antd'; +import { CustomDraggerUpload, ConfigProvider } from '@actiontech/dms-kit'; +import { + CloudUploadOutlined, + DeleteOutlined, + EyeOutlined +} from '@ant-design/icons'; + +const MultipleFilesDemo: React.FC = () => { + const [fileList, setFileList] = useState([]); + + const handleChange = (info: any) => { + const { file, fileList: fileListInfo } = info; + + if (file.status === 'done') { + message.success(`${file.name} 文件上传成功`); + } else if (file.status === 'error') { + message.error(`${file.name} 文件上传失败`); + } + + setFileList(fileListInfo); + }; + + const beforeUpload = (file: File) => { + const isLt10M = file.size / 1024 / 1024 < 10; + if (!isLt10M) { + message.error(`${file.name} 文件大小不能超过 10MB!`); + return false; + } + return true; + }; + + const handleRemove = (file: UploadFile) => { + const newFileList = fileList.filter((item) => item.uid !== file.uid); + setFileList(newFileList); + message.success(`${file.name} 文件已移除`); + }; + + const handlePreview = (file: UploadFile) => { + if (file.url) { + window.open(file.url); + } else { + message.info('文件预览功能需要文件URL'); + } + }; + + const getFileIcon = (file: UploadFile) => { + const fileName = file.name || ''; + if (fileName.match(/\.(jpg|jpeg|png|gif|bmp)$/i)) { + return } />; + } else if (fileName.match(/\.(doc|docx)$/i)) { + return ( + 📄} style={{ backgroundColor: '#1890ff' }} /> + ); + } else if (fileName.match(/\.(pdf)$/i)) { + return ( + 📕} style={{ backgroundColor: '#ff4d4f' }} /> + ); + } else if (fileName.match(/\.(zip|rar|7z)$/i)) { + return ( + 📦} style={{ backgroundColor: '#fa8c16' }} /> + ); + } else { + return ( + 📁} style={{ backgroundColor: '#52c41a' }} /> + ); + } + }; + + const getFileSize = (size: number) => { + if (size < 1024) { + return `${size} B`; + } else if (size < 1024 * 1024) { + return `${(size / 1024).toFixed(1)} KB`; + } else { + return `${(size / 1024 / 1024).toFixed(1)} MB`; + } + }; + + return ( + +
+

多文件上传

+ +
+ + } + title="拖拽多个文件到此处上传" + maxCount={10} + /> +
+ + {fileList.length > 0 && ( +
+
+

已上传文件 ({fileList.length})

+ + + +
+ + ( + } + onClick={() => handlePreview(file)} + > + 预览 + , + + ]} + > + + {file.name} + {file.status === 'done' && ( + 已完成 + )} + {file.status === 'uploading' && ( + 上传中 + )} + {file.status === 'error' && ( + 上传失败 + )} +
+ } + description={ + + 大小: {getFileSize(file.size || 0)} + {file.type && 类型: {file.type}} + + } + /> + + )} + /> +
+ )} + +
+ ); +}; + +export default MultipleFilesDemo; diff --git a/packages/dms-kit/src/components/CustomDraggerUpload/demo/uploadStatus.tsx b/packages/dms-kit/src/components/CustomDraggerUpload/demo/uploadStatus.tsx new file mode 100644 index 000000000..65cac4130 --- /dev/null +++ b/packages/dms-kit/src/components/CustomDraggerUpload/demo/uploadStatus.tsx @@ -0,0 +1,154 @@ +import React, { useState } from 'react'; +import { message, UploadFile, Progress, Space, Tag } from 'antd'; +import { CustomDraggerUpload, ConfigProvider } from '@actiontech/dms-kit'; +import { CloudUploadOutlined } from '@ant-design/icons'; + +const UploadStatusDemo: React.FC = () => { + const [fileList, setFileList] = useState([]); + const [uploadProgress, setUploadProgress] = useState>( + {} + ); + + const handleChange = (info: any) => { + const { file, fileList: fileListInfo } = info; + + // 更新文件列表 + setFileList(fileListInfo); + + // 处理上传状态 + if (file.status === 'uploading') { + // 模拟上传进度 + const timer = setInterval(() => { + setUploadProgress((prev) => { + const current = prev[file.uid] || 0; + if (current >= 100) { + clearInterval(timer); + return prev; + } + return { ...prev, [file.uid]: current + 10 }; + }); + }, 200); + } else if (file.status === 'done') { + message.success(`${file.name} 文件上传成功`); + setUploadProgress((prev) => ({ ...prev, [file.uid]: 100 })); + } else if (file.status === 'error') { + message.error(`${file.name} 文件上传失败`); + } + }; + + const beforeUpload = (file: File) => { + const isLt5M = file.size / 1024 / 1024 < 5; + if (!isLt5M) { + message.error('文件大小不能超过 5MB!'); + return false; + } + return true; + }; + + const getStatusTag = (file: UploadFile) => { + switch (file.status) { + case 'uploading': + return 上传中; + case 'done': + return 已完成; + case 'error': + return 上传失败; + default: + return 等待中; + } + }; + + const getProgressColor = (file: UploadFile) => { + switch (file.status) { + case 'done': + return '#52c41a'; + case 'error': + return '#ff4d4f'; + default: + return '#1890ff'; + } + }; + + return ( + +
+

上传进度和状态

+ +
+ + } + title="拖拽文件到此处上传" + /> +
+ + {fileList.length > 0 && ( +
+

上传状态

+ + {fileList.map((file) => ( +
+
+ {file.name} + {getStatusTag(file)} +
+ +
+ +
+ +
+ + 文件大小: {(file.size! / 1024 / 1024).toFixed(2)} MB + + {file.status === 'done' && ( + + ✓ 上传完成 + + )} + {file.status === 'error' && ( + + ✗ 上传失败 + + )} +
+
+ ))} +
+
+ )} +
+
+ ); +}; + +export default UploadStatusDemo; diff --git a/packages/shared/lib/components/CustomDraggerUpload/index.ts b/packages/dms-kit/src/components/CustomDraggerUpload/index.ts similarity index 100% rename from packages/shared/lib/components/CustomDraggerUpload/index.ts rename to packages/dms-kit/src/components/CustomDraggerUpload/index.ts diff --git a/packages/shared/lib/components/CustomDraggerUpload/style.ts b/packages/dms-kit/src/components/CustomDraggerUpload/style.ts similarity index 100% rename from packages/shared/lib/components/CustomDraggerUpload/style.ts rename to packages/dms-kit/src/components/CustomDraggerUpload/style.ts diff --git a/packages/shared/lib/components/CustomForm/FormItem/CustomLabelContent.tsx b/packages/dms-kit/src/components/CustomForm/FormItem/CustomLabelContent.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/CustomLabelContent.tsx rename to packages/dms-kit/src/components/CustomForm/FormItem/CustomLabelContent.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItem/FormInputBotBorder.tsx b/packages/dms-kit/src/components/CustomForm/FormItem/FormInputBotBorder.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/FormInputBotBorder.tsx rename to packages/dms-kit/src/components/CustomForm/FormItem/FormInputBotBorder.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItem/FormItem.types.ts b/packages/dms-kit/src/components/CustomForm/FormItem/FormItem.types.ts similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/FormItem.types.ts rename to packages/dms-kit/src/components/CustomForm/FormItem/FormItem.types.ts diff --git a/packages/shared/lib/components/CustomForm/FormItem/FormItemLabel.tsx b/packages/dms-kit/src/components/CustomForm/FormItem/FormItemLabel.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/FormItemLabel.tsx rename to packages/dms-kit/src/components/CustomForm/FormItem/FormItemLabel.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItem/FormItemNoLabel.tsx b/packages/dms-kit/src/components/CustomForm/FormItem/FormItemNoLabel.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/FormItemNoLabel.tsx rename to packages/dms-kit/src/components/CustomForm/FormItem/FormItemNoLabel.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItem/__tests__/CustomLabelContent.test.tsx b/packages/dms-kit/src/components/CustomForm/FormItem/__tests__/CustomLabelContent.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/__tests__/CustomLabelContent.test.tsx rename to packages/dms-kit/src/components/CustomForm/FormItem/__tests__/CustomLabelContent.test.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItem/__tests__/FormInputBotBorder.test.tsx b/packages/dms-kit/src/components/CustomForm/FormItem/__tests__/FormInputBotBorder.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/__tests__/FormInputBotBorder.test.tsx rename to packages/dms-kit/src/components/CustomForm/FormItem/__tests__/FormInputBotBorder.test.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItem/__tests__/FormItemLabel.test.tsx b/packages/dms-kit/src/components/CustomForm/FormItem/__tests__/FormItemLabel.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/__tests__/FormItemLabel.test.tsx rename to packages/dms-kit/src/components/CustomForm/FormItem/__tests__/FormItemLabel.test.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItem/__tests__/FormItemNoLabel.test.tsx b/packages/dms-kit/src/components/CustomForm/FormItem/__tests__/FormItemNoLabel.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/__tests__/FormItemNoLabel.test.tsx rename to packages/dms-kit/src/components/CustomForm/FormItem/__tests__/FormItemNoLabel.test.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItem/__tests__/__snapshots__/CustomLabelContent.test.tsx.snap b/packages/dms-kit/src/components/CustomForm/FormItem/__tests__/__snapshots__/CustomLabelContent.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/__tests__/__snapshots__/CustomLabelContent.test.tsx.snap rename to packages/dms-kit/src/components/CustomForm/FormItem/__tests__/__snapshots__/CustomLabelContent.test.tsx.snap diff --git a/packages/shared/lib/components/CustomForm/FormItem/__tests__/__snapshots__/FormInputBotBorder.test.tsx.snap b/packages/dms-kit/src/components/CustomForm/FormItem/__tests__/__snapshots__/FormInputBotBorder.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/__tests__/__snapshots__/FormInputBotBorder.test.tsx.snap rename to packages/dms-kit/src/components/CustomForm/FormItem/__tests__/__snapshots__/FormInputBotBorder.test.tsx.snap diff --git a/packages/shared/lib/components/CustomForm/FormItem/__tests__/__snapshots__/FormItemLabel.test.tsx.snap b/packages/dms-kit/src/components/CustomForm/FormItem/__tests__/__snapshots__/FormItemLabel.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/__tests__/__snapshots__/FormItemLabel.test.tsx.snap rename to packages/dms-kit/src/components/CustomForm/FormItem/__tests__/__snapshots__/FormItemLabel.test.tsx.snap diff --git a/packages/shared/lib/components/CustomForm/FormItem/__tests__/__snapshots__/FormItemNoLabel.test.tsx.snap b/packages/dms-kit/src/components/CustomForm/FormItem/__tests__/__snapshots__/FormItemNoLabel.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/__tests__/__snapshots__/FormItemNoLabel.test.tsx.snap rename to packages/dms-kit/src/components/CustomForm/FormItem/__tests__/__snapshots__/FormItemNoLabel.test.tsx.snap diff --git a/packages/shared/lib/components/CustomForm/FormItem/style.ts b/packages/dms-kit/src/components/CustomForm/FormItem/style.ts similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItem/style.ts rename to packages/dms-kit/src/components/CustomForm/FormItem/style.ts diff --git a/packages/shared/lib/components/CustomForm/FormItemTitle/FormItemBigTitle.tsx b/packages/dms-kit/src/components/CustomForm/FormItemTitle/FormItemBigTitle.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItemTitle/FormItemBigTitle.tsx rename to packages/dms-kit/src/components/CustomForm/FormItemTitle/FormItemBigTitle.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItemTitle/FormItemSubTitle.tsx b/packages/dms-kit/src/components/CustomForm/FormItemTitle/FormItemSubTitle.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItemTitle/FormItemSubTitle.tsx rename to packages/dms-kit/src/components/CustomForm/FormItemTitle/FormItemSubTitle.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItemTitle/FormItemTitle.types.ts b/packages/dms-kit/src/components/CustomForm/FormItemTitle/FormItemTitle.types.ts similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItemTitle/FormItemTitle.types.ts rename to packages/dms-kit/src/components/CustomForm/FormItemTitle/FormItemTitle.types.ts diff --git a/packages/shared/lib/components/CustomForm/FormItemTitle/__tests__/FormItemBigTitle.test.tsx b/packages/dms-kit/src/components/CustomForm/FormItemTitle/__tests__/FormItemBigTitle.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItemTitle/__tests__/FormItemBigTitle.test.tsx rename to packages/dms-kit/src/components/CustomForm/FormItemTitle/__tests__/FormItemBigTitle.test.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItemTitle/__tests__/FormItemSubTitle.test.tsx b/packages/dms-kit/src/components/CustomForm/FormItemTitle/__tests__/FormItemSubTitle.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItemTitle/__tests__/FormItemSubTitle.test.tsx rename to packages/dms-kit/src/components/CustomForm/FormItemTitle/__tests__/FormItemSubTitle.test.tsx diff --git a/packages/shared/lib/components/CustomForm/FormItemTitle/__tests__/__snapshots__/FormItemBigTitle.test.tsx.snap b/packages/dms-kit/src/components/CustomForm/FormItemTitle/__tests__/__snapshots__/FormItemBigTitle.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItemTitle/__tests__/__snapshots__/FormItemBigTitle.test.tsx.snap rename to packages/dms-kit/src/components/CustomForm/FormItemTitle/__tests__/__snapshots__/FormItemBigTitle.test.tsx.snap diff --git a/packages/shared/lib/components/CustomForm/FormItemTitle/__tests__/__snapshots__/FormItemSubTitle.test.tsx.snap b/packages/dms-kit/src/components/CustomForm/FormItemTitle/__tests__/__snapshots__/FormItemSubTitle.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItemTitle/__tests__/__snapshots__/FormItemSubTitle.test.tsx.snap rename to packages/dms-kit/src/components/CustomForm/FormItemTitle/__tests__/__snapshots__/FormItemSubTitle.test.tsx.snap diff --git a/packages/shared/lib/components/CustomForm/FormItemTitle/style.ts b/packages/dms-kit/src/components/CustomForm/FormItemTitle/style.ts similarity index 100% rename from packages/shared/lib/components/CustomForm/FormItemTitle/style.ts rename to packages/dms-kit/src/components/CustomForm/FormItemTitle/style.ts diff --git a/packages/dms-kit/src/components/CustomForm/README.md b/packages/dms-kit/src/components/CustomForm/README.md new file mode 100644 index 000000000..786bf3a91 --- /dev/null +++ b/packages/dms-kit/src/components/CustomForm/README.md @@ -0,0 +1,137 @@ +--- +group: + title: 自定义组件 + order: 7 +--- + +# CustomForm 自定义表单组件 + +基于 Ant Design Form 组件封装的自定义表单组件集合,提供了多种表单布局样式、标题组件和特殊的表单字段组件,满足不同场景的表单设计需求。 + +## 何时使用 + +- 需要大标题样式的表单标题时 +- 需要子标题样式的表单分组时 +- 需要无标签的表单项时 +- 需要自定义标签内容的表单项时 +- 需要底部边框样式的输入框时 +- 需要保持与设计系统一致的表单样式时 + +## 代码演示 + +### 基础用法 + + + +### 表单标题组件 + + + +### 表单字段组件 + + + +### 复杂表单布局 + + + +### 表单验证 + + + +### 响应式表单 + + + + +## API + +### FormItemBigTitle + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| children | 标题内容 | `ReactNode` | - | - | + +### FormItemSubTitle + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| children | 标题内容 | `ReactNode` | - | - | + +### FormItemLabel + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| children | 表单项内容 | `ReactNode` | - | - | + +### FormItemNoLabel + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| children | 表单项内容 | `ReactNode` | - | - | + +### FormInputBotBorder + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| placeholder | 占位符文本 | `string` | - | - | + +### CustomLabelContent + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| title | 标签标题 | `ReactNode` | - | - | +| tips | 提示信息 | `ReactNode` | - | - | + +### 继承属性 + +所有表单组件都继承了 Ant Design Form.Item 组件的相关属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| name | 字段名 | `string \| number \| (string \| number)[]` | - | - | +| label | 标签文本 | `ReactNode` | - | - | +| rules | 验证规则 | `Rule[]` | - | - | +| required | 是否必填 | `boolean` | `false` | - | +| help | 帮助信息 | `ReactNode` | - | - | +| validateStatus | 验证状态 | `'success' \| 'warning' \| 'error' \| 'validating'` | - | - | +| hasFeedback | 是否有反馈图标 | `boolean` | `false` | - | + +## 设计规范 + +### 标题层级 + +- **FormItemBigTitle**: 使用 `h3` 标签,适合表单的主要标题 +- **FormItemSubTitle**: 使用 `h4` 标签,适合表单的分组标题 + +### 样式特性 + +- 统一的字体大小和颜色规范 +- 一致的间距和边距设计 +- 响应式的布局适配 +- 支持主题系统的样式配置 + +### 布局规范 + +- 标准表单项使用 `FormItemLabel` +- 紧凑布局使用 `FormItemNoLabel` +- 特殊设计使用 `FormInputBotBorder` +- 复杂标签使用 `CustomLabelContent` + + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. 所有表单组件都支持 Ant Design Form 的验证规则 +3. 标题组件主要用于视觉层次,不影响表单逻辑 +4. 特殊样式组件(如 `FormInputBotBorder`)适合特定设计需求 +5. 可以组合使用多个组件创建复杂的表单布局 + +## 更新日志 + +- **1.0.0**: 初始版本,提供基础的表单组件集合 +- 支持多种表单标题样式 +- 支持多种表单字段布局 +- 统一的样式规范和主题系统集成 +- 继承 Ant Design Form 的所有功能 +- 支持响应式布局和自定义样式 diff --git a/packages/dms-kit/src/components/CustomForm/demo/basic.tsx b/packages/dms-kit/src/components/CustomForm/demo/basic.tsx new file mode 100644 index 000000000..85eb56d3f --- /dev/null +++ b/packages/dms-kit/src/components/CustomForm/demo/basic.tsx @@ -0,0 +1,163 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { Form, Input, Button, Card, Space } from 'antd'; +import { + FormItemBigTitle, + FormItemSubTitle, + FormItemLabel, + FormItemNoLabel, + FormInputBotBorder, + CustomLabelContent +} from '@actiontech/dms-kit'; + +const BasicDemo: React.FC = () => { + const [form] = Form.useForm(); + + const onFinish = (values: any) => { + console.log('表单数据:', values); + }; + + return ( + +
+

基础用法

+ + + 用户信息表单 + 基本信息 +

+ 使用 FormItemBigTitle 和 FormItemSubTitle 来组织表单结构 +

+
+ + +
+ + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + +
+ + +
+ + + + + + + + +
+ + +
+ + } + name="databaseConfig" + > + + + + + + + + + + + + +
+ + +
+ 系统配置 + + 基础配置 + + + + + 高级配置 + + } + name="cacheConfig" + > + + + + + + + + + + + + + + +
+
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/CustomForm/demo/complexLayout.tsx b/packages/dms-kit/src/components/CustomForm/demo/complexLayout.tsx new file mode 100644 index 000000000..1e109a80c --- /dev/null +++ b/packages/dms-kit/src/components/CustomForm/demo/complexLayout.tsx @@ -0,0 +1,255 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { + FormItemBigTitle, + FormItemSubTitle, + FormItemLabel, + FormItemNoLabel, + FormInputBotBorder, + CustomLabelContent +} from '@actiontech/dms-kit'; +import { + Form, + Input, + Button, + Card, + Space, + Row, + Col, + Select, + Switch, + DatePicker, + Divider +} from 'antd'; + +const ComplexLayoutDemo: React.FC = () => { + const [form] = Form.useForm(); + + const onFinish = (values: any) => { + console.log('表单数据:', values); + }; + + return ( + +
+

复杂表单布局

+ + +
+ 企业用户注册 + + 企业基本信息 + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + 联系人信息 + + + + + + + + + + + + + + + + + + + + + 系统配置 + + } + name="databaseConfig" + > + + + + + + + + + + + + + + + + + + + + } + name="featureSwitches" + > + +
+ 用户管理: + +
+
+ 权限管理: + +
+
+ 数据备份: + +
+
+ 日志记录: + +
+
+
+ + + + 高级设置 + + + + + + + + + + + + + + + + + + + + + +
    +
  • + 标题层级: 使用 FormItemBigTitle 和 + FormItemSubTitle 创建清晰的表单结构 +
  • +
  • + 栅格布局: 使用 Row 和 Col 组件实现响应式布局 +
  • +
  • + 分组显示: 使用 Divider 分隔不同的表单区域 +
  • +
  • + 组件组合: 混合使用各种表单组件满足不同需求 +
  • +
  • + 验证规则: 为必填字段添加验证规则 +
  • +
  • + 操作按钮: 提供多种操作选项 +
  • +
+
+ + + ); +}; + +export default ComplexLayoutDemo; diff --git a/packages/dms-kit/src/components/CustomForm/demo/formFields.tsx b/packages/dms-kit/src/components/CustomForm/demo/formFields.tsx new file mode 100644 index 000000000..ba0756ed1 --- /dev/null +++ b/packages/dms-kit/src/components/CustomForm/demo/formFields.tsx @@ -0,0 +1,238 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { + FormItemLabel, + FormItemNoLabel, + FormInputBotBorder, + CustomLabelContent +} from '@actiontech/dms-kit'; +import { + Form, + Input, + Button, + Card, + Space, + Select, + Switch, + DatePicker +} from 'antd'; + +const FormFieldsDemo: React.FC = () => { + const [form] = Form.useForm(); + + const onFinish = (values: any) => { + console.log('表单数据:', values); + }; + + return ( + +
+

表单字段组件

+ + +
+ + + + + + + + + + + + + + + + + + } + name="systemSettings" + > + +
+ 启用通知: + +
+
+ 系统日期: + +
+
+
+ + + + + +
+ + +
+ + + + + + + + + + + + + + } + name="advancedConfig" + > + + + + + + + + + + +
+ + +
    +
  • + FormItemLabel: 标准表单项,包含标签和验证规则 +
  • +
  • + FormItemNoLabel: 无标签表单项,适合紧凑布局 +
  • +
  • + FormInputBotBorder: + 特殊样式的输入框,只有底部边框 +
  • +
  • + CustomLabelContent: + 自定义标签内容,支持标题和提示 +
  • +
  • 所有组件都支持 Ant Design Form 的验证规则
  • +
  • 可以组合使用创建复杂的表单布局
  • +
+
+
+
+ ); +}; + +export default FormFieldsDemo; diff --git a/packages/dms-kit/src/components/CustomForm/demo/formTitles.tsx b/packages/dms-kit/src/components/CustomForm/demo/formTitles.tsx new file mode 100644 index 000000000..9e84fda9e --- /dev/null +++ b/packages/dms-kit/src/components/CustomForm/demo/formTitles.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { FormItemBigTitle, FormItemSubTitle } from '@actiontech/dms-kit'; +import { Card, Space, Divider } from 'antd'; + +const FormTitlesDemo: React.FC = () => { + return ( + +
+

表单标题组件

+ + + 用户管理系统 +

+ 用于表单的主要标题,通常放在表单的最顶部 +

+
+ + + 基本信息 +

+ 用于表单的分组标题,通常放在相关字段之前 +

+
+ + + 系统配置 + + 用户配置 +

+ 用户相关的配置选项 +

+ + 系统配置 +

+ 系统级别的配置选项 +

+ + 安全配置 +

+ 安全相关的配置选项 +

+
+ + + +
+ 主要功能 +

这是主要功能的描述

+
+ + + +
+ 辅助功能 +

这是辅助功能的描述

+
+ + + +
+ 高级设置 +

这是高级设置的描述

+
+
+
+ + +
    +
  • + FormItemBigTitle: + 用于表单的主要标题,通常只有一个 +
  • +
  • + FormItemSubTitle: 用于表单的分组标题,可以有多个 +
  • +
  • 标题组件主要用于视觉层次,不影响表单逻辑
  • +
  • 可以组合使用创建清晰的表单结构
  • +
  • 支持主题系统的样式配置
  • +
+
+
+
+ ); +}; + +export default FormTitlesDemo; diff --git a/packages/dms-kit/src/components/CustomForm/demo/formValidation.tsx b/packages/dms-kit/src/components/CustomForm/demo/formValidation.tsx new file mode 100644 index 000000000..996a81960 --- /dev/null +++ b/packages/dms-kit/src/components/CustomForm/demo/formValidation.tsx @@ -0,0 +1,307 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { + FormItemBigTitle, + FormItemSubTitle, + FormItemLabel, + FormItemNoLabel, + CustomLabelContent +} from '@actiontech/dms-kit'; +import { + Form, + Input, + Button, + Card, + Space, + Select, + InputNumber, + message, + Divider +} from 'antd'; + +const FormValidationDemo: React.FC = () => { + const [form] = Form.useForm(); + + const onFinish = (values: any) => { + message.success('表单验证通过!数据:' + JSON.stringify(values, null, 2)); + }; + + const onFinishFailed = (errorInfo: any) => { + message.error('表单验证失败!请检查输入内容。'); + console.log('验证失败:', errorInfo); + }; + + const validatePassword = async (_: any, value: string) => { + if (!value) { + throw new Error('请输入密码'); + } + if (value.length < 6) { + throw new Error('密码长度不能少于6位'); + } + if (!/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)) { + throw new Error('密码必须包含大小写字母和数字'); + } + }; + + const validateConfirmPassword = async (_: any, value: string) => { + if (!value) { + throw new Error('请确认密码'); + } + const password = form.getFieldValue('password'); + if (value !== password) { + throw new Error('两次输入的密码不一致'); + } + }; + + const validatePhone = async (_: any, value: string) => { + if (!value) { + throw new Error('请输入手机号'); + } + if (!/^1[3-9]\d{9}$/.test(value)) { + throw new Error('请输入有效的手机号'); + } + }; + + const validateIdCard = async (_: any, value: string) => { + if (!value) { + throw new Error('请输入身份证号'); + } + if (!/^\d{17}[\dXx]$/.test(value)) { + throw new Error('请输入有效的身份证号'); + } + }; + + return ( + +
+

表单验证示例

+ + +
+ 用户注册 + + 基本信息 + + + + + + + + + + + + + + + + + + + 安全设置 + + + + + + + + + + + 其他信息 + + + + + + + +
+ + + + + + + + + + + + + +
    +
  • + 必填验证: 使用 required: true 确保字段不为空 +
  • +
  • + 长度验证: 使用 min 和 max 限制字符串长度 +
  • +
  • + 格式验证: 使用 pattern 进行正则表达式验证 +
  • +
  • + 类型验证: 使用 type 验证邮箱、数字等类型 +
  • +
  • + 自定义验证: 使用 validator 函数进行复杂验证 +
  • +
  • + 关联验证: 验证密码确认等关联字段 +
  • +
  • + 实时反馈: 使用 hasFeedback 显示验证状态图标 +
  • +
+
+ + +
    +
  • + 滚动到错误: 使用 scrollToFirstError + 自动滚动到第一个错误字段 +
  • +
  • + 验证状态: 支持 + success、warning、error、validating 等状态 +
  • +
  • + 错误提示: 自动显示验证错误信息 +
  • +
  • + 表单重置: 支持一键重置所有字段和验证状态 +
  • +
  • + 手动验证: 可以手动触发表单验证 +
  • +
+
+ +
+ ); +}; + +export default FormValidationDemo; diff --git a/packages/dms-kit/src/components/CustomForm/demo/responsiveForm.tsx b/packages/dms-kit/src/components/CustomForm/demo/responsiveForm.tsx new file mode 100644 index 000000000..f4b87c7ee --- /dev/null +++ b/packages/dms-kit/src/components/CustomForm/demo/responsiveForm.tsx @@ -0,0 +1,334 @@ +import React from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import { + FormItemBigTitle, + FormItemSubTitle, + FormItemLabel, + FormItemNoLabel, + CustomLabelContent +} from '@actiontech/dms-kit'; +import { + Form, + Input, + Button, + Card, + Space, + Row, + Col, + Select, + Switch, + DatePicker, + Divider +} from 'antd'; + +const ResponsiveFormDemo: React.FC = () => { + const [form] = Form.useForm(); + + const onFinish = (values: any) => { + console.log('表单数据:', values); + }; + + return ( + +
+

响应式表单布局

+ + +
+ 用户信息管理 + + 基本信息 + {/* 大屏幕:2列布局,小屏幕:1列布局 */} + +
+ + + + + + + + + + + + + + + + + + + + + + + + + {/* 大屏幕:3列布局,小屏幕:1列布局 */} + + + + + + + + + + + + + + + + 地址信息 + {/* 大屏幕:2列布局,小屏幕:1列布局 */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + 偏好设置 + {/* 大屏幕:4列布局,小屏幕:2列布局 */} + + + + + + + + + + + + + + + + + + + + + + + + + } + name="interests" + > + + +
+ 技术: + +
+ + +
+ 体育: + +
+ + +
+ 音乐: + +
+ + +
+ 电影: + +
+ + + + + + + 其他信息 + + + + + + + + + + + + + + + + + + + + + +
    +
  • + xs (≤576px): 超小屏幕,手机竖屏 +
  • +
  • + sm (≥576px): 小屏幕,手机横屏 +
  • +
  • + md (≥768px): 中等屏幕,平板 +
  • +
  • + lg (≥992px): 大屏幕,桌面 +
  • +
  • + xl (≥1200px): 超大屏幕,大桌面 +
  • +
  • + xxl (≥1600px): 超超大屏幕 +
  • +
+
+ + +
    +
  • + 自适应列数: 大屏幕显示多列,小屏幕自动调整为单列 +
  • +
  • + 栅格系统: 使用 Ant Design 的 Row 和 Col 组件 +
  • +
  • + 间距控制: 使用 gutter 属性控制列间距 +
  • +
  • + 按钮响应式: 按钮在不同屏幕尺寸下自适应宽度 +
  • +
  • + 表单验证: 验证规则在所有屏幕尺寸下保持一致 +
  • +
+
+ + + ); +}; + +export default ResponsiveFormDemo; diff --git a/packages/shared/lib/components/CustomForm/index.ts b/packages/dms-kit/src/components/CustomForm/index.ts similarity index 100% rename from packages/shared/lib/components/CustomForm/index.ts rename to packages/dms-kit/src/components/CustomForm/index.ts diff --git a/packages/shared/lib/components/CustomForm/style.ts b/packages/dms-kit/src/components/CustomForm/style.ts similarity index 100% rename from packages/shared/lib/components/CustomForm/style.ts rename to packages/dms-kit/src/components/CustomForm/style.ts diff --git a/packages/shared/lib/components/CustomInput/CustomInput.test.tsx b/packages/dms-kit/src/components/CustomInput/CustomInput.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomInput/CustomInput.test.tsx rename to packages/dms-kit/src/components/CustomInput/CustomInput.test.tsx diff --git a/packages/shared/lib/components/CustomInput/CustomInput.tsx b/packages/dms-kit/src/components/CustomInput/CustomInput.tsx similarity index 100% rename from packages/shared/lib/components/CustomInput/CustomInput.tsx rename to packages/dms-kit/src/components/CustomInput/CustomInput.tsx diff --git a/packages/shared/lib/components/CustomInput/CustomInput.types.ts b/packages/dms-kit/src/components/CustomInput/CustomInput.types.ts similarity index 100% rename from packages/shared/lib/components/CustomInput/CustomInput.types.ts rename to packages/dms-kit/src/components/CustomInput/CustomInput.types.ts diff --git a/packages/dms-kit/src/components/CustomInput/README.md b/packages/dms-kit/src/components/CustomInput/README.md new file mode 100644 index 000000000..2f3148110 --- /dev/null +++ b/packages/dms-kit/src/components/CustomInput/README.md @@ -0,0 +1,111 @@ +--- +group: + title: 自定义组件 + order: 7 +--- + +# CustomInput 自定义输入框 + +基于 Ant Design Input 组件和 BasicInput 组件封装的自定义输入框组件,提供了统一的样式规范和自定义的回车键处理功能。 + +## 何时使用 + +- 需要自定义回车键处理逻辑时 +- 需要保持与设计系统一致的输入框样式时 +- 需要前缀图标或文本的输入框时 +- 需要继承 BasicInput 所有功能的自定义输入框时 + +## 代码演示 + +### 基础用法 + + + +### 带前缀的输入框 + + + +### 自定义回车处理 + + + +### 不同尺寸 + + + +### 表单集成 + + + +## API + +### CustomInput + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| onCustomPressEnter | 自定义回车键处理函数 | `(value: string) => void` | - | - | +| prefix | 输入框前缀图标或文本 | `ReactNode` | - | - | + +### 继承属性 + +CustomInput 组件继承了 Ant Design Input 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| placeholder | 输入框提示文本 | `string` | - | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| size | 输入框大小 | `'large' \| 'middle' \| 'small'` | `'small'` | - | +| value | 输入框的值 | `string` | - | - | +| defaultValue | 输入框的默认值 | `string` | - | - | +| onChange | 输入框值变化时的回调 | `(e: ChangeEvent) => void` | - | - | +| onBlur | 输入框失去焦点时的回调 | `(e: FocusEvent) => void` | - | - | +| onFocus | 输入框获得焦点时的回调 | `(e: FocusEvent) => void` | - | - | +| className | 输入框类名 | `string` | - | - | +| style | 输入框样式 | `CSSProperties` | - | - | + +## 设计规范 + +### 样式特性 + +- 基于 BasicInput 组件的样式系统 +- 统一的圆角设计 (`border-radius: 4px`) +- 自定义前缀样式,支持图标和文本 +- 响应式的悬停和聚焦效果 +- 支持清除图标功能 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.customSelect = { + border: string; + content: { + prefixColor: string; + }; + focusBackGroundColor: string; + hoverBackgroundColor: string; +} +``` + +### 尺寸规范 + +- **小尺寸 (small)**: 默认尺寸,适合大多数场景 +- **中尺寸 (middle)**: 通过 size 属性设置 +- **大尺寸 (large)**: 通过 size 属性设置 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `onCustomPressEnter` 属性是必需的,用于处理回车键事件 +3. 组件默认使用 `small` 尺寸,可以通过 `size` 属性覆盖 +4. 所有 Ant Design Input 的属性和事件都可以正常使用 +5. 组件会自动应用统一的样式类名 `custom-input-namespace` + +## 更新日志 + +- **1.0.0**: 初始版本,基于 BasicInput 和 Ant Design Input 封装 +- 支持所有 Input 组件的属性和事件 +- 新增 `onCustomPressEnter` 属性支持自定义回车处理 +- 统一的样式规范和主题系统集成 +- 继承 BasicInput 的所有功能和样式 diff --git a/packages/shared/lib/components/CustomInput/__snapshots__/CustomInput.test.tsx.snap b/packages/dms-kit/src/components/CustomInput/__snapshots__/CustomInput.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomInput/__snapshots__/CustomInput.test.tsx.snap rename to packages/dms-kit/src/components/CustomInput/__snapshots__/CustomInput.test.tsx.snap diff --git a/packages/dms-kit/src/components/CustomInput/demo/basic.tsx b/packages/dms-kit/src/components/CustomInput/demo/basic.tsx new file mode 100644 index 000000000..0f9ee0fd8 --- /dev/null +++ b/packages/dms-kit/src/components/CustomInput/demo/basic.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { CustomInput, ConfigProvider } from '@actiontech/dms-kit'; +import { message } from 'antd'; + +const BasicDemo: React.FC = () => { + const handleCustomPressEnter = (value: string) => { + message.success(`输入的值: ${value}`); + }; + + return ( + +
+

基础用法

+
+ +
+ +

带前缀的输入框

+
+ +
+ +

带文本前缀的输入框

+
+ +
+
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/CustomInput/demo/customEnter.tsx b/packages/dms-kit/src/components/CustomInput/demo/customEnter.tsx new file mode 100644 index 000000000..27cc66ceb --- /dev/null +++ b/packages/dms-kit/src/components/CustomInput/demo/customEnter.tsx @@ -0,0 +1,108 @@ +import React, { useState } from 'react'; +import { CustomInput, ConfigProvider } from '@actiontech/dms-kit'; +import { message, Button, Space, Card } from 'antd'; + +const CustomEnterDemo: React.FC = () => { + const [searchValue, setSearchValue] = useState(''); + const [sqlValue, setSqlValue] = useState(''); + const [commandValue, setCommandValue] = useState(''); + + const handleSearch = (value: string) => { + if (!value.trim()) { + message.warning('请输入搜索内容'); + return; + } + message.success(`执行搜索: ${value}`); + setSearchValue(value); + }; + + const handleSqlExecute = (value: string) => { + if (!value.trim()) { + message.warning('请输入SQL语句'); + return; + } + if (!value.toLowerCase().includes('select')) { + message.error('请输入有效的SELECT语句'); + return; + } + message.success(`执行SQL: ${value}`); + setSqlValue(value); + }; + + const handleCommandExecute = (value: string) => { + if (!value.trim()) { + message.warning('请输入命令'); + return; + } + message.success(`执行命令: ${value}`); + setCommandValue(value); + }; + + const clearAll = () => { + setSearchValue(''); + setSqlValue(''); + setCommandValue(''); + message.info('已清空所有输入'); + }; + + return ( + +
+

自定义回车处理示例

+ + + + {searchValue && ( +
+ 当前搜索: {searchValue} +
+ )} +
+ + + + {sqlValue && ( +
+ 当前SQL: {sqlValue} +
+ )} +
+ + + + {commandValue && ( +
+ 当前命令: {commandValue} +
+ )} +
+ + + + + +
+
+ ); +}; + +export default CustomEnterDemo; diff --git a/packages/dms-kit/src/components/CustomInput/demo/formIntegration.tsx b/packages/dms-kit/src/components/CustomInput/demo/formIntegration.tsx new file mode 100644 index 000000000..a417fad7e --- /dev/null +++ b/packages/dms-kit/src/components/CustomInput/demo/formIntegration.tsx @@ -0,0 +1,187 @@ +import React, { useState } from 'react'; +import { CustomInput, ConfigProvider } from '@actiontech/dms-kit'; +import { message, Form, Button, Card, Space, Divider } from 'antd'; + +interface FormData { + username: string; + email: string; + project: string; + database: string; + sql: string; +} + +const FormIntegrationDemo: React.FC = () => { + const [form] = Form.useForm(); + const [formData, setFormData] = useState({ + username: '', + email: '', + project: '', + database: '', + sql: '' + }); + + const handleUsernameEnter = (value: string) => { + form.setFieldsValue({ username: value }); + setFormData(prev => ({ ...prev, username: value })); + message.success(`用户名已设置: ${value}`); + }; + + const handleEmailEnter = (value: string) => { + form.setFieldsValue({ email: value }); + setFormData(prev => ({ ...prev, email: value })); + message.success(`邮箱已设置: ${value}`); + }; + + const handleProjectEnter = (value: string) => { + form.setFieldsValue({ project: value }); + setFormData(prev => ({ ...prev, project: value })); + message.success(`项目已设置: ${value}`); + }; + + const handleDatabaseEnter = (value: string) => { + form.setFieldsValue({ database: value }); + setFormData(prev => ({ ...prev, database: value })); + message.success(`数据库已设置: ${value}`); + }; + + const handleSqlEnter = (value: string) => { + form.setFieldsValue({ sql: value }); + setFormData(prev => ({ ...prev, sql: value })); + message.success(`SQL已设置: ${value}`); + }; + + const onFinish = (values: FormData) => { + message.success('表单提交成功!'); + console.log('表单数据:', values); + }; + + const resetForm = () => { + form.resetFields(); + setFormData({ + username: '', + email: '', + project: '', + database: '', + sql: '' + }); + message.info('表单已重置'); + }; + + return ( + +
+

表单集成示例

+

+ 在表单中使用 CustomInput 组件,支持回车键快速提交单个字段 +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+            {JSON.stringify(formData, null, 2)}
+          
+
+ + + + +
    +
  • 每个输入框都支持回车键快速确认输入
  • +
  • 回车确认后会自动更新表单数据
  • +
  • 表单验证规则仍然有效
  • +
  • 可以结合 Ant Design Form 的所有功能
  • +
+
+
+
+ ); +}; + +export default FormIntegrationDemo; diff --git a/packages/dms-kit/src/components/CustomInput/demo/sizes.tsx b/packages/dms-kit/src/components/CustomInput/demo/sizes.tsx new file mode 100644 index 000000000..9479ff6c1 --- /dev/null +++ b/packages/dms-kit/src/components/CustomInput/demo/sizes.tsx @@ -0,0 +1,116 @@ +import React from 'react'; +import { CustomInput, ConfigProvider } from '@actiontech/dms-kit'; +import { message, Space, Card } from 'antd'; + +const SizesDemo: React.FC = () => { + const handleCustomPressEnter = (value: string) => { + message.success(`输入的值: ${value}`); + }; + + return ( + +
+

不同尺寸的输入框

+ + + + +
+ 适合紧凑的布局,节省空间 +
+
+
+ + + + +
+ 标准尺寸,适合大多数场景 +
+
+
+ + + + +
+ 适合需要突出显示的输入框 +
+
+
+ + + + + + + + + + + + + + + + +
+
+ ); +}; + +export default SizesDemo; diff --git a/packages/dms-kit/src/components/CustomInput/demo/withPrefix.tsx b/packages/dms-kit/src/components/CustomInput/demo/withPrefix.tsx new file mode 100644 index 000000000..7ffa91403 --- /dev/null +++ b/packages/dms-kit/src/components/CustomInput/demo/withPrefix.tsx @@ -0,0 +1,89 @@ +import React from 'react'; +import { CustomInput, ConfigProvider } from '@actiontech/dms-kit'; +import { + UserOutlined, + LockOutlined, + MailOutlined, + PhoneOutlined +} from '@ant-design/icons'; +import { message } from 'antd'; + +const WithPrefixDemo: React.FC = () => { + const handleCustomPressEnter = (value: string) => { + message.success(`输入的值: ${value}`); + }; + + return ( + +
+

图标前缀

+
+ } + placeholder="请输入用户名" + onCustomPressEnter={handleCustomPressEnter} + style={{ width: '300px', marginBottom: '8px' }} + /> +
+ +
+ } + placeholder="请输入密码" + type="password" + onCustomPressEnter={handleCustomPressEnter} + style={{ width: '300px', marginBottom: '8px' }} + /> +
+ +
+ } + placeholder="请输入邮箱" + onCustomPressEnter={handleCustomPressEnter} + style={{ width: '300px', marginBottom: '8px' }} + /> +
+ +
+ } + placeholder="请输入手机号" + onCustomPressEnter={handleCustomPressEnter} + style={{ width: '300px' }} + /> +
+ +

文本前缀

+
+ +
+ +
+ +
+ +
+ +
+
+
+ ); +}; + +export default WithPrefixDemo; diff --git a/packages/shared/lib/components/CustomInput/index.ts b/packages/dms-kit/src/components/CustomInput/index.ts similarity index 100% rename from packages/shared/lib/components/CustomInput/index.ts rename to packages/dms-kit/src/components/CustomInput/index.ts diff --git a/packages/shared/lib/components/CustomInput/style.ts b/packages/dms-kit/src/components/CustomInput/style.ts similarity index 100% rename from packages/shared/lib/components/CustomInput/style.ts rename to packages/dms-kit/src/components/CustomInput/style.ts diff --git a/packages/shared/lib/components/CustomSegmentedFilter/CustomSegmentedFilter.tsx b/packages/dms-kit/src/components/CustomSegmentedFilter/CustomSegmentedFilter.tsx similarity index 100% rename from packages/shared/lib/components/CustomSegmentedFilter/CustomSegmentedFilter.tsx rename to packages/dms-kit/src/components/CustomSegmentedFilter/CustomSegmentedFilter.tsx diff --git a/packages/shared/lib/components/CustomSegmentedFilter/CustomSegmentedFilter.types.ts b/packages/dms-kit/src/components/CustomSegmentedFilter/CustomSegmentedFilter.types.ts similarity index 100% rename from packages/shared/lib/components/CustomSegmentedFilter/CustomSegmentedFilter.types.ts rename to packages/dms-kit/src/components/CustomSegmentedFilter/CustomSegmentedFilter.types.ts diff --git a/packages/dms-kit/src/components/CustomSegmentedFilter/README.md b/packages/dms-kit/src/components/CustomSegmentedFilter/README.md new file mode 100644 index 000000000..fe7f5a184 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSegmentedFilter/README.md @@ -0,0 +1,176 @@ +--- +group: + title: 自定义组件 + order: 12 +--- + +# CustomSegmentedFilter 自定义分段过滤器 + +基于 Ant Design Segmented 组件封装的自定义分段过滤器组件,提供了统一的样式规范和增强的功能特性,包括标签字典、全部选项支持和自定义样式模式。 + +## 何时使用 + +- 需要分段选择器进行数据过滤时 +- 需要支持标签字典进行国际化时 +- 需要自动添加"全部"选项时 +- 需要自定义样式或使用无样式模式时 +- 需要保持与设计系统一致的分段选择器样式时 + +## 代码演示 + +### 基础用法 + + + +### 标签字典支持 + + + +### 全部选项配置 + + + +### 无样式模式 + + + +### 复杂选项配置 + + + + + +## API + +### CustomSegmentedFilter + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| value | 当前选中的值 | `V` | - | - | +| onChange | 值变化时的回调函数 | `(val: V) => void` | - | - | +| defaultValue | 默认选中的值 | `V` | - | - | +| labelDictionary | 标签字典,用于字符串选项的标签转换 | `Record` | - | - | +| options | 选项配置数组 | `CustomSegmentedFilterDefaultOptionsType \| string[]` | - | - | +| withAll | 是否添加"全部"选项 | `boolean \| CustomSegmentedFilterWithAllConfig` | `false` | - | +| noStyle | 是否清空样式 | `boolean` | `false` | - | +| className | 自定义类名 | `string` | - | - | +| style | 自定义样式 | `CSSProperties` | - | - | + +### 类型定义 + +```typescript +// 基础值类型 +type CustomSegmentedFilterBaseValue = string | number | null; + +// 全部选项配置 +type CustomSegmentedFilterWithAllConfig = { + label: ReactNode; + value: V; +}; + +// 选项类型 +type CustomSegmentedFilterDefaultOptionsType = Array<{ + label: ReactNode; + value: V; +}>; +``` + +### 继承属性 + +CustomSegmentedFilter 组件继承了 Ant Design Segmented 组件的所有属性,当 `noStyle` 为 `false` 时。 + +## 设计规范 + +### 样式特性 + +- 统一的圆角设计 +- 基于主题的色彩系统 +- 支持悬停、选中、禁用等状态样式 +- 响应式布局支持 +- 可选的样式自定义 + +### 布局规范 + +- 默认使用 BasicSegmented 组件样式 +- 支持无样式模式进行完全自定义 +- 响应式选项排列 +- 统一的间距和对齐 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.basicSegmented = { + // 继承 BasicSegmented 的主题配置 +} +``` + +## 功能特性 + +### 标签字典支持 + +当 `options` 为字符串数组时,可以通过 `labelDictionary` 自动转换标签: + +```typescript +const options = ['failed', 'finished']; +const labelDictionary = { + failed: '执行失败', + finished: '执行结束' +}; + +// 自动渲染为: +// [ +// { label: '执行失败', value: 'failed' }, +// { label: '执行结束', value: 'finished' } +// ] +``` + +### 全部选项支持 + +通过 `withAll` 属性可以自动添加"全部"选项: + +- `withAll: true` - 使用默认配置,label为"全部",value为null +- `withAll: { label: '自定义', value: 'all' }` - 自定义配置 +- `withAll: false` - 不显示全部选项 + +### 无样式模式 + +当 `noStyle` 为 `true` 时: +- 清空所有默认样式 +- 用户可以使用 StyleWrapper 进行包裹 +- 或自行添加 Class 来处理样式 +- 提供最大的样式自定义自由度 + +### 响应式支持 + +- 自动适应容器宽度 +- 选项自动换行 +- 支持不同屏幕尺寸 +- 保持良好的用户体验 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `labelDictionary` 主要用于国际化场景,建议提供完整的字典映射 +3. `withAll` 选项的 value 类型需要与 options 中的 value 类型保持一致 +4. 当使用 `noStyle` 模式时,需要自行处理样式和交互逻辑 +5. 组件会自动处理受控和非受控状态 + +## 最佳实践 + +1. **标签字典**: 在需要国际化的场景下使用 `labelDictionary` +2. **全部选项**: 根据业务需求合理配置 `withAll` 选项 +3. **样式自定义**: 在需要特殊样式时使用 `noStyle` 模式 +4. **类型安全**: 使用泛型确保类型安全 +5. **响应式设计**: 考虑不同屏幕尺寸下的显示效果 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Segmented 封装 +- 支持所有 Segmented 组件的属性和事件 +- 新增 `labelDictionary` 属性支持标签字典 +- 新增 `withAll` 属性支持全部选项 +- 新增 `noStyle` 属性支持无样式模式 +- 统一的样式规范和主题系统集成 +- 完整的 TypeScript 类型支持 diff --git a/packages/shared/lib/components/CustomSegmentedFilter/__tests__/CustomSegmentedFilter.test.tsx b/packages/dms-kit/src/components/CustomSegmentedFilter/__tests__/CustomSegmentedFilter.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomSegmentedFilter/__tests__/CustomSegmentedFilter.test.tsx rename to packages/dms-kit/src/components/CustomSegmentedFilter/__tests__/CustomSegmentedFilter.test.tsx diff --git a/packages/shared/lib/components/CustomSegmentedFilter/__tests__/__snapshots__/CustomSegmentedFilter.test.tsx.snap b/packages/dms-kit/src/components/CustomSegmentedFilter/__tests__/__snapshots__/CustomSegmentedFilter.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomSegmentedFilter/__tests__/__snapshots__/CustomSegmentedFilter.test.tsx.snap rename to packages/dms-kit/src/components/CustomSegmentedFilter/__tests__/__snapshots__/CustomSegmentedFilter.test.tsx.snap diff --git a/packages/dms-kit/src/components/CustomSegmentedFilter/demo/basic.tsx b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/basic.tsx new file mode 100644 index 000000000..a4880a30a --- /dev/null +++ b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/basic.tsx @@ -0,0 +1,64 @@ +import React, { useState } from 'react'; +import { Card, Space, Tag } from 'antd'; +import { CustomSegmentedFilter, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicDemo: React.FC = () => { + const [status, setStatus] = useState('all'); + const [type, setType] = useState('document'); + + return ( + +
+

基础用法

+ + +
+ 当前选中: + {status} +
+ +
+ + +
+ 当前选中: + {type} +
+ +
+ + +
+ 当前选中: + {status} +
+ +
+
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/CustomSegmentedFilter/demo/complexOptions.tsx b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/complexOptions.tsx new file mode 100644 index 000000000..5cbef8dc4 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/complexOptions.tsx @@ -0,0 +1,226 @@ +import React, { useState } from 'react'; +import { Card, Space, Tag, Divider, Row, Col } from 'antd'; +import { CustomSegmentedFilter, ConfigProvider } from '@actiontech/dms-kit'; + +const ComplexOptionsDemo: React.FC = () => { + const [status, setStatus] = useState('processing'); + const [priority, setPriority] = useState('normal'); + const [type, setType] = useState('document'); + const [category, setCategory] = useState('work'); + + // 复杂选项配置 + const complexOptions = [ + { label: '进行中', value: 'processing', color: '#1890ff' }, + { label: '已完成', value: 'finished', color: '#52c41a' }, + { label: '已失败', value: 'failed', color: '#ff4d4f' }, + { label: '已取消', value: 'cancelled', color: '#faad14' } + ]; + + const priorityOptions = [ + { label: '低优先级', value: 'low', icon: '🔵' }, + { label: '普通优先级', value: 'normal', icon: '🟡' }, + { label: '高优先级', value: 'high', icon: '🟠' }, + { label: '紧急优先级', value: 'urgent', icon: '🔴' } + ]; + + const typeOptions = [ + { label: '📄 文档', value: 'document' }, + { label: '🖼️ 图片', value: 'image' }, + { label: '🎥 视频', value: 'video' }, + { label: '🎵 音频', value: 'audio' }, + { label: '📦 压缩包', value: 'archive' } + ]; + + return ( + +
+

复杂选项配置

+ + +
+ 当前选中: + {status} +
+ + + + +
+

配置说明:

+
+{`const complexOptions = [
+  { label: '进行中', value: 'processing', color: '#1890ff' },
+  { label: '已完成', value: 'finished', color: '#52c41a' },
+  { label: '已失败', value: 'failed', color: '#ff4d4f' },
+  { label: '已取消', value: 'cancelled', color: '#faad14' }
+];`}
+            
+
+
+ + +
+ 当前选中: + {priority} +
+ + + + +
+

配置说明:

+
+{`const priorityOptions = [
+  { label: '低优先级', value: 'low', icon: '🔵' },
+  { label: '普通优先级', value: 'normal', icon: '🟡' },
+  { label: '高优先级', value: 'high', icon: '🟠' },
+  { label: '紧急优先级', value: 'urgent', icon: '🔴' }
+];`}
+            
+
+
+ + +
+ 当前选中: + {type} +
+ + + + +
+

配置说明:

+
+{`const typeOptions = [
+  { label: '📄 文档', value: 'document' },
+  { label: '🖼️ 图片', value: 'image' },
+  { label: '🎥 视频', value: 'video' },
+  { label: '🎵 音频', value: 'audio' },
+  { label: '📦 压缩包', value: 'archive' }
+];`}
+            
+
+
+ + +
+

根据数据动态生成选项

+
+ + +
+
+ 当前选中: + {category} +
+ + + + +
+
动态选项配置:
+
+{`// 基础选项
+options: ['work', 'personal', 'study', ...]
+
+// 标签字典
+labelDictionary: {
+  work: '💼 工作',
+  personal: '👤 个人',
+  study: '📚 学习',
+  ...
+}
+
+// 自动转换为:
+// [
+//   { label: '💼 工作', value: 'work' },
+//   { label: '👤 个人', value: 'personal' },
+//   { label: '📚 学习', value: 'study' },
+//   ...
+// ]`}
+                
+
+ + + + + +
+

多种配置方式的组合使用

+
+ +
+
+
字符串 + 标签字典
+ +
+ +
+
对象数组 + 自定义全部
+ +
+
+
+ + + ); +}; + +export default ComplexOptionsDemo; diff --git a/packages/dms-kit/src/components/CustomSegmentedFilter/demo/labelDictionary.tsx b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/labelDictionary.tsx new file mode 100644 index 000000000..941281544 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/labelDictionary.tsx @@ -0,0 +1,154 @@ +import React, { useState } from 'react'; +import { Card, Space, Tag, Divider } from 'antd'; +import { CustomSegmentedFilter, ConfigProvider } from '@actiontech/dms-kit'; + +const LabelDictionaryDemo: React.FC = () => { + const [status, setStatus] = useState('all'); + const [priority, setPriority] = useState('normal'); + + // 状态标签字典 + const statusDictionary = { + all: '全部', + processing: '进行中', + finished: '已完成', + failed: '已失败', + cancelled: '已取消' + }; + + // 优先级标签字典 + const priorityDictionary = { + low: '低优先级', + normal: '普通优先级', + high: '高优先级', + urgent: '紧急优先级' + }; + + // 任务类型标签字典 + const taskTypeDictionary = { + data_sync: '数据同步', + backup: '数据备份', + restore: '数据恢复', + migration: '数据迁移', + cleanup: '数据清理' + }; + + return ( + +
+

标签字典支持

+ + +
+ 当前选中: + + {statusDictionary[status as keyof typeof statusDictionary] || + status} + +
+ + + + +
+

标签字典配置:

+
+              {`const statusDictionary = {
+  all: '全部',
+  processing: '进行中',
+  finished: '已完成',
+  failed: '已失败',
+  cancelled: '已取消'
+};`}
+            
+
+
+ + +
+ 当前选中: + + {priorityDictionary[ + priority as keyof typeof priorityDictionary + ] || priority} + +
+ + + + +
+

标签字典配置:

+
+              {`const priorityDictionary = {
+  low: '低优先级',
+  normal: '普通优先级',
+  high: '高优先级',
+  urgent: '紧急优先级'
+};`}
+            
+
+
+ + +
+ 当前选中: + 请选择 +
+ + + + +
+

标签字典配置:

+
+              {`const taskTypeDictionary = {
+  data_sync: '数据同步',
+  backup: '数据备份',
+  restore: '数据恢复',
+  migration: '数据迁移',
+  cleanup: '数据清理'
+};`}
+            
+
+
+
+
+ ); +}; + +export default LabelDictionaryDemo; diff --git a/packages/dms-kit/src/components/CustomSegmentedFilter/demo/noStyle.tsx b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/noStyle.tsx new file mode 100644 index 000000000..0ada812ed --- /dev/null +++ b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/noStyle.tsx @@ -0,0 +1,180 @@ +import React, { useState } from 'react'; +import { Card, Space, Tag, Divider } from 'antd'; +import { CustomSegmentedFilter, ConfigProvider } from '@actiontech/dms-kit'; + +const NoStyleDemo: React.FC = () => { + const [status, setStatus] = useState('processing'); + const [priority, setPriority] = useState('normal'); + + return ( + +
+

无样式模式

+ + +
+ 当前选中: + {status} +
+ + + + +
+

配置说明:

+
+              {`noStyle: false
+
+// 使用 BasicSegmented 的默认样式
+// 继承 Ant Design Segmented 的所有样式特性`}
+            
+
+
+ + +
+ 当前选中: + {priority} +
+ + + + +
+

配置说明:

+
+              {`noStyle: true
+
+// 清空所有默认样式
+// 用户可以通过 className 和 style 自定义样式
+// 完全控制外观和交互`}
+            
+
+
+ + +
+

通过 CSS 类自定义样式

+
+ +
+
卡片式样式
+ +
+ +
+
标签式样式
+ +
+ + + +
+

CSS 样式示例:

+
+              {`/* 卡片式样式 */
+.card-style-filter .custom-segmented-filter-item {
+  padding: 12px 20px;
+  background: white;
+  border: 1px solid #d9d9d9;
+  border-radius: 8px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.card-style-filter .custom-segmented-filter-item:hover {
+  border-color: #1890ff;
+  box-shadow: 0 2px 8px rgba(24, 144, 255, 0.15);
+}
+
+.card-style-filter .custom-segmented-filter-item-checked {
+  background: #1890ff;
+  color: white;
+  border-color: #1890ff;
+}
+
+/* 标签式样式 */
+.tag-style-filter .custom-segmented-filter-item {
+  padding: 6px 16px;
+  background: #f0f0f0;
+  border-radius: 16px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.tag-style-filter .custom-segmented-filter-item:hover {
+  background: #e6f7ff;
+}
+
+.tag-style-filter .custom-segmented-filter-item-checked {
+  background: #1890ff;
+  color: white;
+}`}
+            
+
+
+
+
+ ); +}; + +export default NoStyleDemo; diff --git a/packages/dms-kit/src/components/CustomSegmentedFilter/demo/withAll.tsx b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/withAll.tsx new file mode 100644 index 000000000..bc9bfc623 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSegmentedFilter/demo/withAll.tsx @@ -0,0 +1,181 @@ +import React, { useState } from 'react'; +import { Card, Space, Tag, Divider } from 'antd'; +import { CustomSegmentedFilter, ConfigProvider } from '@actiontech/dms-kit'; + +const WithAllDemo: React.FC = () => { + const [status, setStatus] = useState('all'); + const [priority, setPriority] = useState('all'); + const [type, setType] = useState('all'); + + return ( + +
+

全部选项配置

+ + +
+ 当前选中: + {status === 'all' ? '全部' : status} +
+ + + + +
+

配置说明:

+
+              {`withAll: true
+
+// 自动添加的选项:
+// { label: '全部', value: null }`}
+            
+
+
+ + +
+ 当前选中: + + {priority === 'all' ? '所有优先级' : priority} + +
+ + + + +
+

配置说明:

+
+              {`withAll: {
+  label: '所有优先级',
+  value: 'all'
+}
+
+// 自定义的选项:
+// { label: '所有优先级', value: 'all' }`}
+            
+
+
+ + +
+ 当前选中: + {type || '请选择'} +
+ + + + +
+

配置说明:

+
+              {`withAll: false
+
+// 不添加全部选项,只显示原始选项`}
+            
+
+
+ + +
+

三种配置方式的对比

+
+ +
+
+
默认全部选项
+ +
+ 自动添加"全部"选项,value 为 null +
+
+ +
+
自定义全部选项
+ +
+ 自定义标签和值 +
+
+ +
+
禁用全部选项
+ +
+ 不显示全部选项 +
+
+
+
+
+
+ ); +}; + +export default WithAllDemo; diff --git a/packages/shared/lib/components/CustomSegmentedFilter/index.ts b/packages/dms-kit/src/components/CustomSegmentedFilter/index.ts similarity index 100% rename from packages/shared/lib/components/CustomSegmentedFilter/index.ts rename to packages/dms-kit/src/components/CustomSegmentedFilter/index.ts diff --git a/packages/shared/lib/components/CustomSelect/CustomOptionLabel.tsx b/packages/dms-kit/src/components/CustomSelect/CustomOptionLabel.tsx similarity index 100% rename from packages/shared/lib/components/CustomSelect/CustomOptionLabel.tsx rename to packages/dms-kit/src/components/CustomSelect/CustomOptionLabel.tsx diff --git a/packages/shared/lib/components/CustomSelect/CustomPlaceholder.tsx b/packages/dms-kit/src/components/CustomSelect/CustomPlaceholder.tsx similarity index 100% rename from packages/shared/lib/components/CustomSelect/CustomPlaceholder.tsx rename to packages/dms-kit/src/components/CustomSelect/CustomPlaceholder.tsx diff --git a/packages/shared/lib/components/CustomSelect/CustomSelect.tsx b/packages/dms-kit/src/components/CustomSelect/CustomSelect.tsx similarity index 100% rename from packages/shared/lib/components/CustomSelect/CustomSelect.tsx rename to packages/dms-kit/src/components/CustomSelect/CustomSelect.tsx diff --git a/packages/shared/lib/components/CustomSelect/CustomSelect.types.ts b/packages/dms-kit/src/components/CustomSelect/CustomSelect.types.ts similarity index 100% rename from packages/shared/lib/components/CustomSelect/CustomSelect.types.ts rename to packages/dms-kit/src/components/CustomSelect/CustomSelect.types.ts diff --git a/packages/shared/lib/components/CustomSelect/CustomSelectSearchInput.tsx b/packages/dms-kit/src/components/CustomSelect/CustomSelectSearchInput.tsx similarity index 100% rename from packages/shared/lib/components/CustomSelect/CustomSelectSearchInput.tsx rename to packages/dms-kit/src/components/CustomSelect/CustomSelectSearchInput.tsx diff --git a/packages/dms-kit/src/components/CustomSelect/README.md b/packages/dms-kit/src/components/CustomSelect/README.md new file mode 100644 index 000000000..9c46ad8a5 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSelect/README.md @@ -0,0 +1,153 @@ +--- +group: + title: 自定义组件 + order: 7 +--- + +# CustomSelect 自定义选择器 + +基于 Ant Design Select 组件封装的自定义选择器组件,提供了统一的样式规范、内置搜索功能、自定义前缀显示和增强的标签模式。 + +## 何时使用 + +- 需要内置搜索功能的选择器时 +- 需要自定义前缀显示的选择器时 +- 需要增强标签模式的选择器时 +- 需要保持与设计系统一致的选择器样式时 +- 需要分组选项和复杂选项结构时 + +## 代码演示 + +### 基础用法 + + + +### 带前缀的选择器 + + + +### 标签模式 + + + +### 分组选项 + + + +### 搜索功能 + + + +### 表单集成 + + + +## API + +### CustomSelect + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| prefix | 选择器前缀图标或文本 | `ReactNode` | - | - | +| valuePrefix | 选项值的前缀显示 | `ReactNode` | `prefix` | - | +| searchInputRef | 搜索输入框的引用 | `RefObject` | - | - | + +### 继承属性 + +CustomSelect 组件继承了 Ant Design Select 组件的所有属性,包括但不限于: + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| options | 选项数据 | `OptionType[]` | - | - | +| mode | 选择模式 | `'multiple' \| 'tags' \| undefined` | - | - | +| placeholder | 占位符文本 | `string \| ReactNode` | - | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| size | 选择器大小 | `'large' \| 'middle' \| 'small'` | `'small'` | - | +| value | 当前选中的值 | `string \| string[]` | - | - | +| defaultValue | 默认选中的值 | `string \| string[]` | - | - | +| onChange | 选择变化时的回调 | `(value, option) => void` | - | - | +| onSearch | 搜索时的回调 | `(value: string) => void` | - | - | +| onDropdownVisibleChange | 下拉框显示状态变化时的回调 | `(open: boolean) => void` | - | - | +| className | 选择器类名 | `string` | - | - | +| style | 选择器样式 | `CSSProperties` | - | - | + +## 设计规范 + +### 样式特性 + +- 基于 Ant Design Select 组件的样式系统 +- 统一的圆角设计 (`border-radius: 4px`) +- 自定义前缀样式,支持图标和文本 +- 内置搜索输入框,自动聚焦 +- 响应式的悬停和聚焦效果 +- 支持清除图标功能 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.customSelect = { + border: string; + content: { + prefixColor: string; + }; + focusBackGroundColor: string; + hoverBackgroundColor: string; +} +``` + +### 尺寸规范 + +- **小尺寸 (small)**: 默认尺寸,适合大多数场景 +- **中尺寸 (middle)**: 通过 size 属性设置 +- **大尺寸 (large)**: 通过 size 属性设置 + +## 功能特性 + +### 内置搜索 + +- 自动显示搜索输入框 +- 支持实时过滤选项 +- 搜索输入框自动聚焦 +- 支持自定义搜索逻辑 + +### 前缀显示 + +- 支持图标和文本前缀 +- 选项标签中显示前缀 +- 标签模式下的前缀处理 +- 可自定义值前缀显示 + +### 标签模式增强 + +- 优化的标签渲染 +- 支持分隔符显示 +- 第一个标签显示前缀 +- 后续标签使用分隔符 + +### 分组选项支持 + +- 支持选项组结构 +- 组标签自定义样式 +- 组内选项搜索过滤 +- 保持分组层次结构 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. 组件默认使用 `small` 尺寸,可以通过 `size` 属性覆盖 +3. 搜索功能默认启用,无需额外配置 +4. 所有 Ant Design Select 的属性和事件都可以正常使用 +5. 组件会自动应用统一的样式类名 `custom-select-namespace` +6. 下拉框弹出层使用 `custom-select-popup-wrapper` 类名 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Ant Design Select 封装 +- 支持所有 Select 组件的属性和事件 +- 新增内置搜索功能 +- 新增前缀显示功能 +- 增强标签模式支持 +- 统一的样式规范和主题系统集成 +- 支持分组选项和复杂选项结构 diff --git a/packages/shared/lib/components/CustomSelect/__tests__/CustomOptionLabel.test.tsx b/packages/dms-kit/src/components/CustomSelect/__tests__/CustomOptionLabel.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomSelect/__tests__/CustomOptionLabel.test.tsx rename to packages/dms-kit/src/components/CustomSelect/__tests__/CustomOptionLabel.test.tsx diff --git a/packages/shared/lib/components/CustomSelect/__tests__/CustomPlaceholder.test.tsx b/packages/dms-kit/src/components/CustomSelect/__tests__/CustomPlaceholder.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomSelect/__tests__/CustomPlaceholder.test.tsx rename to packages/dms-kit/src/components/CustomSelect/__tests__/CustomPlaceholder.test.tsx diff --git a/packages/shared/lib/components/CustomSelect/__tests__/CustomSelect.test.tsx b/packages/dms-kit/src/components/CustomSelect/__tests__/CustomSelect.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomSelect/__tests__/CustomSelect.test.tsx rename to packages/dms-kit/src/components/CustomSelect/__tests__/CustomSelect.test.tsx diff --git a/packages/shared/lib/components/CustomSelect/__tests__/CustomSelectSearchInput.test.tsx b/packages/dms-kit/src/components/CustomSelect/__tests__/CustomSelectSearchInput.test.tsx similarity index 100% rename from packages/shared/lib/components/CustomSelect/__tests__/CustomSelectSearchInput.test.tsx rename to packages/dms-kit/src/components/CustomSelect/__tests__/CustomSelectSearchInput.test.tsx diff --git a/packages/shared/lib/components/CustomSelect/__tests__/__snapshots__/CustomOptionLabel.test.tsx.snap b/packages/dms-kit/src/components/CustomSelect/__tests__/__snapshots__/CustomOptionLabel.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomSelect/__tests__/__snapshots__/CustomOptionLabel.test.tsx.snap rename to packages/dms-kit/src/components/CustomSelect/__tests__/__snapshots__/CustomOptionLabel.test.tsx.snap diff --git a/packages/shared/lib/components/CustomSelect/__tests__/__snapshots__/CustomPlaceholder.test.tsx.snap b/packages/dms-kit/src/components/CustomSelect/__tests__/__snapshots__/CustomPlaceholder.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomSelect/__tests__/__snapshots__/CustomPlaceholder.test.tsx.snap rename to packages/dms-kit/src/components/CustomSelect/__tests__/__snapshots__/CustomPlaceholder.test.tsx.snap diff --git a/packages/shared/lib/components/CustomSelect/__tests__/__snapshots__/CustomSelect.test.tsx.snap b/packages/dms-kit/src/components/CustomSelect/__tests__/__snapshots__/CustomSelect.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomSelect/__tests__/__snapshots__/CustomSelect.test.tsx.snap rename to packages/dms-kit/src/components/CustomSelect/__tests__/__snapshots__/CustomSelect.test.tsx.snap diff --git a/packages/shared/lib/components/CustomSelect/__tests__/__snapshots__/CustomSelectSearchInput.test.tsx.snap b/packages/dms-kit/src/components/CustomSelect/__tests__/__snapshots__/CustomSelectSearchInput.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/CustomSelect/__tests__/__snapshots__/CustomSelectSearchInput.test.tsx.snap rename to packages/dms-kit/src/components/CustomSelect/__tests__/__snapshots__/CustomSelectSearchInput.test.tsx.snap diff --git a/packages/dms-kit/src/components/CustomSelect/demo/basic.tsx b/packages/dms-kit/src/components/CustomSelect/demo/basic.tsx new file mode 100644 index 000000000..cfcdeb0bc --- /dev/null +++ b/packages/dms-kit/src/components/CustomSelect/demo/basic.tsx @@ -0,0 +1,98 @@ +import React, { useState } from 'react'; +import { CustomSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { message, Space, Card } from 'antd'; + +const BasicDemo: React.FC = () => { + const [selectedValue, setSelectedValue] = useState(); + + const basicOptions = [ + { label: '选项1', value: 'option1' }, + { label: '选项2', value: 'option2' }, + { label: '选项3', value: 'option3' }, + { label: '选项4', value: 'option4' }, + { label: '选项5', value: 'option5' } + ]; + + const handleChange = (value: string) => { + setSelectedValue(value); + message.success(`选择了: ${value}`); + }; + + return ( + +
+

基础用法

+ + + + +
+ 当前选择: {selectedValue || '未选择'} +
+
+
+ + + + + + + + + + + + + + + + + + + + +
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/CustomSelect/demo/formIntegration.tsx b/packages/dms-kit/src/components/CustomSelect/demo/formIntegration.tsx new file mode 100644 index 000000000..13f642b41 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSelect/demo/formIntegration.tsx @@ -0,0 +1,314 @@ +import React from 'react'; +import { CustomSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { + Form, + Input, + Button, + Card, + Space, + Row, + Col, + message, + Divider +} from 'antd'; +import { + UserOutlined, + DatabaseOutlined, + ProjectOutlined, + TeamOutlined +} from '@ant-design/icons'; + +const FormIntegrationDemo: React.FC = () => { + const [form] = Form.useForm(); + + const userOptions = [ + { label: '张三', value: 'zhangsan' }, + { label: '李四', value: 'lisi' }, + { label: '王五', value: 'wangwu' }, + { label: '赵六', value: 'zhaoliu' } + ]; + + const databaseOptions = [ + { label: 'MySQL', value: 'mysql' }, + { label: 'PostgreSQL', value: 'postgresql' }, + { label: 'Oracle', value: 'oracle' }, + { label: 'SQL Server', value: 'sqlserver' } + ]; + + const projectOptions = [ + { label: '电商系统', value: 'ecommerce' }, + { label: 'CRM系统', value: 'crm' }, + { label: 'ERP系统', value: 'erp' }, + { label: '数据分析平台', value: 'analytics' } + ]; + + const teamOptions = [ + { label: '开发团队', value: 'dev' }, + { label: '测试团队', value: 'test' }, + { label: '运维团队', value: 'ops' }, + { label: '产品团队', value: 'product' } + ]; + + const onFinish = (values: any) => { + message.success('表单提交成功!'); + console.log('表单数据:', values); + }; + + const onFinishFailed = (errorInfo: any) => { + message.error('表单验证失败!请检查输入内容。'); + console.log('验证失败:', errorInfo); + }; + + return ( + +
+

表单集成

+ + +
+ +
+ + + + + + + + + + + + + + + } + placeholder="请选择负责人" + options={userOptions} + style={{ width: '100%' }} + /> + + + + + } + placeholder="请选择数据库类型" + options={databaseOptions} + style={{ width: '100%' }} + /> + + + + + + + + } + placeholder="请选择项目名称" + options={projectOptions} + style={{ width: '100%' }} + /> + + + + + } + placeholder="请选择所属团队" + options={teamOptions} + style={{ width: '100%' }} + /> + + + + + + + + + + + + + + + + + + +
+ + } + placeholder="请选择项目成员(可多选)" + options={userOptions} + style={{ width: '100%' }} + /> + + + + } + placeholder="请选择支持的技术栈(可多选)" + options={[ + ...databaseOptions, + { label: 'Redis', value: 'redis' }, + { label: 'MongoDB', value: 'mongodb' }, + { label: 'Node.js', value: 'nodejs' }, + { label: 'React', value: 'react' }, + { label: 'Vue', value: 'vue' } + ]} + style={{ width: '100%' }} + /> + + + + } + placeholder="请输入或选择项目标签" + options={[ + { label: '前端', value: 'frontend' }, + { label: '后端', value: 'backend' }, + { label: '移动端', value: 'mobile' }, + { label: 'AI', value: 'ai' }, + { label: '大数据', value: 'bigdata' } + ]} + style={{ width: '100%' }} + /> + + + + + + +
+ + +
    +
  • + 必填验证: 使用 rules 属性设置验证规则 +
  • +
  • + 实时验证: 支持实时验证和提交时验证 +
  • +
  • + 错误提示: 自动显示验证错误信息 +
  • +
  • + 滚动定位: 使用 scrollToFirstError + 自动滚动到错误字段 +
  • +
  • + 表单重置: 支持一键重置所有字段和验证状态 +
  • +
  • + 数据绑定: 自动绑定表单数据到组件状态 +
  • +
+
+ + +
    +
  • + 无缝集成: 与 Ant Design Form 完全兼容 +
  • +
  • + 验证支持: 支持所有 Form 验证规则 +
  • +
  • + 样式统一: 保持与 Form 组件的样式一致性 +
  • +
  • + 功能增强: 在 Form 基础上提供额外功能 +
  • +
  • + 开发效率: 减少重复代码,提高开发效率 +
  • +
+
+ + +
    +
  • + 命名规范: 使用语义化的字段名称 +
  • +
  • + 验证规则: 为重要字段设置合适的验证规则 +
  • +
  • + 用户体验: 使用 placeholder 和 prefix 提升用户体验 +
  • +
  • + 错误处理: 提供清晰的错误提示信息 +
  • +
  • + 响应式设计: 使用 Row 和 Col 实现响应式布局 +
  • +
+
+ + + ); +}; + +export default FormIntegrationDemo; diff --git a/packages/dms-kit/src/components/CustomSelect/demo/groupedOptions.tsx b/packages/dms-kit/src/components/CustomSelect/demo/groupedOptions.tsx new file mode 100644 index 000000000..d57fc3660 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSelect/demo/groupedOptions.tsx @@ -0,0 +1,189 @@ +import React, { useState } from 'react'; +import { CustomSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { message, Space, Card } from 'antd'; +import { + UserOutlined, + DatabaseOutlined, + ProjectOutlined, + TeamOutlined +} from '@ant-design/icons'; + +const GroupedOptionsDemo: React.FC = () => { + const [selectedValue, setSelectedValue] = useState(); + + const groupedOptions = [ + { + label: '用户管理', + options: [ + { label: '张三', value: 'zhangsan' }, + { label: '李四', value: 'lisi' }, + { label: '王五', value: 'wangwu' }, + { label: '赵六', value: 'zhaoliu' } + ] + }, + { + label: '数据库管理', + options: [ + { label: 'MySQL', value: 'mysql' }, + { label: 'PostgreSQL', value: 'postgresql' }, + { label: 'Oracle', value: 'oracle' }, + { label: 'SQL Server', value: 'sqlserver' } + ] + }, + { + label: '项目管理', + options: [ + { label: '电商系统', value: 'ecommerce' }, + { label: 'CRM系统', value: 'crm' }, + { label: 'ERP系统', value: 'erp' }, + { label: '数据分析平台', value: 'analytics' } + ] + }, + { + label: '团队管理', + options: [ + { label: '开发团队', value: 'dev' }, + { label: '测试团队', value: 'test' }, + { label: '运维团队', value: 'ops' }, + { label: '产品团队', value: 'product' } + ] + } + ]; + + const handleChange = (value: string) => { + setSelectedValue(value); + message.success(`选择了: ${value}`); + }; + + return ( + +
+

分组选项

+ + + + +
+ 当前选择: {selectedValue || '未选择'} +
+
+
+ + + + } + placeholder="选择用户或项目" + options={groupedOptions} + onChange={handleChange} + style={{ width: '400px' }} + /> +
+ 当前选择: {selectedValue || '未选择'} +
+
+
+ + + + } + placeholder="选择多个选项" + options={groupedOptions} + onChange={(values) => { + console.log('多选值:', values); + message.success(`选择了 ${values.length} 个选项`); + }} + style={{ width: '400px' }} + /> + + + + + + } + placeholder="选择项目或数据库" + options={[ + { + label: '核心项目', + options: [ + { label: '用户中心', value: 'user-center' }, + { label: '订单系统', value: 'order-system' }, + { label: '支付系统', value: 'payment-system' } + ] + }, + { + label: '数据库集群', + options: [ + { label: '主库-MySQL', value: 'master-mysql' }, + { label: '从库-MySQL', value: 'slave-mysql' }, + { label: '读写分离', value: 'read-write-split' } + ] + }, + { + label: '缓存系统', + options: [ + { label: 'Redis主节点', value: 'redis-master' }, + { label: 'Redis从节点', value: 'redis-slave' }, + { label: 'Redis集群', value: 'redis-cluster' } + ] + } + ]} + onChange={handleChange} + style={{ width: '400px' }} + /> + + + + +
    +
  • + 层次结构: 支持多级分组,每个分组可以有独立的标签 +
  • +
  • + 搜索过滤: 搜索功能会在所有分组中查找匹配的选项 +
  • +
  • + 前缀显示: 分组标签和选项都可以显示前缀 +
  • +
  • + 多选支持: 分组选择器支持单选和多选模式 +
  • +
  • + 样式统一: 分组标签使用特殊的样式类名 +
  • +
+
+ + +
    +
  • + 组织架构: 按部门、团队分组显示人员 +
  • +
  • + 系统分类: 按功能模块分组显示系统 +
  • +
  • + 数据分类: 按类型分组显示数据项 +
  • +
  • + 权限管理: 按角色分组显示权限 +
  • +
  • + 配置管理: 按类别分组显示配置项 +
  • +
+
+
+
+ ); +}; + +export default GroupedOptionsDemo; diff --git a/packages/dms-kit/src/components/CustomSelect/demo/searchFunction.tsx b/packages/dms-kit/src/components/CustomSelect/demo/searchFunction.tsx new file mode 100644 index 000000000..acdfc5ca6 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSelect/demo/searchFunction.tsx @@ -0,0 +1,218 @@ +import React, { useState } from 'react'; +import { CustomSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { message, Space, Card, Tag } from 'antd'; +import { + SearchOutlined, + UserOutlined, + DatabaseOutlined, + ProjectOutlined +} from '@ant-design/icons'; + +const SearchFunctionDemo: React.FC = () => { + const [selectedValue, setSelectedValue] = useState(); + const [searchValue, setSearchValue] = useState(''); + + const allOptions = [ + { label: '张三', value: 'zhangsan' }, + { label: '李四', value: 'lisi' }, + { label: '王五', value: 'wangwu' }, + { label: '赵六', value: 'zhaoliu' }, + { label: '钱七', value: 'qianqi' }, + { label: '孙八', value: 'sunba' }, + { label: '周九', value: 'zhoujiu' }, + { label: '吴十', value: 'wushi' }, + { label: 'MySQL', value: 'mysql' }, + { label: 'PostgreSQL', value: 'postgresql' }, + { label: 'Oracle', value: 'oracle' }, + { label: 'SQL Server', value: 'sqlserver' }, + { label: 'MongoDB', value: 'mongodb' }, + { label: 'Redis', value: 'redis' }, + { label: '电商系统', value: 'ecommerce' }, + { label: 'CRM系统', value: 'crm' }, + { label: 'ERP系统', value: 'erp' }, + { label: '数据分析平台', value: 'analytics' }, + { label: '移动应用', value: 'mobile' }, + { label: 'Web应用', value: 'web' } + ]; + + const groupedOptions = [ + { + label: '用户管理', + options: [ + { label: '张三', value: 'zhangsan' }, + { label: '李四', value: 'lisi' }, + { label: '王五', value: 'wangwu' }, + { label: '赵六', value: 'zhaoliu' } + ] + }, + { + label: '数据库管理', + options: [ + { label: 'MySQL', value: 'mysql' }, + { label: 'PostgreSQL', value: 'postgresql' }, + { label: 'Oracle', value: 'oracle' }, + { label: 'SQL Server', value: 'sqlserver' } + ] + }, + { + label: '项目管理', + options: [ + { label: '电商系统', value: 'ecommerce' }, + { label: 'CRM系统', value: 'crm' }, + { label: 'ERP系统', value: 'erp' }, + { label: '数据分析平台', value: 'analytics' } + ] + } + ]; + + const handleChange = (value: string) => { + setSelectedValue(value); + message.success(`选择了: ${value}`); + }; + + const handleSearch = (value: string) => { + setSearchValue(value); + console.log('搜索关键词:', value); + }; + + return ( + +
+

搜索功能

+ + + + } + placeholder="输入关键词搜索选项" + options={allOptions} + onChange={handleChange} + onSearch={handleSearch} + style={{ width: '400px' }} + /> +
+ 当前选择: {selectedValue || '未选择'} +
+
+ 搜索关键词: {searchValue || '无'} +
+
+
+ + + + } + placeholder="在分组中搜索选项" + options={groupedOptions} + onChange={handleChange} + onSearch={handleSearch} + style={{ width: '400px' }} + /> +
+ 搜索功能会在所有分组中查找匹配的选项 +
+
+
+ + + + } + placeholder="搜索并选择多个用户" + options={allOptions.filter( + (opt) => + opt.label.includes('张') || + opt.label.includes('李') || + opt.label.includes('王') || + opt.label.includes('赵') + )} + onChange={(values) => { + console.log('多选值:', values); + message.success(`选择了 ${values.length} 个用户`); + }} + onSearch={handleSearch} + style={{ width: '400px' }} + /> +
+ 只显示用户相关的选项,支持搜索和多选 +
+
+
+ + +
    +
  • + 自动聚焦: 下拉框打开时搜索输入框自动获得焦点 +
  • +
  • + 实时过滤: 输入关键词时实时过滤选项 +
  • +
  • + 分组搜索: 在分组选项中也能进行搜索 +
  • +
  • + 大小写不敏感: 搜索不区分大小写 +
  • +
  • + 模糊匹配: 支持部分关键词匹配 +
  • +
  • + 搜索回调: 提供 onSearch 回调函数 +
  • +
+
+ + +
    +
  • + 关键词搜索: 输入部分名称即可快速找到选项 +
  • +
  • + 中文搜索: 支持中文关键词搜索 +
  • +
  • + 英文搜索: 支持英文关键词搜索 +
  • +
  • + 数字搜索: 支持数字关键词搜索 +
  • +
  • + 组合搜索: 可以搜索多个关键词 +
  • +
+
+ + + +
+ 用户搜索: + + + + +
+
+ 数据库搜索: + MySQL + PostgreSQL + Oracle +
+
+ 项目搜索: + 电商 + CRM + ERP +
+
+ 点击标签可以快速搜索对应的关键词 +
+
+
+
+
+ ); +}; + +export default SearchFunctionDemo; diff --git a/packages/dms-kit/src/components/CustomSelect/demo/tagsMode.tsx b/packages/dms-kit/src/components/CustomSelect/demo/tagsMode.tsx new file mode 100644 index 000000000..e2a274655 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSelect/demo/tagsMode.tsx @@ -0,0 +1,158 @@ +import React, { useState } from 'react'; +import { CustomSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { message, Space, Card, Tag } from 'antd'; +import { UserOutlined, DatabaseOutlined, ProjectOutlined } from '@ant-design/icons'; + +const TagsModeDemo: React.FC = () => { + const [selectedUsers, setSelectedUsers] = useState([]); + const [selectedDatabases, setSelectedDatabases] = useState([]); + const [selectedProjects, setSelectedProjects] = useState([]); + + const userOptions = [ + { label: '张三', value: 'zhangsan' }, + { label: '李四', value: 'lisi' }, + { label: '王五', value: 'wangwu' }, + { label: '赵六', value: 'zhaoliu' }, + { label: '钱七', value: 'qianqi' }, + { label: '孙八', value: 'sunba' } + ]; + + const databaseOptions = [ + { label: 'MySQL', value: 'mysql' }, + { label: 'PostgreSQL', value: 'postgresql' }, + { label: 'Oracle', value: 'oracle' }, + { label: 'SQL Server', value: 'sqlserver' }, + { label: 'MongoDB', value: 'mongodb' }, + { label: 'Redis', value: 'redis' } + ]; + + const projectOptions = [ + { label: '电商系统', value: 'ecommerce' }, + { label: 'CRM系统', value: 'crm' }, + { label: 'ERP系统', value: 'erp' }, + { label: '数据分析平台', value: 'analytics' }, + { label: '移动应用', value: 'mobile' }, + { label: 'Web应用', value: 'web' } + ]; + + const handleUserChange = (values: string[]) => { + setSelectedUsers(values); + message.success(`用户选择已更新: ${values.join(', ')}`); + }; + + const handleDatabaseChange = (values: string[]) => { + setSelectedDatabases(values); + message.success(`数据库选择已更新: ${values.join(', ')}`); + }; + + const handleProjectChange = (values: string[]) => { + setSelectedProjects(values); + message.success(`项目选择已更新: ${values.join(', ')}`); + }; + + return ( + +
+

标签模式

+ + + + } + placeholder="选择多个用户" + options={userOptions} + onChange={handleUserChange} + style={{ width: '100%' }} + /> +
+ 已选择: + {selectedUsers.map(user => ( + + {userOptions.find(opt => opt.value === user)?.label} + + ))} +
+
+
+ + + + } + placeholder="选择多个数据库" + options={databaseOptions} + onChange={handleDatabaseChange} + style={{ width: '100%' }} + /> +
+ 已选择: + {selectedDatabases.map(db => ( + + {databaseOptions.find(opt => opt.value === db)?.label} + + ))} +
+
+
+ + + + } + placeholder="选择多个项目" + options={projectOptions} + onChange={handleProjectChange} + style={{ width: '100%' }} + /> +
+ 已选择: + {selectedProjects.map(project => ( + + {projectOptions.find(opt => opt.value === project)?.label} + + ))} +
+
+
+ + +
    +
  • 支持多选模式,可以同时选择多个选项
  • +
  • 第一个标签会显示前缀图标
  • +
  • 后续标签使用分隔符显示
  • +
  • 支持搜索和过滤功能
  • +
  • 可以单独删除每个标签
  • +
+
+ + + +
+ 用户: + + {selectedUsers.length} + +
+
+ 数据库: + + {selectedDatabases.length} + +
+
+ 项目: + + {selectedProjects.length} + +
+
+
+
+
+ ); +}; + +export default TagsModeDemo; diff --git a/packages/dms-kit/src/components/CustomSelect/demo/withPrefix.tsx b/packages/dms-kit/src/components/CustomSelect/demo/withPrefix.tsx new file mode 100644 index 000000000..b8fafbbf3 --- /dev/null +++ b/packages/dms-kit/src/components/CustomSelect/demo/withPrefix.tsx @@ -0,0 +1,158 @@ +import React, { useState } from 'react'; +import { CustomSelect, ConfigProvider } from '@actiontech/dms-kit'; +import { message, Space, Card } from 'antd'; +import { + UserOutlined, + DatabaseOutlined, + ProjectOutlined, + TeamOutlined, + SettingOutlined +} from '@ant-design/icons'; + +const WithPrefixDemo: React.FC = () => { + const [selectedValue, setSelectedValue] = useState(); + + const userOptions = [ + { label: '张三', value: 'zhangsan' }, + { label: '李四', value: 'lisi' }, + { label: '王五', value: 'wangwu' }, + { label: '赵六', value: 'zhaoliu' } + ]; + + const databaseOptions = [ + { label: 'MySQL', value: 'mysql' }, + { label: 'PostgreSQL', value: 'postgresql' }, + { label: 'Oracle', value: 'oracle' }, + { label: 'SQL Server', value: 'sqlserver' } + ]; + + const projectOptions = [ + { label: '电商系统', value: 'ecommerce' }, + { label: 'CRM系统', value: 'crm' }, + { label: 'ERP系统', value: 'erp' }, + { label: '数据分析平台', value: 'analytics' } + ]; + + const teamOptions = [ + { label: '开发团队', value: 'dev' }, + { label: '测试团队', value: 'test' }, + { label: '运维团队', value: 'ops' }, + { label: '产品团队', value: 'product' } + ]; + + const settingOptions = [ + { label: '系统配置', value: 'system' }, + { label: '用户配置', value: 'user' }, + { label: '安全配置', value: 'security' }, + { label: '网络配置', value: 'network' } + ]; + + const handleChange = (value: string) => { + setSelectedValue(value); + message.success(`选择了: ${value}`); + }; + + return ( + +
+

带前缀的选择器

+ + + + } + placeholder="选择用户" + options={userOptions} + onChange={handleChange} + style={{ width: '300px' }} + /> + } + placeholder="选择数据库" + options={databaseOptions} + onChange={handleChange} + style={{ width: '300px' }} + /> + } + placeholder="选择项目" + options={projectOptions} + onChange={handleChange} + style={{ width: '300px' }} + /> + + + + + + + + + + + + + } + valuePrefix={} + placeholder="选择用户(值前缀不同)" + options={userOptions} + onChange={handleChange} + style={{ width: '300px' }} + /> +
+ 说明:prefix 显示在选择器上,valuePrefix 显示在选项标签中 +
+
+
+ + + + + } + placeholder="系统设置" + options={[ + { label: '界面设置', value: 'ui' }, + { label: '功能设置', value: 'feature' }, + { label: '权限设置', value: 'permission' } + ]} + onChange={handleChange} + style={{ width: '300px' }} + /> + + + + +
+ 当前选择: {selectedValue || '未选择'} +
+
+
+
+ ); +}; + +export default WithPrefixDemo; diff --git a/packages/shared/lib/components/CustomSelect/index.ts b/packages/dms-kit/src/components/CustomSelect/index.ts similarity index 100% rename from packages/shared/lib/components/CustomSelect/index.ts rename to packages/dms-kit/src/components/CustomSelect/index.ts diff --git a/packages/shared/lib/components/CustomSelect/style.ts b/packages/dms-kit/src/components/CustomSelect/style.ts similarity index 100% rename from packages/shared/lib/components/CustomSelect/style.ts rename to packages/dms-kit/src/components/CustomSelect/style.ts diff --git a/packages/shared/lib/components/DatabaseTypeLogo/DatabaseTypeLogo.test.tsx b/packages/dms-kit/src/components/DatabaseTypeLogo/DatabaseTypeLogo.test.tsx similarity index 100% rename from packages/shared/lib/components/DatabaseTypeLogo/DatabaseTypeLogo.test.tsx rename to packages/dms-kit/src/components/DatabaseTypeLogo/DatabaseTypeLogo.test.tsx diff --git a/packages/shared/lib/components/DatabaseTypeLogo/DatabaseTypeLogo.tsx b/packages/dms-kit/src/components/DatabaseTypeLogo/DatabaseTypeLogo.tsx similarity index 100% rename from packages/shared/lib/components/DatabaseTypeLogo/DatabaseTypeLogo.tsx rename to packages/dms-kit/src/components/DatabaseTypeLogo/DatabaseTypeLogo.tsx diff --git a/packages/shared/lib/components/DatabaseTypeLogo/DatabaseTypeLogo.types.ts b/packages/dms-kit/src/components/DatabaseTypeLogo/DatabaseTypeLogo.types.ts similarity index 100% rename from packages/shared/lib/components/DatabaseTypeLogo/DatabaseTypeLogo.types.ts rename to packages/dms-kit/src/components/DatabaseTypeLogo/DatabaseTypeLogo.types.ts diff --git a/packages/dms-kit/src/components/DatabaseTypeLogo/README.md b/packages/dms-kit/src/components/DatabaseTypeLogo/README.md new file mode 100644 index 000000000..17d38fe08 --- /dev/null +++ b/packages/dms-kit/src/components/DatabaseTypeLogo/README.md @@ -0,0 +1,39 @@ +--- +group: + title: 通用 + order: 1 +--- + +# DatabaseTypeLogo 数据库类型图标 + +## 组件介绍 + +DatabaseTypeLogo 是一个数据库类型图标组件,用于显示不同数据库类型的标识图标。它提供了统一的数据库类型识别和展示功能,适用于数据库管理、连接配置、类型选择等场景。 + +## 何时使用 + +- 需要显示数据库类型标识时 +- 数据库连接配置界面 +- 数据库类型选择器 +- 数据库列表或表格中 +- 数据库相关的文档和说明中 + + +## API 文档 + +### DatabaseTypeLogoProps + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| dbType | 数据库类型 | string | - | +| logoUrl | 图标url | string | - | + +## 设计规范 + +## 更新日志 + +### 1.0.0 +- 初始版本发布 +- 支持主流数据库类型 +- 提供多种尺寸规格 +- 支持样式自定义 diff --git a/packages/shared/lib/components/DatabaseTypeLogo/__snapshots__/DatabaseTypeLogo.test.tsx.snap b/packages/dms-kit/src/components/DatabaseTypeLogo/__snapshots__/DatabaseTypeLogo.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/DatabaseTypeLogo/__snapshots__/DatabaseTypeLogo.test.tsx.snap rename to packages/dms-kit/src/components/DatabaseTypeLogo/__snapshots__/DatabaseTypeLogo.test.tsx.snap diff --git a/packages/shared/lib/components/DatabaseTypeLogo/index.ts b/packages/dms-kit/src/components/DatabaseTypeLogo/index.ts similarity index 100% rename from packages/shared/lib/components/DatabaseTypeLogo/index.ts rename to packages/dms-kit/src/components/DatabaseTypeLogo/index.ts diff --git a/packages/shared/lib/components/DatabaseTypeLogo/style.ts b/packages/dms-kit/src/components/DatabaseTypeLogo/style.ts similarity index 100% rename from packages/shared/lib/components/DatabaseTypeLogo/style.ts rename to packages/dms-kit/src/components/DatabaseTypeLogo/style.ts diff --git a/packages/shared/lib/components/EditText/EditText.test.tsx b/packages/dms-kit/src/components/EditText/EditText.test.tsx similarity index 100% rename from packages/shared/lib/components/EditText/EditText.test.tsx rename to packages/dms-kit/src/components/EditText/EditText.test.tsx diff --git a/packages/shared/lib/components/EditText/EditText.tsx b/packages/dms-kit/src/components/EditText/EditText.tsx similarity index 100% rename from packages/shared/lib/components/EditText/EditText.tsx rename to packages/dms-kit/src/components/EditText/EditText.tsx diff --git a/packages/shared/lib/components/EditText/EditText.types.ts b/packages/dms-kit/src/components/EditText/EditText.types.ts similarity index 100% rename from packages/shared/lib/components/EditText/EditText.types.ts rename to packages/dms-kit/src/components/EditText/EditText.types.ts diff --git a/packages/dms-kit/src/components/EditText/README.md b/packages/dms-kit/src/components/EditText/README.md new file mode 100644 index 000000000..2df63cb67 --- /dev/null +++ b/packages/dms-kit/src/components/EditText/README.md @@ -0,0 +1,141 @@ +--- +group: + title: 通用 + order: 1 +--- + +# EditText 可编辑文本 + +## 组件介绍 + +EditText 是一个可编辑的文本组件,支持在显示模式和编辑模式之间切换。它提供了灵活的文本编辑功能,适用于需要内联编辑的场景,如表格单元格编辑、列表项编辑等。 + +## 何时使用 + +- 需要在显示和编辑模式之间切换的文本内容 +- 表格单元格的内联编辑 +- 列表项的可编辑文本 +- 需要快速编辑而不跳转页面的场景 +- 表单中的动态文本编辑 + +## 代码演示 + +### 基础使用 + + + +### 编辑模式 + + + +## API 文档 + +### EditTextProps + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| value | 文本内容 | `string` | - | +| defaultValue | 默认文本内容 | `string` | - | +| onChange | 文本变化回调 | `(value: string) => void` | - | +| onEdit | 编辑状态变化回调 | `(editing: boolean) => void` | - | +| editing | 是否处于编辑状态 | `boolean` | `false` | +| defaultEditing | 默认是否处于编辑状态 | `boolean` | `false` | +| placeholder | 编辑时的占位符 | `string` | - | +| disabled | 是否禁用编辑 | `boolean` | `false` | +| maxLength | 最大字符长度 | `number` | - | +| showCount | 是否显示字符计数 | `boolean` | `false` | +| autoSize | 自动调整大小 | `boolean \| { minRows: number, maxRows: number }` | `false` | +| className | 自定义类名 | `string` | - | +| style | 自定义样式 | `CSSProperties` | - | + +## 类型定义 + +```typescript +interface EditTextProps { + value?: string; + defaultValue?: string; + onChange?: (value: string) => void; + onEdit?: (editing: boolean) => void; + editing?: boolean; + defaultEditing?: boolean; + placeholder?: string; + disabled?: boolean; + maxLength?: number; + showCount?: boolean; + autoSize?: boolean | { minRows: number; maxRows: number }; + className?: string; + style?: CSSProperties; +} +``` + +## 设计规范 + +### 交互模式 + +- **显示模式**: 文本以只读形式显示,点击可进入编辑模式 +- **编辑模式**: 显示输入框,支持文本编辑,失去焦点或按回车键保存 +- **状态切换**: 支持受控和非受控两种模式 + +### 样式特点 + +- 继承 Ant Design 的输入框样式 +- 支持自定义样式和主题配置 +- 响应式设计,适配不同屏幕尺寸 +- 统一的交互反馈和动画效果 + +## 功能特性 + +### 编辑控制 +- 支持点击进入编辑模式 +- 支持受控和非受控模式 +- 支持禁用编辑功能 +- 支持编辑状态回调 + +### 文本验证 +- 支持最大字符长度限制 +- 支持字符计数显示 +- 支持自定义验证规则 +- 支持错误状态显示 + +### 样式定制 +- 支持自定义类名和样式 +- 支持自动大小调整 +- 支持占位符文本 +- 支持主题系统集成 + +## 使用场景 + +### 表格单元格编辑 +在数据表格中实现单元格的内联编辑功能。 + +### 列表项编辑 +在列表组件中实现项目名称等文本的快速编辑。 + +### 表单动态编辑 +在表单中实现某些字段的动态编辑功能。 + +### 配置项编辑 +在配置界面中实现配置项的快速修改。 + +## 注意事项 + +1. **状态管理**: 合理管理编辑状态,避免状态混乱 +2. **数据同步**: 确保编辑后的数据及时同步到父组件 +3. **用户体验**: 提供清晰的编辑反馈和保存提示 +4. **性能考虑**: 避免在大量数据中使用过多的可编辑组件 + +## 最佳实践 + +1. **合理使用**: 只在真正需要编辑的场景下使用 +2. **状态控制**: 使用受控模式管理编辑状态 +3. **验证规则**: 为重要字段添加适当的验证规则 +4. **用户反馈**: 提供清晰的编辑成功/失败提示 +5. **键盘支持**: 支持回车保存、ESC 取消等快捷键 + +## 更新日志 + +### 1.0.0 +- 初始版本发布 +- 支持基础的文本编辑功能 +- 支持显示/编辑模式切换 +- 提供完整的 API 接口 diff --git a/packages/shared/lib/components/EditText/__snapshots__/EditText.test.tsx.snap b/packages/dms-kit/src/components/EditText/__snapshots__/EditText.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/EditText/__snapshots__/EditText.test.tsx.snap rename to packages/dms-kit/src/components/EditText/__snapshots__/EditText.test.tsx.snap diff --git a/packages/dms-kit/src/components/EditText/demo/basic.tsx b/packages/dms-kit/src/components/EditText/demo/basic.tsx new file mode 100644 index 000000000..ed2b1caab --- /dev/null +++ b/packages/dms-kit/src/components/EditText/demo/basic.tsx @@ -0,0 +1,327 @@ +import React, { useState } from 'react'; +import { + Card, + Space, + Typography, + Divider, + Button, + Row, + Col, + Tag, + Alert +} from 'antd'; +import { EditText, ConfigProvider } from '@actiontech/dms-kit'; +import { + EditOutlined, + SaveOutlined, + CloseOutlined, + EyeOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; + +const BasicDemo: React.FC = () => { + const [userName, setUserName] = useState('张三'); + const [userEmail, setUserEmail] = useState('zhangsan@example.com'); + const [userBio, setUserBio] = useState( + '前端开发工程师,专注于 React 和 TypeScript 开发' + ); + const [companyName, setCompanyName] = useState('科技有限公司'); + + return ( + +
+ 基础使用 + + 演示 EditText 组件的基本用法,包括文本编辑、状态管理和数据同步。 + + + + + +
+
+ 用户名: +
+ +
+
+ + +
+ 邮箱: +
+ +
+
+ + + +
+ 个人简介: +
+ +
+
+ +
+ 公司名称: +
+ +
+
+ + + + + + +
+ +
+ 点击编辑 +
+ + 点击文本进入编辑模式 + +
+ + +
+ +
+ 保存更改 +
+ + 按回车键或失去焦点保存 + +
+ + +
+ +
+ 取消编辑 +
+ + 按 ESC 键取消编辑 + +
+ + + + + + + +
+
+ {userName} +
+ 用户名 +
+ + +
+
+ {userEmail} +
+ 邮箱 +
+ + +
+
+ {companyName} +
+ 公司 +
+ + +
+
+ {userBio.length} +
+ 简介字符数 +
+ + + + + +
+ 个人简介预览: +
+ {userBio || '暂无简介'} +
+
+ + + + +
+

功能特点:

+
    +
  • + 点击编辑: 点击文本即可进入编辑模式 +
  • +
  • + 自动保存: 失去焦点或按回车键自动保存 +
  • +
  • + 支持多行: 支持单行和多行文本编辑 +
  • +
  • + 实时同步: 编辑内容实时同步到父组件 +
  • +
+
+ + + +
+

使用场景:

+
    +
  • 用户资料编辑:快速修改用户信息
  • +
  • 表格单元格编辑:内联编辑表格数据
  • +
  • 配置项修改:快速调整系统配置
  • +
  • 内容管理:编辑文章标题、描述等
  • +
+
+ + + +
+

操作说明:

+
    +
  • + 进入编辑: 点击文本内容 +
  • +
  • + 保存更改: 按回车键或失去焦点 +
  • +
  • + 取消编辑: 按 ESC 键 +
  • +
  • + 多行编辑: 支持自动换行和手动换行 +
  • +
+
+ + + ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/EditText/demo/editMode.tsx b/packages/dms-kit/src/components/EditText/demo/editMode.tsx new file mode 100644 index 000000000..1bfa1398a --- /dev/null +++ b/packages/dms-kit/src/components/EditText/demo/editMode.tsx @@ -0,0 +1,425 @@ +import React, { useState } from 'react'; +import { + Card, + Space, + Typography, + Divider, + Switch, + Button, + Row, + Col, + Tag, + Alert, + Select +} from 'antd'; +import { EditText, ConfigProvider } from '@actiontech/dms-kit'; +import { + EditOutlined, + SaveOutlined, + CloseOutlined, + LockOutlined, + UnlockOutlined, + EyeOutlined, + EyeInvisibleOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; +const { Option } = Select; + +const EditModeDemo: React.FC = () => { + const [editingMode, setEditingMode] = useState<'auto' | 'controlled'>('auto'); + const [controlledEditing, setControlledEditing] = useState(false); + const [disabled, setDisabled] = useState(false); + const [showPlaceholder, setShowPlaceholder] = useState(true); + + // 受控模式的数据 + const [controlledText, setControlledText] = useState('这是受控模式的文本'); + const [controlledEditingState, setControlledEditingState] = useState(false); + + // 自动模式的数据 + const [autoText, setAutoText] = useState('这是自动模式的文本'); + const [autoText2, setAutoText2] = useState('支持占位符的文本'); + + // 处理受控模式的编辑状态变化 + const handleEditChange = (editing: boolean) => { + setControlledEditingState(editing); + }; + + // 处理受控模式的文本变化 + const handleTextChange = (value: string) => { + setControlledText(value); + }; + + return ( + +
+ 编辑模式 + + 演示 EditText + 组件的不同编辑模式,包括自动模式和受控模式,以及编辑状态的控制。 + + + + +
+
+ 编辑模式: + +
+ + +
+ 禁用状态: + + + {disabled ? '已禁用' : '已启用'} + +
+ + +
+ 显示占位符: + + + {showPlaceholder ? '显示' : '隐藏'} + +
+ + + + {editingMode === 'controlled' && ( +
+ 受控编辑状态: + + + {controlledEditing ? '编辑中' : '显示中'} + +
+ )} + + + + {/* 左侧:自动模式 */} + + + + 自动模式 + 默认 + + } + style={{ marginBottom: '20px' }} + > +
+ 基础文本编辑: +
+ +
+
+ +
+ 带占位符的编辑: +
+ +
+
+ + + +
+ + 自动模式特点: +
    +
  • 点击文本自动进入编辑模式
  • +
  • 失去焦点或按回车自动保存
  • +
  • 按 ESC 键取消编辑
  • +
  • 编辑状态由组件内部管理
  • +
+
+
+
+ + + {/* 右侧:受控模式 */} + + + + 受控模式 + 可控 + + } + style={{ marginBottom: '20px' }} + > +
+ 受控文本编辑: +
+ +
+
+ +
+ 编辑状态控制: +
+ + + + + +
+
+ + + +
+ + 受控模式特点: +
    +
  • 编辑状态由外部控制
  • +
  • 可以精确控制何时进入/退出编辑
  • +
  • 支持复杂的编辑逻辑
  • +
  • 适合需要验证或确认的场景
  • +
+
+
+
+ + + + + + +
+
+ {editingMode} +
+ 当前模式 +
+ + +
+
+ {controlledEditingState ? '编辑中' : '显示中'} +
+ 受控状态 +
+ + +
+
+ {disabled ? '已禁用' : '已启用'} +
+ 组件状态 +
+ + + + + +
+ 当前文本内容: + +
+
+ 自动模式: +
+ {autoText || '暂无内容'} +
+
+ + +
+ 受控模式: +
+ {controlledText || '暂无内容'} +
+
+ + + + + + + +
+

编辑模式对比:

+
    +
  • + 自动模式: 适合简单的内联编辑,用户体验流畅 +
  • +
  • + 受控模式: 适合需要精确控制的复杂编辑场景 +
  • +
  • + 状态管理: + 自动模式由组件内部管理,受控模式由外部控制 +
  • +
  • + 适用场景: 根据业务需求选择合适的编辑模式 +
  • +
+
+ + + +
+

使用建议:

+
    +
  • 对于简单的文本编辑,推荐使用自动模式
  • +
  • 对于需要验证、确认或复杂逻辑的编辑,使用受控模式
  • +
  • 合理使用禁用状态,避免用户误操作
  • +
  • 提供清晰的占位符文本,提升用户体验
  • +
+
+ + + ); +}; + +export default EditModeDemo; diff --git a/packages/shared/lib/components/EditText/index.ts b/packages/dms-kit/src/components/EditText/index.ts similarity index 100% rename from packages/shared/lib/components/EditText/index.ts rename to packages/dms-kit/src/components/EditText/index.ts diff --git a/packages/shared/lib/components/EditText/style.ts b/packages/dms-kit/src/components/EditText/style.ts similarity index 100% rename from packages/shared/lib/components/EditText/style.ts rename to packages/dms-kit/src/components/EditText/style.ts diff --git a/packages/shared/lib/components/EditableSelect/EditableSelect.tsx b/packages/dms-kit/src/components/EditableSelect/EditableSelect.tsx similarity index 100% rename from packages/shared/lib/components/EditableSelect/EditableSelect.tsx rename to packages/dms-kit/src/components/EditableSelect/EditableSelect.tsx diff --git a/packages/dms-kit/src/components/EditableSelect/README.md b/packages/dms-kit/src/components/EditableSelect/README.md new file mode 100644 index 000000000..556bc9cf7 --- /dev/null +++ b/packages/dms-kit/src/components/EditableSelect/README.md @@ -0,0 +1,268 @@ +--- +group: + title: 业务组件 + order: 3 +--- + +# EditableSelect 可编辑选择器 + +功能强大的可编辑选择器组件,支持选择、添加、编辑和删除选项,适用于需要动态管理选项列表的场景。 + +## 何时使用 + +- 需要动态管理选项列表时 +- 用户需要自定义选项内容时 +- 构建标签管理、类别管理等功能时 +- 需要实时编辑下拉选项时 +- 表单中需要可扩展的选择字段时 + +## 代码演示 + +### 基础用法 + + + + +### 异步操作 + + + +### 表单集成 + + + +## API + +### EditableSelect + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| value | 当前选中的值 | `EditableSelectValue` | - | - | +| onChange | 选择变化时的回调 | `(value: EditableSelectValue) => void` | - | - | +| options | 选项数据源 | `EditableSelectOption[]` | `[]` | - | +| onAdd | 添加新选项时的回调 | `(value: string) => void` | - | - | +| onUpdate | 更新选项时的回调 | `(newData: EditableSelectOption) => void` | - | - | +| onDelete | 删除选项时的回调 | `(item: EditableSelectOption) => Promise \| void` | - | - | +| addable | 是否允许添加新选项 | `boolean` | `true` | - | +| updatable | 是否允许编辑选项 | `boolean` | `true` | - | +| deletable | 是否允许删除选项 | `boolean` | `true` | - | +| addButtonText | 添加按钮的文本 | `string` | - | - | +| placeholder | 选择框占位符 | `string` | - | - | +| disabled | 是否禁用 | `boolean` | `false` | - | +| loading | 是否显示加载状态 | `boolean` | `false` | - | +| deletionConfirmTitle | 删除确认弹窗的标题 | `ReactNode \| (option: EditableSelectOption) => ReactNode` | - | - | +| errorMessage | 错误信息,显示时会标红边框 | `string` | - | - | + +### 数据结构 + +#### EditableSelectValue + +```typescript +type EditableSelectValue = string | number; +``` + +#### EditableSelectOption + +```typescript +interface EditableSelectOption { + value: EditableSelectValue; + label: string; +} +``` + +## 功能特性 + +### 基础功能 + +- **选择选项**: 点击选项进行选择 +- **添加选项**: 点击 + 按钮添加新选项 +- **编辑选项**: 点击编辑图标修改选项名称 +- **删除选项**: 点击删除图标移除选项 + +### 状态管理 + +- **加载状态**: 显示加载动画,禁用所有操作 +- **禁用状态**: 完全禁用组件交互 +- **错误状态**: 显示错误信息和错误样式 +- **空状态**: 无选项时的空状态展示 + +### 权限控制 + +- **addable**: 控制是否显示添加按钮 +- **updatable**: 控制是否显示编辑按钮 +- **deletable**: 控制是否显示删除按钮 + +### 交互体验 + +- **即时编辑**: 点击编辑后直接在下拉框内编辑 +- **确认删除**: 支持删除前确认弹窗 +- **键盘支持**: 编辑时支持 Enter 保存,Esc 取消 +- **自动聚焦**: 编辑模式自动聚焦输入框 + +## 设计规范 + +### 布局结构 + +- **触发器**: 显示当前选中值的触发区域 +- **下拉面板**: 包含选项列表和操作按钮的面板 +- **选项行**: 每个选项包含内容、编辑和删除按钮 +- **添加区域**: 底部的添加新选项区域 + +### 交互规范 + +- **悬停效果**: 选项悬停时显示操作按钮 +- **编辑模式**: 点击编辑后替换为输入框 +- **确认机制**: 删除操作需要确认 +- **状态反馈**: 操作成功/失败的及时反馈 + +### 样式特性 + +- 统一的边框和圆角设计 +- 清晰的状态区分(选中、悬停、禁用) +- 错误状态的红色边框提示 +- 加载状态的动画效果 + +## 使用场景 + +### 1. 标签管理 + +```typescript +// 项目标签管理 + +``` + +### 2. 环境配置 + +```typescript +// 部署环境管理 + +``` + +### 3. 分类管理 + +```typescript +// 文档分类管理 + +``` + +## 最佳实践 + +### 异步操作处理 + +```typescript +const handleAsyncAdd = async (name: string) => { + setLoading(true); + try { + const newOption = await api.createOption(name); + setOptions(prev => [...prev, newOption]); + message.success('添加成功'); + } catch (error) { + message.error('添加失败'); + } finally { + setLoading(false); + } +}; +``` + +### 删除前验证 + +```typescript +const handleDelete = async (option: EditableSelectOption): Promise => { + try { + await api.deleteOption(option.value); + setOptions(prev => prev.filter(opt => opt.value !== option.value)); + return true; // 删除成功 + } catch (error) { + message.error('删除失败'); + return false; // 阻止删除 + } +}; +``` + +### 表单集成 + +```typescript + + + +``` + +### 错误处理 + +```typescript +const [errorMessage, setErrorMessage] = useState(''); + +const handleAdd = (name: string) => { + if (name.length < 2) { + setErrorMessage('名称至少需要2个字符'); + return; + } + + if (options.some(opt => opt.label === name)) { + setErrorMessage('名称已存在'); + return; + } + + // 添加成功,清除错误 + setErrorMessage(''); + // ... 添加逻辑 +}; + + +``` + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `onDelete` 回调支持返回 `Promise` 来控制删除是否成功 +3. 编辑和删除操作会自动阻止事件冒泡,避免触发选择 +4. 建议为异步操作提供适当的加载状态和错误处理 +5. `errorMessage` 属性设置后会显示错误样式,需要手动清除 +6. 删除确认弹窗支持自定义内容,可以是字符串或 React 节点 +7. 建议为选项设置有意义的 `value` 值,确保唯一性 + +## 更新日志 + +- **1.0.0**: 初始版本 + - 支持选择、添加、编辑、删除选项 + - 提供完整的状态管理(加载、禁用、错误) + - 支持权限控制(addable、updatable、deletable) + - 内置确认删除和错误处理机制 + - 完整的键盘交互支持 + - 响应式设计和主题系统集成 diff --git a/packages/shared/lib/components/EditableSelect/__tests__/EditableSelect.test.tsx b/packages/dms-kit/src/components/EditableSelect/__tests__/EditableSelect.test.tsx similarity index 100% rename from packages/shared/lib/components/EditableSelect/__tests__/EditableSelect.test.tsx rename to packages/dms-kit/src/components/EditableSelect/__tests__/EditableSelect.test.tsx diff --git a/packages/shared/lib/components/EditableSelect/__tests__/__snapshots__/EditableSelect.test.tsx.snap b/packages/dms-kit/src/components/EditableSelect/__tests__/__snapshots__/EditableSelect.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/EditableSelect/__tests__/__snapshots__/EditableSelect.test.tsx.snap rename to packages/dms-kit/src/components/EditableSelect/__tests__/__snapshots__/EditableSelect.test.tsx.snap diff --git a/packages/dms-kit/src/components/EditableSelect/demo/async.tsx b/packages/dms-kit/src/components/EditableSelect/demo/async.tsx new file mode 100644 index 000000000..54c2262ab --- /dev/null +++ b/packages/dms-kit/src/components/EditableSelect/demo/async.tsx @@ -0,0 +1,151 @@ +import React, { useState } from 'react'; +import { + EditableSelect, + ConfigProvider, + EditableSelectOption, + EditableSelectValue +} from '@actiontech/dms-kit'; +import { message } from 'antd'; + +const EditableSelectAsyncDemo = () => { + const [value, setValue] = useState(''); + const [options, setOptions] = useState([ + { value: 'tag1', label: '前端开发' }, + { value: 'tag2', label: '后端开发' }, + { value: 'tag3', label: '数据库管理' } + ]); + const [loading, setLoading] = useState(false); + + // 模拟异步添加 + const handleAsyncAdd = async (label: string) => { + setLoading(true); + try { + // 模拟API调用 + await new Promise((resolve) => setTimeout(resolve, 1500)); + + // 模拟验证重复 + if (options.some((opt) => opt.label === label)) { + message.error('标签名称已存在'); + return; + } + + const newOption: EditableSelectOption = { + value: `tag_${Date.now()}`, + label: label + }; + + setOptions((prev) => [...prev, newOption]); + setValue(newOption.value as string); + message.success(`成功添加标签: ${label}`); + } catch (error) { + message.error('添加失败,请重试'); + } finally { + setLoading(false); + } + }; + + // 模拟异步更新 + const handleAsyncUpdate = async (updatedOption: EditableSelectOption) => { + setLoading(true); + try { + // 模拟API调用 + await new Promise((resolve) => setTimeout(resolve, 1000)); + + setOptions((prev) => + prev.map((opt) => + opt.value === updatedOption.value + ? { ...opt, label: updatedOption.label } + : opt + ) + ); + message.success(`成功更新标签: ${updatedOption.label}`); + } catch (error) { + message.error('更新失败,请重试'); + } finally { + setLoading(false); + } + }; + + // 模拟异步删除(带确认) + const handleAsyncDelete = async ( + optionToDelete: EditableSelectOption + ): Promise => { + setLoading(true); + try { + // 模拟API调用 + await new Promise((resolve) => setTimeout(resolve, 800)); + + // 模拟删除验证 + if (optionToDelete.value === 'tag1') { + message.error('系统标签不可删除'); + return false; + } + + setOptions((prev) => + prev.filter((opt) => opt.value !== optionToDelete.value) + ); + if (value === optionToDelete.value) { + setValue(''); + } + message.success(`成功删除标签: ${optionToDelete.label}`); + return true; + } catch (error) { + message.error('删除失败,请重试'); + return false; + } finally { + setLoading(false); + } + }; + + return ( + +
+

异步操作演示

+

+ 演示与后端API交互的场景,包括异步的添加、更新和删除操作 +

+ + setValue(val)} + options={options} + onAdd={handleAsyncAdd} + onUpdate={handleAsyncUpdate} + onDelete={handleAsyncDelete} + loading={loading} + placeholder="选择或添加技能标签" + addButtonText="添加技能标签" + deletionConfirmTitle="确定要删除这个技能标签吗?" + /> + +
+

操作说明:

+
    +
  • 添加操作会验证名称重复,有 1.5 秒延迟
  • +
  • 更新操作有 1 秒延迟模拟网络请求
  • +
  • 删除操作有 0.8 秒延迟,"前端开发"标签无法删除
  • +
  • 所有操作都有加载状态和错误处理
  • +
+
+ +
+

+ 当前选择:{' '} + {value ? options.find((opt) => opt.value === value)?.label : '无'} +

+

可用标签: {options.map((opt) => opt.label).join(', ')}

+
+
+
+ ); +}; + +export default EditableSelectAsyncDemo; diff --git a/packages/dms-kit/src/components/EditableSelect/demo/basic.tsx b/packages/dms-kit/src/components/EditableSelect/demo/basic.tsx new file mode 100644 index 000000000..46cdfc364 --- /dev/null +++ b/packages/dms-kit/src/components/EditableSelect/demo/basic.tsx @@ -0,0 +1,84 @@ +import React, { useState } from 'react'; +import { + EditableSelect, + ConfigProvider, + EditableSelectOption +} from '@actiontech/dms-kit'; +import { message } from 'antd'; + +const EditableSelectBasicDemo = () => { + const [value, setValue] = useState('option1'); + const [options, setOptions] = useState([ + { value: 'option1', label: '选项 1' }, + { value: 'option2', label: '选项 2' }, + { value: 'option3', label: '选项 3' } + ]); + + const handleChange = (newValue: string | number) => { + setValue(newValue as string); + message.success( + `选择了: ${options.find((opt) => opt.value === newValue)?.label}` + ); + }; + + const handleAdd = (label: string) => { + const newOption: EditableSelectOption = { + value: `option_${Date.now()}`, + label: label + }; + setOptions((prev) => [...prev, newOption]); + message.success(`添加成功: ${label}`); + }; + + const handleUpdate = (updatedOption: EditableSelectOption) => { + setOptions((prev) => + prev.map((opt) => + opt.value === updatedOption.value + ? { ...opt, label: updatedOption.label } + : opt + ) + ); + message.success(`更新成功: ${updatedOption.label}`); + }; + + const handleDelete = (optionToDelete: EditableSelectOption) => { + setOptions((prev) => + prev.filter((opt) => opt.value !== optionToDelete.value) + ); + if (value === optionToDelete.value) { + setValue(''); + } + message.success(`删除成功: ${optionToDelete.label}`); + }; + + return ( + +
+

基础可编辑选择器

+ + +
+

当前选择的值: {value || '无'}

+

支持的操作:

+
    +
  • 点击选择选项
  • +
  • 点击 + 号添加新选项
  • +
  • 点击编辑图标修改选项名称
  • +
  • 点击删除图标移除选项
  • +
+
+
+
+ ); +}; + +export default EditableSelectBasicDemo; diff --git a/packages/dms-kit/src/components/EditableSelect/demo/formIntegration.tsx b/packages/dms-kit/src/components/EditableSelect/demo/formIntegration.tsx new file mode 100644 index 000000000..390cba459 --- /dev/null +++ b/packages/dms-kit/src/components/EditableSelect/demo/formIntegration.tsx @@ -0,0 +1,190 @@ +import React, { useState } from 'react'; +import { + EditableSelect, + ConfigProvider, + BasicButton, + EditableSelectOption +} from '@actiontech/dms-kit'; +import { Form, Input, Switch, Card, message } from 'antd'; + +interface ProjectFormData { + name: string; + description: string; + environment: string; + isPublic: boolean; + tags: string[]; +} + +const FormIntegrationDemo = () => { + const [form] = Form.useForm(); + const [environments, setEnvironments] = useState([ + { value: 'dev', label: '开发环境' }, + { value: 'test', label: '测试环境' }, + { value: 'staging', label: '预发环境' }, + { value: 'prod', label: '生产环境' } + ]); + + const [tags, setTags] = useState([ + { value: 'frontend', label: '前端' }, + { value: 'backend', label: '后端' }, + { value: 'database', label: '数据库' }, + { value: 'mobile', label: '移动端' } + ]); + + const [submitLoading, setSubmitLoading] = useState(false); + + const handleAddEnvironment = (name: string) => { + const newEnv: EditableSelectOption = { + value: name.toLowerCase().replace(/\s+/g, '_'), + label: name + }; + setEnvironments((prev) => [...prev, newEnv]); + message.success(`添加环境: ${name}`); + }; + + const handleUpdateEnvironment = (updatedEnv: EditableSelectOption) => { + setEnvironments((prev) => + prev.map((env) => + env.value === updatedEnv.value + ? { ...env, label: updatedEnv.label } + : env + ) + ); + }; + + const handleDeleteEnvironment = (envToDelete: EditableSelectOption) => { + setEnvironments((prev) => + prev.filter((env) => env.value !== envToDelete.value) + ); + // 清空表单中的选择 + const currentEnv = form.getFieldValue('environment'); + if (currentEnv === envToDelete.value) { + form.setFieldValue('environment', undefined); + } + }; + + const handleAddTag = (name: string) => { + const newTag: EditableSelectOption = { + value: name.toLowerCase().replace(/\s+/g, '_'), + label: name + }; + setTags((prev) => [...prev, newTag]); + }; + + const handleSubmit = async (values: ProjectFormData) => { + setSubmitLoading(true); + try { + // 模拟提交 + await new Promise((resolve) => setTimeout(resolve, 2000)); + message.success('项目创建成功!'); + + // 获取对应的标签名称 + const selectedEnv = environments.find( + (env) => env.value === values.environment + ); + + console.log('表单数据:', { + ...values, + environmentLabel: selectedEnv?.label + }); + + // 重置表单 + form.resetFields(); + } catch (error) { + message.error('提交失败,请重试'); + } finally { + setSubmitLoading(false); + } + }; + + return ( + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + 创建项目 + + form.resetFields()}>重置 + + +
+ + +
    +
  • 在"部署环境"字段中,你可以添加、编辑和删除环境配置
  • +
  • 在"项目标签"字段中,只允许添加新标签,不能修改或删除
  • +
  • 表单验证会确保必填字段已填写
  • +
  • 提交时会显示完整的表单数据,包括选择的标签名称
  • +
+
+
+
+ ); +}; + +export default FormIntegrationDemo; diff --git a/packages/shared/lib/components/EditableSelect/index.ts b/packages/dms-kit/src/components/EditableSelect/index.ts similarity index 100% rename from packages/shared/lib/components/EditableSelect/index.ts rename to packages/dms-kit/src/components/EditableSelect/index.ts diff --git a/packages/shared/lib/components/EditableSelect/index.type.ts b/packages/dms-kit/src/components/EditableSelect/index.type.ts similarity index 100% rename from packages/shared/lib/components/EditableSelect/index.type.ts rename to packages/dms-kit/src/components/EditableSelect/index.type.ts diff --git a/packages/shared/lib/components/EditableSelect/style.ts b/packages/dms-kit/src/components/EditableSelect/style.ts similarity index 100% rename from packages/shared/lib/components/EditableSelect/style.ts rename to packages/dms-kit/src/components/EditableSelect/style.ts diff --git a/packages/shared/lib/components/EmptyBox/EmptyBox.test.tsx b/packages/dms-kit/src/components/EmptyBox/EmptyBox.test.tsx similarity index 100% rename from packages/shared/lib/components/EmptyBox/EmptyBox.test.tsx rename to packages/dms-kit/src/components/EmptyBox/EmptyBox.test.tsx diff --git a/packages/shared/lib/components/EmptyBox/EmptyBox.tsx b/packages/dms-kit/src/components/EmptyBox/EmptyBox.tsx similarity index 100% rename from packages/shared/lib/components/EmptyBox/EmptyBox.tsx rename to packages/dms-kit/src/components/EmptyBox/EmptyBox.tsx diff --git a/packages/shared/lib/components/EmptyBox/EmptyBox.types.ts b/packages/dms-kit/src/components/EmptyBox/EmptyBox.types.ts similarity index 100% rename from packages/shared/lib/components/EmptyBox/EmptyBox.types.ts rename to packages/dms-kit/src/components/EmptyBox/EmptyBox.types.ts diff --git a/packages/dms-kit/src/components/EmptyBox/README.md b/packages/dms-kit/src/components/EmptyBox/README.md new file mode 100644 index 000000000..a2ca6d997 --- /dev/null +++ b/packages/dms-kit/src/components/EmptyBox/README.md @@ -0,0 +1,114 @@ +--- +group: + title: 通用 + order: 1 +--- + +# EmptyBox 空盒子 + +## 组件介绍 + +EmptyBox 是一个条件渲染组件,用于根据条件决定是否渲染其子组件。它提供了灵活的渲染控制机制,支持强制渲染、销毁策略和动画效果。 + +## 何时使用 + +- 需要根据条件控制组件渲染时 +- 需要优化性能,避免不必要的组件渲染时 +- 需要实现懒加载或按需渲染功能时 +- 需要控制组件的显示/隐藏状态时 + +## 代码演示 + +### 基础使用 + + + + +### 动画效果 + + + + +## API 文档 + +### EmptyBoxProps + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| if | 是否渲染子组件 | `boolean` | `true` | +| children | 子组件内容 | `ReactNode` | - | + +## 类型定义 + +```typescript +interface EmptyBoxProps { + if: boolean; + children: ReactNode; +} +``` + +## 设计规范 + +### 渲染逻辑 + +- 当 `if` 为 `true` 时,渲染子组件 +- 当 `if` 为 `false` 时,不渲染任何内容 +- 支持动态条件变化,实时响应状态更新 + +### 性能特点 + +- 条件为 `false` 时完全不渲染,节省内存和计算资源 +- 支持 React 的优化机制,如 React.memo 等 +- 适合在列表渲染、条件显示等场景中使用 + +## 功能特性 + +### 条件渲染 +- 基于布尔值的简单条件控制 +- 支持动态条件变化 +- 实时响应状态更新 + +### 性能优化 +- 条件不满足时完全不渲染 +- 减少不必要的 DOM 操作 +- 支持 React 性能优化 + +### 灵活配置 +- 简洁的 API 设计 +- 易于集成到现有代码中 +- 支持复杂的条件逻辑 + +## 使用场景 + +### 列表项条件渲染 +在列表渲染中,根据数据状态决定是否显示某些项目。 + +### 权限控制 +根据用户权限决定是否显示某些功能组件。 + +### 状态依赖渲染 +根据应用状态决定是否渲染相关组件。 + +### 性能优化 +避免渲染不必要的组件,提升应用性能。 + +## 注意事项 + +1. **条件变化频率**: 避免频繁切换条件,可能影响性能 +2. **子组件状态**: 条件变化时子组件状态会重置 +3. **事件处理**: 确保条件变化时正确处理相关事件 +4. **样式继承**: 注意子组件的样式继承关系 + +## 最佳实践 + +1. **合理使用条件**: 只在真正需要时使用条件渲染 +2. **性能考虑**: 对于复杂组件,考虑使用 React.memo 优化 +3. **状态管理**: 合理管理条件相关的状态 +4. **测试覆盖**: 确保条件变化的各种情况都有测试覆盖 + +## 更新日志 + +### 1.0.0 +- 初始版本发布 +- 支持基础的条件渲染功能 +- 提供简洁的 API 接口 diff --git a/packages/dms-kit/src/components/EmptyBox/demo/animation.tsx b/packages/dms-kit/src/components/EmptyBox/demo/animation.tsx new file mode 100644 index 000000000..2b8683963 --- /dev/null +++ b/packages/dms-kit/src/components/EmptyBox/demo/animation.tsx @@ -0,0 +1,369 @@ +import React, { useState, useEffect } from 'react'; +import { + Card, + Space, + Typography, + Divider, + Switch, + Button, + Row, + Col, + Tag, + Slider, + Select +} from 'antd'; +import { EmptyBox, ConfigProvider } from '@actiontech/dms-kit'; +import { + PlayCircleOutlined, + PauseCircleOutlined, + ReloadOutlined, + RocketOutlined, + HeartOutlined, + StarOutlined, + ThunderboltOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; +const { Option } = Select; + +const AnimationDemo: React.FC = () => { + const [showComponent, setShowComponent] = useState(false); + const [animationType, setAnimationType] = useState< + 'fade' | 'slide' | 'zoom' | 'bounce' + >('fade'); + const [animationDuration, setAnimationDuration] = useState(300); + const [autoPlay, setAutoPlay] = useState(false); + const [autoPlaySpeed, setAutoPlaySpeed] = useState(2000); + const [componentCount, setComponentCount] = useState(1); + + // 自动播放逻辑 + useEffect(() => { + let timer: NodeJS.Timeout; + if (autoPlay) { + timer = setInterval(() => { + setShowComponent((prev) => !prev); + }, autoPlaySpeed); + } + return () => { + if (timer) clearInterval(timer); + }; + }, [autoPlay, autoPlaySpeed]); + + // 生成多个组件 + const generateComponents = () => { + const components = []; + for (let i = 0; i < componentCount; i++) { + components.push( + + {i === 0 && } + {i === 1 && } + {i === 2 && } + {i === 3 && } + 组件 {i + 1} + + } + size="small" + style={{ + backgroundColor: + i === 0 + ? '#f0f9ff' + : i === 1 + ? '#fff0f6' + : i === 2 + ? '#fff7e6' + : '#f9f0ff', + borderColor: + i === 0 + ? '#1890ff' + : i === 1 + ? '#eb2f96' + : i === 2 + ? '#faad14' + : '#722ed1', + marginBottom: '16px' + }} + > +
+ + 这是第 {i + 1} 个组件,展示了 EmptyBox 的动画效果。 + + +
+
+ 组件ID: + + comp_{i + 1} + +
+
+ 动画类型: + + {animationType} + +
+ + +
+ 动画时长: + + {animationDuration}ms + +
+
+ 状态: + + {showComponent ? '显示' : '隐藏'} + +
+ + + + + ); + } + return components; + }; + + // 动画样式 + const getAnimationStyle = () => { + const baseStyle = { + transition: `all ${animationDuration}ms ease-in-out` + }; + + switch (animationType) { + case 'fade': + return { + ...baseStyle, + opacity: showComponent ? 1 : 0, + transform: 'scale(1)' + }; + case 'slide': + return { + ...baseStyle, + transform: showComponent ? 'translateX(0)' : 'translateX(-100%)', + opacity: showComponent ? 1 : 0 + }; + case 'zoom': + return { + ...baseStyle, + transform: showComponent ? 'scale(1)' : 'scale(0.8)', + opacity: showComponent ? 1 : 0 + }; + case 'bounce': + return { + ...baseStyle, + transform: showComponent ? 'translateY(0)' : 'translateY(-20px)', + opacity: showComponent ? 1 : 0 + }; + default: + return baseStyle; + } + }; + + return ( + +
+ 动画效果 + + 演示 EmptyBox 组件的动画效果,包括不同的动画类型和过渡效果。 + + + + +
+
+ 动画类型: + +
+ +
+ 动画时长: + + + {animationDuration}ms + +
+ +
+ 组件数量: + + + {componentCount} 个 + +
+ + + +
+ 自动播放: + + + {autoPlay ? '开启' : '关闭'} + +
+ +
+ 播放速度: + + + {autoPlaySpeed}ms + +
+ +
+ 当前状态: + + {showComponent ? '显示' : '隐藏'} + +
+ + + + + + + + + + + + + +
+

调整上方配置,观察组件的动画效果:

+
+ +
+ {generateComponents()} +
+ + {/* 状态提示 */} +
+ + 动画类型: {animationType} | 时长: {animationDuration}ms | + 自动播放: {autoPlay ? '开启' : '关闭'} + +
+
+ + + +
+

动画类型说明:

+
    +
  • + 淡入淡出 (fade): 透明度渐变,视觉效果柔和 +
  • +
  • + 滑动 (slide): 水平滑动效果,适合横向布局 +
  • +
  • + 缩放 (zoom): 大小缩放效果,增强视觉冲击力 +
  • +
  • + 弹跳 (bounce): 垂直弹跳效果,增加趣味性 +
  • +
+
+ + + +
+

性能优化:

+
    +
  • 使用 CSS transition 实现动画,性能更好
  • +
  • 合理设置动画时长,避免过长影响用户体验
  • +
  • 支持自动播放功能,适合展示和演示场景
  • +
  • 组件数量可配置,便于测试不同场景下的性能
  • +
+
+ + + +
+

使用建议:

+
    +
  • 根据应用风格选择合适的动画类型
  • +
  • 在移动端考虑使用较短的动画时长
  • +
  • 避免同时使用过多动画,可能影响性能
  • +
  • 为不同组件设置不同的动画效果,提升用户体验
  • +
+
+ + + ); +}; + +export default AnimationDemo; diff --git a/packages/dms-kit/src/components/EmptyBox/demo/basic.tsx b/packages/dms-kit/src/components/EmptyBox/demo/basic.tsx new file mode 100644 index 000000000..7e6e1ffcd --- /dev/null +++ b/packages/dms-kit/src/components/EmptyBox/demo/basic.tsx @@ -0,0 +1,304 @@ +import React, { useState } from 'react'; +import { + Card, + Space, + Typography, + Divider, + Switch, + Button, + Row, + Col, + Tag +} from 'antd'; +import { EmptyBox, ConfigProvider } from '@actiontech/dms-kit'; +import { + EyeOutlined, + EyeInvisibleOutlined, + UserOutlined, + SettingOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; + +const BasicDemo: React.FC = () => { + const [showUserInfo, setShowUserInfo] = useState(true); + const [showSettings, setShowSettings] = useState(false); + const [showStatistics, setShowStatistics] = useState(true); + + return ( + +
+ 基础使用 + + 演示 EmptyBox 组件的基本用法,通过开关控制不同组件的显示和隐藏。 + + + + +
+ + 用户信息: + } + unCheckedChildren={} + /> + + {showUserInfo ? '显示' : '隐藏'} + + + + + + 系统设置: + } + unCheckedChildren={} + /> + + {showSettings ? '显示' : '隐藏'} + + + + + + 数据统计: + } + unCheckedChildren={} + /> + + {showStatistics ? '显示' : '隐藏'} + + + + + + + + + {/* 用户信息组件 */} + + + + 用户信息 + + } + size="small" + style={{ backgroundColor: '#f6ffed', borderColor: '#52c41a' }} + > +
+ + 这是用户信息组件,当开关打开时会显示,关闭时会完全隐藏。 + + +
+
+ 用户名: + 张三 +
+
+ 邮箱: + + zhangsan@example.com + +
+ + +
+ 角色: + + 管理员 + +
+
+ 状态: + + 活跃 + +
+ + + + + + + {/* 系统设置组件 */} + + + + 系统设置 + + } + size="small" + style={{ backgroundColor: '#fff7e6', borderColor: '#faad14' }} + > +
+ + 这是系统设置组件,展示了 EmptyBox 的条件渲染功能。 + + +
+ 主题模式: + + 浅色 + +
+
+ 语言设置: + + 中文 + +
+
+ 通知设置: + + 开启 + +
+
+
+
+
+ + {/* 数据统计组件 */} + + +
+ + 这是数据统计组件,使用 EmptyBox 控制显示状态。 + + +
+
+
+ 1,234 +
+ 总用户数 +
+ + +
+
+ 89% +
+ 活跃率 +
+ + +
+
+ 56 +
+ 今日新增 +
+ + + + + + + {/* 状态提示 */} +
+ + 当前显示组件: + {showUserInfo && ( + + 用户信息 + + )} + {showSettings && ( + + 系统设置 + + )} + {showStatistics && ( + + 数据统计 + + )} + {!showUserInfo && !showSettings && !showStatistics && ( + + 无组件显示 + + )} + +
+ + + + + +
+

功能特点:

+
    +
  • + 条件渲染: 根据布尔值控制组件的显示/隐藏 +
  • +
  • + 实时响应: 条件变化时立即更新渲染状态 +
  • +
  • + 性能优化: 条件不满足时完全不渲染,节省资源 +
  • +
  • + 灵活控制: 支持多个独立的条件控制 +
  • +
+
+ + + +
+

使用场景:

+
    +
  • 根据用户权限显示/隐藏功能模块
  • +
  • 根据数据状态控制组件渲染
  • +
  • 实现动态的界面布局
  • +
  • 优化应用性能,避免不必要的渲染
  • +
+
+ + + ); +}; + +export default BasicDemo; diff --git a/packages/shared/lib/components/EmptyBox/index.ts b/packages/dms-kit/src/components/EmptyBox/index.ts similarity index 100% rename from packages/shared/lib/components/EmptyBox/index.ts rename to packages/dms-kit/src/components/EmptyBox/index.ts diff --git a/packages/shared/lib/components/HeaderProgress/HeaderProgress.test.tsx b/packages/dms-kit/src/components/HeaderProgress/HeaderProgress.test.tsx similarity index 100% rename from packages/shared/lib/components/HeaderProgress/HeaderProgress.test.tsx rename to packages/dms-kit/src/components/HeaderProgress/HeaderProgress.test.tsx diff --git a/packages/shared/lib/components/HeaderProgress/HeaderProgress.tsx b/packages/dms-kit/src/components/HeaderProgress/HeaderProgress.tsx similarity index 100% rename from packages/shared/lib/components/HeaderProgress/HeaderProgress.tsx rename to packages/dms-kit/src/components/HeaderProgress/HeaderProgress.tsx diff --git a/packages/dms-kit/src/components/HeaderProgress/README.md b/packages/dms-kit/src/components/HeaderProgress/README.md new file mode 100644 index 000000000..a1f5a4768 --- /dev/null +++ b/packages/dms-kit/src/components/HeaderProgress/README.md @@ -0,0 +1,58 @@ +--- +group: + title: 交互组件 + order: 21 +--- + +# HeaderProgress 头部进度条 + +基于 NProgress 库封装的头部进度条组件,提供了简洁的页面加载进度指示,适用于页面切换、数据加载等场景的进度反馈。 + +## 何时使用 + +- 需要在页面顶部显示加载进度时 +- 需要为页面切换提供视觉反馈时 +- 需要为异步操作显示进度指示时 +- 需要保持与设计系统一致的进度条样式时 +- 需要简洁的进度指示器时 + +## 代码演示 + + + +## API + +### HeaderProgress + +HeaderProgress 组件是一个无渲染组件,不接收任何 props,自动在组件挂载时启动进度条,在组件卸载时完成进度条。 + + +### NProgress 配置 + +组件内部配置了 NProgress 的默认设置: + +```typescript +Nprogress.configure({ + showSpinner: false // 不显示旋转器 +}); + +// 组件内部 +useEffect(() => { + Nprogress.start(); + return () => { + Nprogress.done(); + }; +}, []); +``` + + + +## 更新日志 + +- **1.0.0**: 初始版本,基于 NProgress 库封装 +- 自动进度条管理 +- 与 React 生命周期同步 +- 简洁的进度指示效果 +- 轻量级实现 +- 完整的 TypeScript 类型支持 +- 基于 NProgress 的可靠进度显示 diff --git a/packages/shared/lib/components/HeaderProgress/index.ts b/packages/dms-kit/src/components/HeaderProgress/index.ts similarity index 100% rename from packages/shared/lib/components/HeaderProgress/index.ts rename to packages/dms-kit/src/components/HeaderProgress/index.ts diff --git a/packages/shared/lib/components/LazyLoadComponent/LazyLoadComponent.tsx b/packages/dms-kit/src/components/LazyLoadComponent/LazyLoadComponent.tsx similarity index 100% rename from packages/shared/lib/components/LazyLoadComponent/LazyLoadComponent.tsx rename to packages/dms-kit/src/components/LazyLoadComponent/LazyLoadComponent.tsx diff --git a/packages/shared/lib/components/LazyLoadComponent/LazyLoadComponent.types.ts b/packages/dms-kit/src/components/LazyLoadComponent/LazyLoadComponent.types.ts similarity index 100% rename from packages/shared/lib/components/LazyLoadComponent/LazyLoadComponent.types.ts rename to packages/dms-kit/src/components/LazyLoadComponent/LazyLoadComponent.types.ts diff --git a/packages/dms-kit/src/components/LazyLoadComponent/README.md b/packages/dms-kit/src/components/LazyLoadComponent/README.md new file mode 100644 index 000000000..364d2c7a7 --- /dev/null +++ b/packages/dms-kit/src/components/LazyLoadComponent/README.md @@ -0,0 +1,34 @@ +--- +group: + title: 交互组件 + order: 20 +--- + +# LazyLoadComponent 组件 + +一个轻量级的 React 懒加载容器,支持按需挂载、隐藏与销毁。 + +## 何时使用 + +- 根据 `open` 控制子组件的挂载与卸载 +- 需要隐藏但保留 DOM 或完全销毁以释放资源 + +## 基础示例 + + + +## 切换显隐时重新渲染 + + +## API + +| 参数 | 说明 | 类型 | 默认值 | +| --------------- | ----------------------- | ------------------- | ------- | +| open | 是否显示组件 | `boolean` | - | +| forceRender | 强制首次渲染但隐藏 | `boolean` | `false` | +| destroyOnClose | 关闭时卸载组件 | `boolean` | `false` | +| animation | CSS 动画类名或禁用动画 | `string` | `false` | - | +| className | 自定义容器类名 | `string` | - | +| children | 渲染内容 | `ReactNode` | - | + + diff --git a/packages/shared/lib/components/LazyLoadComponent/__tests__/index.test.tsx b/packages/dms-kit/src/components/LazyLoadComponent/__tests__/index.test.tsx similarity index 100% rename from packages/shared/lib/components/LazyLoadComponent/__tests__/index.test.tsx rename to packages/dms-kit/src/components/LazyLoadComponent/__tests__/index.test.tsx diff --git a/packages/dms-kit/src/components/LazyLoadComponent/demo/advanced.tsx b/packages/dms-kit/src/components/LazyLoadComponent/demo/advanced.tsx new file mode 100644 index 000000000..37bf2938d --- /dev/null +++ b/packages/dms-kit/src/components/LazyLoadComponent/demo/advanced.tsx @@ -0,0 +1,24 @@ +import React, { useState } from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import LazyLoadComponent from '../LazyLoadComponent'; + +function HeavyComponent() { + return
这是重组件内容
; +} + +export default function AdvancedDemo() { + const [visible, setVisible] = useState(false); + return ( + + + + + + + ); +} diff --git a/packages/dms-kit/src/components/LazyLoadComponent/demo/basic.tsx b/packages/dms-kit/src/components/LazyLoadComponent/demo/basic.tsx new file mode 100644 index 000000000..25411253a --- /dev/null +++ b/packages/dms-kit/src/components/LazyLoadComponent/demo/basic.tsx @@ -0,0 +1,15 @@ +import React, { useState } from 'react'; +import { ConfigProvider } from '@actiontech/dms-kit'; +import LazyLoadComponent from '../LazyLoadComponent'; + +export default function BasicDemo() { + const [visible, setVisible] = useState(false); + return ( + + + +
这是懒加载内容
+
+
+ ); +} diff --git a/packages/shared/lib/components/LazyLoadComponent/index.ts b/packages/dms-kit/src/components/LazyLoadComponent/index.ts similarity index 100% rename from packages/shared/lib/components/LazyLoadComponent/index.ts rename to packages/dms-kit/src/components/LazyLoadComponent/index.ts diff --git a/packages/shared/lib/components/LazyLoadComponent/style.ts b/packages/dms-kit/src/components/LazyLoadComponent/style.ts similarity index 100% rename from packages/shared/lib/components/LazyLoadComponent/style.ts rename to packages/dms-kit/src/components/LazyLoadComponent/style.ts diff --git a/packages/shared/lib/components/ModeSwitcher/ModeSwitcher.test.tsx b/packages/dms-kit/src/components/ModeSwitcher/ModeSwitcher.test.tsx similarity index 100% rename from packages/shared/lib/components/ModeSwitcher/ModeSwitcher.test.tsx rename to packages/dms-kit/src/components/ModeSwitcher/ModeSwitcher.test.tsx diff --git a/packages/shared/lib/components/ModeSwitcher/ModeSwitcher.tsx b/packages/dms-kit/src/components/ModeSwitcher/ModeSwitcher.tsx similarity index 100% rename from packages/shared/lib/components/ModeSwitcher/ModeSwitcher.tsx rename to packages/dms-kit/src/components/ModeSwitcher/ModeSwitcher.tsx diff --git a/packages/shared/lib/components/ModeSwitcher/ModeSwitcher.types.ts b/packages/dms-kit/src/components/ModeSwitcher/ModeSwitcher.types.ts similarity index 100% rename from packages/shared/lib/components/ModeSwitcher/ModeSwitcher.types.ts rename to packages/dms-kit/src/components/ModeSwitcher/ModeSwitcher.types.ts diff --git a/packages/dms-kit/src/components/ModeSwitcher/README.md b/packages/dms-kit/src/components/ModeSwitcher/README.md new file mode 100644 index 000000000..64a74084d --- /dev/null +++ b/packages/dms-kit/src/components/ModeSwitcher/README.md @@ -0,0 +1,190 @@ +--- +group: + title: 交互组件 + order: 19 +--- + +# ModeSwitcher 模式切换器 + +基于 Ant Design Row/Col 组件封装的模式切换器组件,提供了统一的样式规范和交互体验,支持图标、文本和自定义布局,适用于不同模式或视图之间的切换。 + +## 何时使用 + +- 需要在不同模式或视图之间切换时 +- 需要显示当前选中状态和切换选项时 +- 需要支持图标和文本组合的模式选择时 +- 需要保持与设计系统一致的切换器样式时 +- 需要自定义布局的模式切换时 + +## 代码演示 + +### 基础用法 + + + +### 图标模式 + + + +### 自定义布局 + + + + + +### 集成使用 + + + +## API + +### ModeSwitcher + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| options | 模式选项数组 | `ModeSwitcherOptionsType \| Array` | - | - | +| value | 当前选中的模式值 | `V` | - | - | +| onChange | 模式切换的回调函数 | `(val: V) => void` | - | - | +| defaultValue | 默认选中的模式值 | `V` | - | - | +| className | 自定义类名 | `string` | - | - | +| rowProps | Row 组件的属性 | `RowProps` | - | - | +| disabled | 是否禁用 | `boolean` | `false` | - | + +### ModeSwitcherOptionsType + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| label | 模式选项的标签文本 | `ReactNode` | - | - | +| value | 模式选项的值 | `string \| number` | - | - | +| icon | 模式选项的图标 | `ReactNode` | - | - | +| colProps | Col 组件的属性 | `ColProps` | - | - | + +### 类型定义 + +```typescript +// 泛型类型,支持 string 或 number 类型的值 +type ModeSwitcherProps = { + options: ModeSwitcherOptionsType | Array; + value?: V; + onChange?: (val: V) => void; + defaultValue?: V; + className?: string; + rowProps?: RowProps; + disabled?: boolean; +}; + +// 模式选项类型 +type ModeSwitcherOptionsType = Array<{ + label: ReactNode; + value: string | number; + icon?: ReactNode; + colProps?: ColProps; +}>; +``` + +### 继承属性 + +ModeSwitcher 组件继承了 Ant Design Row 组件的所有属性,通过 rowProps 进行配置。 + +## 设计规范 + +### 样式特性 + +- 统一的模式切换器样式 +- 基于主题的色彩系统 +- 支持图标和文本组合 +- 响应式布局支持 +- 清晰的选中状态指示 + +### 布局规范 + +- 基于 Row/Col 栅格系统 +- 支持自定义列属性配置 +- 自动处理选项间距 +- 自定义列数配置 +- 统一的选项高度 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.modeSwitcher = { + // 继承自定义样式的主题配置 +} +``` + +## 功能特性 + +### 模式切换 + +- 支持受控和非受控模式 +- 自动处理选中状态 +- 支持图标和文本组合 +- 可配置的切换回调 + +### 布局控制 + +- 基于 Ant Design 栅格系统 +- 支持自定义列属性 +- 灵活布局配置 +- 灵活的选项排列 + +### 状态管理 + +- 使用 useControllableValue 管理状态 +- 支持默认值设置 +- 自动处理内部状态 +- 支持禁用状态 + +### 交互反馈 + +- 清晰的选中状态指示 +- 平滑的切换动画 +- 支持禁用状态 +- 鼠标悬停效果 + +## 使用场景 + +### 视图模式切换 + +在应用的不同视图模式之间切换,如列表视图、网格视图、卡片视图等。 + +### 功能模式选择 + +选择不同的功能模式,如编辑模式、预览模式、只读模式等。 + +### 主题模式切换 + +在明暗主题、色彩主题等不同主题模式之间切换。 + +### 布局模式调整 + +调整页面的布局模式,如紧凑模式、宽松模式、自定义模式等。 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `options` 数组必须包含有效的 `label` 和 `value` 属性 +3. 当使用字符串数组时,字符串既作为标签也作为值 +4. `colProps` 可以用于控制每个选项的列宽和响应式行为 +5. 组件会自动处理选中状态的样式和交互 + +## 最佳实践 + +1. **选项设计**: 保持选项数量适中,避免过多选项影响用户体验 +2. **图标使用**: 为每个模式选择有意义的图标,提升识别性 +3. **布局配置**: 使用 `colProps` 配置列宽和布局属性 +4. **状态管理**: 合理使用受控和非受控模式,根据业务需求选择 +5. **样式定制**: 通过主题系统保持与整体设计的一致性 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Row/Col 组件封装 +- 支持模式切换和状态管理 +- 集成图标和文本显示 +- 统一的样式规范和主题系统集成 +- 响应式布局和自定义配置支持 +- 完整的 TypeScript 类型支持 +- 支持受控和非受控模式 +- 基于 useControllableValue 的状态管理 diff --git a/packages/shared/lib/components/ModeSwitcher/__snapshots__/ModeSwitcher.test.tsx.snap b/packages/dms-kit/src/components/ModeSwitcher/__snapshots__/ModeSwitcher.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/ModeSwitcher/__snapshots__/ModeSwitcher.test.tsx.snap rename to packages/dms-kit/src/components/ModeSwitcher/__snapshots__/ModeSwitcher.test.tsx.snap diff --git a/packages/dms-kit/src/components/ModeSwitcher/demo/basic.tsx b/packages/dms-kit/src/components/ModeSwitcher/demo/basic.tsx new file mode 100644 index 000000000..dc98c8c6d --- /dev/null +++ b/packages/dms-kit/src/components/ModeSwitcher/demo/basic.tsx @@ -0,0 +1,180 @@ +import React, { useState } from 'react'; +import { Card, Space, Typography, Divider } from 'antd'; +import { ModeSwitcher, ConfigProvider } from '@actiontech/dms-kit'; +import { + AppstoreOutlined, + BarsOutlined, + TableOutlined, + UserOutlined, + SettingOutlined, + DashboardOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; + +const BasicDemo: React.FC = () => { + const [viewMode, setViewMode] = useState('grid'); + const [userMode, setUserMode] = useState('view'); + + // 视图模式选项 + const viewOptions = [ + { + label: '网格视图', + value: 'grid', + icon: + }, + { + label: '列表视图', + value: 'list', + icon: + }, + { + label: '表格视图', + value: 'table', + icon: + } + ]; + + // 用户模式选项 + const userOptions = [ + { + label: '查看模式', + value: 'view', + icon: + }, + { + label: '编辑模式', + value: 'edit', + icon: + }, + { + label: '管理模式', + value: 'admin', + icon: + } + ]; + + // 简单字符串选项 + const simpleOptions = ['紧凑', '标准', '宽松']; + + return ( + +
+

基础用法

+ + +
+

使用图标和文本的模式切换器:

+
+ + + + + +
+ + 当前选中的视图模式: {viewMode} + + 这里会根据选中的模式显示不同的内容布局。 +
+
+ + +
+

不同用户权限的模式切换:

+
+ + + + + +
+ + 当前用户模式: {userMode} + + 不同模式提供不同的功能和权限。 +
+
+ + +
+

使用字符串数组的简单选项:

+
+ + + + + +
+ + 布局密度选项,适用于调整页面元素的间距和大小。 + +
+
+ + +
+

组件特点:

+
    +
  • + 模式切换: 支持不同模式之间的切换 +
  • +
  • + 图标支持: 每个选项可以配置独立的图标 +
  • +
  • + 状态管理: 支持受控和非受控模式 +
  • +
  • + 栅格布局: 基于 Ant Design 栅格系统 +
  • +
  • + 选中指示: 清晰的选中状态显示 +
  • +
+
+ +
+

使用场景:

+
    +
  • 视图模式切换(列表、网格、卡片等)
  • +
  • 功能模式选择(查看、编辑、管理等)
  • +
  • 主题模式切换(明暗、色彩等)
  • +
  • 布局模式调整(紧凑、标准、宽松等)
  • +
+
+
+
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/ModeSwitcher/demo/customLayout.tsx b/packages/dms-kit/src/components/ModeSwitcher/demo/customLayout.tsx new file mode 100644 index 000000000..7194afa98 --- /dev/null +++ b/packages/dms-kit/src/components/ModeSwitcher/demo/customLayout.tsx @@ -0,0 +1,316 @@ +import React, { useState } from 'react'; +import { Card, Space, Typography, Divider, Row, Col, Switch } from 'antd'; +import { ModeSwitcher, ConfigProvider } from '@actiontech/dms-kit'; +import { + AppstoreOutlined, + BarsOutlined, + TableOutlined, + CalendarOutlined, + ClockCircleOutlined, + UserOutlined, + TeamOutlined, + SettingOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; + +const CustomLayoutDemo: React.FC = () => { + const [viewMode, setViewMode] = useState('grid'); + const [timeMode, setTimeMode] = useState('day'); + const [userMode, setUserMode] = useState('single'); + const [compactMode, setCompactMode] = useState(false); + + // 视图模式选项 - 使用 colProps 控制列宽 + const viewOptions = [ + { + label: '网格视图', + value: 'grid', + icon: , + colProps: { span: 8 } + }, + { + label: '列表视图', + value: 'list', + icon: , + colProps: { span: 8 } + }, + { + label: '表格视图', + value: 'table', + icon: , + colProps: { span: 8 } + } + ]; + + // 时间模式选项 - 不同列宽 + const timeOptions = [ + { + label: '日视图', + value: 'day', + icon: , + colProps: { span: 6 } + }, + { + label: '周视图', + value: 'week', + icon: , + colProps: { span: 6 } + }, + { + label: '月视图', + value: 'month', + icon: , + colProps: { span: 6 } + }, + { + label: '年视图', + value: 'year', + icon: , + colProps: { span: 6 } + } + ]; + + // 用户模式选项 - 自定义列宽 + const userOptions = [ + { + label: '单用户', + value: 'single', + icon: , + colProps: { + xs: 24, + sm: 12, + md: 8, + lg: 6 + } + }, + { + label: '多用户', + value: 'multiple', + icon: , + colProps: { + xs: 24, + sm: 12, + md: 8, + lg: 6 + } + }, + { + label: '管理员', + value: 'admin', + icon: , + colProps: { + xs: 24, + sm: 12, + md: 8, + lg: 6 + } + }, + { + label: '访客', + value: 'guest', + icon: , + colProps: { + xs: 24, + sm: 12, + md: 8, + lg: 6 + } + } + ]; + + return ( + +
+

自定义布局

+ + +
+

使用 colProps 控制每个选项的列宽,实现均匀分布:

+
+ + + + + +
+ + 当前视图模式: {viewMode} + + + 每个选项占用 8 列,在 24 列栅格系统中均匀分布。 + +
+
+ + +
+

为不同选项设置不同的列宽,适应内容长度:

+
+ + + + + +
+ + 当前时间模式: {timeMode} + + 每个选项占用 6 列,支持 4 个选项的布局。 +
+
+ + +
+

使用自定义列宽,配置不同屏幕尺寸下的列数:

+
+ + + + + +
+ + 当前用户模式: {userMode} + + 自定义列宽:xs(24) → sm(12) → md(8) → lg(6) + 调整浏览器窗口大小查看布局效果 +
+
+ + +
+

通过 rowProps 控制整体布局的紧凑程度:

+
+ + +
+ + 紧凑模式: + + +
+ + +
+ + + +
+ + 紧凑模式: {compactMode ? '开启' : '关闭'} + + + 通过调整 gutter 和 className 实现不同的布局效果。 + +
+
+ + +
+

colProps 配置选项:

+
    +
  • + span: 固定列宽,适用于等宽布局 +
  • +
  • + xs/sm/md/lg/xl: 自定义列宽,适用于不同屏幕尺寸 +
  • +
  • + offset: 列偏移,用于调整位置 +
  • +
  • + order: 列顺序,用于调整显示顺序 +
  • +
+
+ + + +
+

rowProps 配置选项:

+
    +
  • + gutter: 栅格间隔,控制选项之间的间距 +
  • +
  • + justify: + 水平排列方式(start/end/center/space-around/space-between) +
  • +
  • + align: 垂直对齐方式(top/middle/bottom) +
  • +
  • + className: 自定义类名,用于样式定制 +
  • +
+
+ +
+

布局最佳实践:

+
    +
  • 使用 24 列栅格系统,确保布局的一致性
  • +
  • 为不同屏幕尺寸配置自定义列宽
  • +
  • 合理使用 gutter 控制选项间距
  • +
  • 通过 className 实现自定义样式
  • +
+
+
+
+
+ ); +}; + +export default CustomLayoutDemo; diff --git a/packages/dms-kit/src/components/ModeSwitcher/demo/iconMode.tsx b/packages/dms-kit/src/components/ModeSwitcher/demo/iconMode.tsx new file mode 100644 index 000000000..f7e56b3ca --- /dev/null +++ b/packages/dms-kit/src/components/ModeSwitcher/demo/iconMode.tsx @@ -0,0 +1,206 @@ +import React, { useState } from 'react'; +import { Card, Space, Typography, Divider, Row, Col } from 'antd'; +import { ModeSwitcher, ConfigProvider } from '@actiontech/dms-kit'; +import { + SunOutlined, + MoonOutlined, + DesktopOutlined, + MobileOutlined, + TabletOutlined, + CloudOutlined, + DatabaseOutlined, + ApiOutlined, + SettingOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; + +const IconModeDemo: React.FC = () => { + const [themeMode, setThemeMode] = useState('light'); + const [deviceMode, setDeviceMode] = useState('desktop'); + const [serviceMode, setServiceMode] = useState('cloud'); + + // 主题模式选项 + const themeOptions = [ + { + label: '浅色主题', + value: 'light', + icon: + }, + { + label: '深色主题', + value: 'dark', + icon: + }, + { + label: '跟随系统', + value: 'auto', + icon: + } + ]; + + // 设备模式选项 + const deviceOptions = [ + { + label: '桌面端', + value: 'desktop', + icon: + }, + { + label: '移动端', + value: 'mobile', + icon: + }, + { + label: '平板端', + value: 'tablet', + icon: + } + ]; + + // 服务模式选项 + const serviceOptions = [ + { + label: '云端服务', + value: 'cloud', + icon: + }, + { + label: '本地服务', + value: 'local', + icon: + }, + { + label: 'API 服务', + value: 'api', + icon: + }, + { + label: '自定义配置', + value: 'custom', + icon: + } + ]; + + return ( + +
+

图标模式

+ + +
+

使用图标表示不同主题模式的切换器:

+
+ + + + + +
+ + 当前主题模式: {themeMode} + + + 图标帮助用户快速识别不同的主题选项,提升用户体验。 + +
+
+ + +
+

不同设备类型的模式切换:

+
+ + + + + +
+ + 当前设备模式: {deviceMode} + + + 根据设备类型调整界面布局和交互方式。 + +
+
+ + +
+

多种服务模式的切换选择:

+
+ + + + + +
+ + 当前服务模式: {serviceMode} + + + 选择不同的服务部署和配置模式。 + +
+
+ + +
+

图标使用原则:

+
    +
  • + 语义化: 图标应该与模式含义相关 +
  • +
  • + 一致性: 使用统一的图标风格和大小 +
  • +
  • + 可识别性: 图标应该容易理解和识别 +
  • +
  • + 视觉平衡: 图标与文本保持视觉平衡 +
  • +
+
+ +
+

图标模式优势:

+
    +
  • 提升用户识别速度
  • +
  • 增强界面的视觉吸引力
  • +
  • 减少文字阅读负担
  • +
  • 支持国际化场景
  • +
+
+ +
+

使用建议:

+
    +
  • 选择有意义的图标,避免使用抽象符号
  • +
  • 保持图标大小一致,建议使用 16-20px
  • +
  • 考虑图标的颜色和主题适配
  • +
  • 为图标添加适当的 tooltip 说明
  • +
+
+
+
+
+ ); +}; + +export default IconModeDemo; diff --git a/packages/dms-kit/src/components/ModeSwitcher/demo/integration.tsx b/packages/dms-kit/src/components/ModeSwitcher/demo/integration.tsx new file mode 100644 index 000000000..ab444879d --- /dev/null +++ b/packages/dms-kit/src/components/ModeSwitcher/demo/integration.tsx @@ -0,0 +1,544 @@ +import React, { useState } from 'react'; +import { + Card, + Space, + Button, + Typography, + Divider, + Row, + Col, + Table, + Tag, + Input, + Select, + DatePicker +} from 'antd'; +import { ModeSwitcher, ConfigProvider } from '@actiontech/dms-kit'; +import { + AppstoreOutlined, + BarsOutlined, + TableOutlined, + CalendarOutlined, + UserOutlined, + SettingOutlined, + SearchOutlined, + FilterOutlined, + PlusOutlined, + EditOutlined, + DeleteOutlined, + EyeOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; +const { Search } = Input; +const { Option } = Select; + +const IntegrationDemo: React.FC = () => { + const [viewMode, setViewMode] = useState('grid'); + const [userMode, setUserMode] = useState('view'); + const [themeMode, setThemeMode] = useState('light'); + const [searchText, setSearchText] = useState(''); + const [filterStatus, setFilterStatus] = useState('all'); + + // 模拟用户数据 + const userData = [ + { + id: 1, + name: '张三', + email: 'zhangsan@example.com', + role: '管理员', + status: '活跃', + createTime: '2024-01-15' + }, + { + id: 2, + name: '李四', + email: 'lisi@example.com', + role: '用户', + status: '活跃', + createTime: '2024-01-20' + }, + { + id: 3, + name: '王五', + email: 'wangwu@example.com', + role: '用户', + status: '禁用', + createTime: '2024-02-01' + }, + { + id: 4, + name: '赵六', + email: 'zhaoliu@example.com', + role: '编辑', + status: '活跃', + createTime: '2024-02-10' + }, + { + id: 5, + name: '钱七', + email: 'qianqi@example.com', + role: '用户', + status: '活跃', + createTime: '2024-02-15' + }, + { + id: 6, + name: '孙八', + email: 'sunba@example.com', + role: '编辑', + status: '禁用', + createTime: '2024-02-20' + } + ]; + + // 视图模式选项 + const viewOptions = [ + { + label: '网格视图', + value: 'grid', + icon: , + colProps: { span: 8 } + }, + { + label: '列表视图', + value: 'list', + icon: , + colProps: { span: 8 } + }, + { + label: '表格视图', + value: 'table', + icon: , + colProps: { span: 8 } + } + ]; + + // 用户模式选项 + const userOptions = [ + { + label: '查看模式', + value: 'view', + icon: , + colProps: { span: 6 } + }, + { + label: '编辑模式', + value: 'edit', + icon: , + colProps: { span: 6 } + }, + { + label: '管理模式', + value: 'admin', + icon: , + colProps: { span: 6 } + }, + { + label: '审核模式', + value: 'review', + icon: , + colProps: { span: 6 } + } + ]; + + // 主题模式选项 + const themeOptions = [ + { + label: '浅色主题', + value: 'light', + icon: ( +
+ ) + }, + { + label: '深色主题', + value: 'dark', + icon: ( +
+ ) + }, + { + label: '跟随系统', + value: 'auto', + icon: ( +
+ ) + } + ]; + + // 过滤后的数据 + const filteredData = userData.filter( + (user) => + user.name.toLowerCase().includes(searchText.toLowerCase()) && + (filterStatus === 'all' || user.status === filterStatus) + ); + + // 表格列定义 + const columns = [ + { title: 'ID', dataIndex: 'id', key: 'id', width: 80 }, + { title: '姓名', dataIndex: 'name', key: 'name', width: 120 }, + { title: '邮箱', dataIndex: 'email', key: 'email', width: 200 }, + { + title: '角色', + dataIndex: 'role', + key: 'role', + width: 100, + render: (role: string) => { + const colorMap: { [key: string]: string } = { + 管理员: 'red', + 编辑: 'blue', + 用户: 'green' + }; + return {role}; + } + }, + { + title: '状态', + dataIndex: 'status', + key: 'status', + width: 100, + render: (status: string) => ( + {status} + ) + }, + { + title: '创建时间', + dataIndex: 'createTime', + key: 'createTime', + width: 120 + }, + { + title: '操作', + key: 'action', + width: 200, + render: (_: any, record: any) => ( + + + {userMode === 'edit' && ( + + )} + {userMode === 'admin' && ( + + )} + + ) + } + ]; + + // 渲染网格视图 + const renderGridView = () => ( + + {filteredData.map((user) => ( +
+ +
+
+ {user.name.charAt(0)} +
+ + {user.name} + + {user.email} +
+ + {user.role} + + + {user.status} + +
+
+
+ + ))} + + ); + + // 渲染列表视图 + const renderListView = () => ( +
+ {filteredData.map((user) => ( + + +
+
+ {user.name.charAt(0)} +
+ + + {user.name} + + + {user.email} + + + + {user.role} + + + + + {user.status} + + + + {user.createTime} + + + + + {userMode === 'edit' && ( + + )} + {userMode === 'admin' && ( + + )} + + + + + ))} + + ); + + return ( + +
+

集成使用

+ + +
+

ModeSwitcher 组件在实际业务系统中的完整集成使用:

+
+ + {/* 主题模式切换 */} +
+ 主题设置: + +
+ + {/* 用户模式切换 */} +
+ 用户模式: + +
+ + {/* 视图模式切换 */} +
+ 视图模式: + +
+
+ + + +
+ setSearchText(e.target.value)} + prefix={} + /> + + + + + + + + + + + + + + +
+ + 当前模式: {userMode} | 视图: {viewMode} | 主题: {themeMode} | + 数据量: {filteredData.length} 条 + +
+ + {viewMode === 'grid' && renderGridView()} + {viewMode === 'list' && renderListView()} + {viewMode === 'table' && ( +
+ `第 ${range[0]}-${range[1]} 条/共 ${total} 条` + }} + /> + )} + + + +
+

集成特点:

+
    +
  • + 多模式切换: + 支持主题、用户权限、视图等多种模式切换 +
  • +
  • + 自定义布局: 支持不同列宽和布局配置 +
  • +
  • + 状态联动: + 不同模式之间相互影响,形成完整的交互系统 +
  • +
  • + 业务集成: 与搜索、筛选、表格等业务组件无缝集成 +
  • +
+
+ + + +
+

使用场景:

+
    +
  • 管理系统的多视图切换
  • +
  • 用户权限模式控制
  • +
  • 主题和界面定制
  • +
  • 数据展示方式选择
  • +
+
+ +
+

最佳实践:

+
    +
  • 将相关的模式切换器组合使用
  • +
  • 考虑不同模式之间的依赖关系
  • +
  • 为用户提供清晰的模式说明
  • +
  • 保存用户的模式偏好设置
  • +
+
+
+ + + ); +}; + +export default IntegrationDemo; diff --git a/packages/shared/lib/components/ModeSwitcher/index.ts b/packages/dms-kit/src/components/ModeSwitcher/index.ts similarity index 100% rename from packages/shared/lib/components/ModeSwitcher/index.ts rename to packages/dms-kit/src/components/ModeSwitcher/index.ts diff --git a/packages/shared/lib/components/ModeSwitcher/style.ts b/packages/dms-kit/src/components/ModeSwitcher/style.ts similarity index 100% rename from packages/shared/lib/components/ModeSwitcher/style.ts rename to packages/dms-kit/src/components/ModeSwitcher/style.ts diff --git a/packages/shared/lib/components/PageHeader/PageHeader.test.tsx b/packages/dms-kit/src/components/PageHeader/PageHeader.test.tsx similarity index 100% rename from packages/shared/lib/components/PageHeader/PageHeader.test.tsx rename to packages/dms-kit/src/components/PageHeader/PageHeader.test.tsx diff --git a/packages/shared/lib/components/PageHeader/PageHeader.tsx b/packages/dms-kit/src/components/PageHeader/PageHeader.tsx similarity index 100% rename from packages/shared/lib/components/PageHeader/PageHeader.tsx rename to packages/dms-kit/src/components/PageHeader/PageHeader.tsx diff --git a/packages/shared/lib/components/PageHeader/PageHeader.types.ts b/packages/dms-kit/src/components/PageHeader/PageHeader.types.ts similarity index 100% rename from packages/shared/lib/components/PageHeader/PageHeader.types.ts rename to packages/dms-kit/src/components/PageHeader/PageHeader.types.ts diff --git a/packages/dms-kit/src/components/PageHeader/README.md b/packages/dms-kit/src/components/PageHeader/README.md new file mode 100644 index 000000000..6d338cfd9 --- /dev/null +++ b/packages/dms-kit/src/components/PageHeader/README.md @@ -0,0 +1,145 @@ +--- +group: + title: 展示组件 + order: 18 +--- + +# PageHeader 页面头部 + +基于自定义样式封装的页面头部组件,提供了统一的布局规范和样式设计,支持标题显示、额外内容区域和固定定位,适用于页面顶部的标题和操作区域。 + +## 何时使用 + +- 需要页面顶部的标题显示时 +- 需要在标题右侧显示额外操作按钮或内容时 +- 需要固定定位的页面头部时 +- 需要保持与设计系统一致的头部样式时 +- 需要简洁明了的页面标题区域时 + +## 代码演示 + +### 基础用法 + + + +### 额外内容区域 + + + +### 集成使用 + + + +## API + +### PageHeader + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| title | 页面标题内容 | `ReactNode` | - | - | +| extra | 标题右侧的额外内容 | `ReactNode` | - | - | +| fixed | 是否使用固定定位 | `boolean` | `false` | - | +| className | 自定义类名 | `string` | - | - | +| style | 自定义样式 | `CSSProperties` | - | - | + +## 设计规范 + +### 样式特性 + +- 统一的标题和内容布局 +- 基于主题的色彩系统 +- 支持固定定位模式 +- 响应式布局支持 +- 清晰的视觉层次 + +### 布局规范 + +- 标题位于左侧,支持任意 React 节点 +- 额外内容位于右侧,支持复杂组件 +- 支持固定定位,适合长页面使用 +- 统一的间距和对齐 +- 自适应内容宽度 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.pageHeader = { + // 继承自定义样式的主题配置 +} +``` + +## 功能特性 + +### 标题显示 + +- 支持任意 React 节点作为标题 +- 自动处理标题的样式和布局 +- 支持长标题的自动换行 +- 与整体设计风格保持一致 + +### 额外内容区域 + +- 在标题右侧显示额外内容 +- 支持按钮、链接、图标等组件 +- 自动处理内容的对齐和间距 +- 灵活的布局配置 + +### 固定定位 + +- 支持固定定位模式 +- 适合长页面的标题显示 +- 滚动时保持头部可见 +- 可配置的定位样式 + +### 响应式设计 + +- 自动适配不同屏幕尺寸 +- 支持移动端的显示优化 +- 内容区域的自动调整 +- 保持良好的用户体验 + +## 使用场景 + +### 数据列表页面 + +在数据列表页面顶部显示页面标题和操作按钮。 + +### 表单页面 + +在表单页面顶部显示表单标题和保存、取消等操作按钮。 + +### 详情页面 + +在详情页面顶部显示页面标题和编辑、删除等操作按钮。 + +### 设置页面 + +在设置页面顶部显示页面标题和配置相关的操作按钮。 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `title` 属性支持任意 React 节点,建议使用简洁的文本或图标 +3. `extra` 属性适合放置操作按钮、链接等交互元素 +4. 固定定位模式会影响页面的滚动行为,注意使用场景 +5. 自定义样式时注意保持与整体设计的一致性 + +## 最佳实践 + +1. **标题简洁**: 保持页面标题简洁明了,避免冗长的描述 +2. **操作合理**: 在额外内容区域放置常用的操作按钮 +3. **布局平衡**: 保持标题和额外内容的视觉平衡 +4. **固定定位**: 在长页面中使用固定定位,提升用户体验 +5. **样式统一**: 通过主题系统保持页面头部的样式一致性 + +## 更新日志 + +- **1.0.0**: 初始版本,基于自定义样式封装 +- 支持页面标题和额外内容显示 +- 集成固定定位功能 +- 统一的样式规范和主题系统集成 +- 响应式布局和自适应支持 +- 完整的 TypeScript 类型支持 +- 灵活的布局配置选项 diff --git a/packages/shared/lib/components/PageHeader/__snapshots__/PageHeader.test.tsx.snap b/packages/dms-kit/src/components/PageHeader/__snapshots__/PageHeader.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/PageHeader/__snapshots__/PageHeader.test.tsx.snap rename to packages/dms-kit/src/components/PageHeader/__snapshots__/PageHeader.test.tsx.snap diff --git a/packages/dms-kit/src/components/PageHeader/demo/basic.tsx b/packages/dms-kit/src/components/PageHeader/demo/basic.tsx new file mode 100644 index 000000000..a334681ff --- /dev/null +++ b/packages/dms-kit/src/components/PageHeader/demo/basic.tsx @@ -0,0 +1,117 @@ +import React from 'react'; +import { Card, Space, Button, Typography } from 'antd'; +import { PageHeader, ConfigProvider } from '@actiontech/dms-kit'; +import { + PlusOutlined, + DownloadOutlined, + ReloadOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph } = Typography; + +const BasicDemo: React.FC = () => { + return ( + +
+

基础用法

+ + +
+

页面头部组件用于显示页面标题和操作按钮:

+
+ + + + + + + } + /> + +
+ + 这里是页面的主要内容区域。页面头部组件会显示在内容区域的顶部, + 提供清晰的页面标题和常用的操作按钮。 + +
+
+ + +
+

页面头部支持不同类型的标题内容:

+
+ + + 系统配置 + + } + extra={} + /> + +
+ + 支持使用 Typography + 组件自定义标题样式,可以设置不同的标题级别和样式。 + +
+
+ + +
+

组件特点:

+
    +
  • + 标题显示: 左侧显示页面标题,支持任意 React 节点 +
  • +
  • + 额外内容: 右侧显示操作按钮、链接等额外内容 +
  • +
  • + 布局灵活: 自动处理标题和额外内容的对齐和间距 +
  • +
  • + 样式统一: 与设计系统保持一致的视觉风格 +
  • +
  • + 响应式设计: 自动适配不同屏幕尺寸 +
  • +
+
+ +
+

使用场景:

+
    +
  • 数据列表页面的标题和操作按钮
  • +
  • 表单页面的标题和保存、取消按钮
  • +
  • 详情页面的标题和编辑、删除按钮
  • +
  • 设置页面的标题和配置相关按钮
  • +
+
+
+
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/PageHeader/demo/extraContent.tsx b/packages/dms-kit/src/components/PageHeader/demo/extraContent.tsx new file mode 100644 index 000000000..b05093a8d --- /dev/null +++ b/packages/dms-kit/src/components/PageHeader/demo/extraContent.tsx @@ -0,0 +1,208 @@ +import React, { useState } from 'react'; +import { + Card, + Space, + Button, + Typography, + Input, + Select, + DatePicker, + Tag +} from 'antd'; +import { PageHeader, ConfigProvider } from '@actiontech/dms-kit'; +import { + PlusOutlined, + DownloadOutlined, + ReloadOutlined, + FilterOutlined, + SearchOutlined, + SettingOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; +const { Search } = Input; +const { Option } = Select; + +const ExtraContentDemo: React.FC = () => { + const [searchText, setSearchText] = useState(''); + const [status, setStatus] = useState('all'); + const [dateRange, setDateRange] = useState(null); + + return ( + +
+

额外内容区域

+ + +
+

在页面头部右侧显示常用的操作按钮:

+
+ + + + + + + } + /> + +
+ + 操作按钮放置在页面头部右侧,方便用户快速访问常用功能。 + +
+
+ + +
+

在页面头部集成搜索和筛选功能:

+
+ + + setSearchText(e.target.value)} + style={{ width: 250 }} + /> + + + + + } + /> + +
+ + 集成了搜索框、状态选择器、日期范围选择器和筛选按钮,提供完整的查询功能。 + +
+
+ + +
+

组合多种操作元素,创建功能丰富的页面头部:

+
+ + + + 数据报表 + + 实时数据统计和分析 +
+ } + extra={ + +
+
+ 最后更新: 2分钟前 +
+
+ 数据状态: 正常 +
+
+ + + +
+ } + /> + +
+ + 复杂的页面头部包含多行标题、状态信息和多种操作按钮,适合数据展示页面。 + +
+ + + +
+

额外内容区域特点:

+
    +
  • + 操作按钮: + 放置常用的操作按钮,如添加、编辑、删除等 +
  • +
  • + 搜索功能: 集成搜索框,支持快速查找内容 +
  • +
  • + 筛选控件: 包含下拉选择、日期选择等筛选组件 +
  • +
  • + 状态信息: 显示页面相关的状态信息和标签 +
  • +
  • + 灵活布局: 支持任意 React 组件的组合排列 +
  • +
+
+ +
+

使用建议:

+
    +
  • 将最常用的操作放在右侧,提升用户体验
  • +
  • 搜索和筛选功能适合数据列表页面
  • +
  • 状态信息可以帮助用户了解当前页面状态
  • +
  • 避免放置过多的操作元素,保持界面简洁
  • +
  • 考虑响应式设计,在小屏幕上适当调整布局
  • +
+
+
+ +
+ ); +}; + +export default ExtraContentDemo; diff --git a/packages/dms-kit/src/components/PageHeader/demo/integration.tsx b/packages/dms-kit/src/components/PageHeader/demo/integration.tsx new file mode 100644 index 000000000..48d28fb6d --- /dev/null +++ b/packages/dms-kit/src/components/PageHeader/demo/integration.tsx @@ -0,0 +1,433 @@ +import React, { useState } from 'react'; +import { + Card, + Space, + Button, + Typography, + Table, + Tag, + Input, + Select, + DatePicker, + Tabs +} from 'antd'; +import { PageHeader, ConfigProvider } from '@actiontech/dms-kit'; +import { + PlusOutlined, + DownloadOutlined, + ReloadOutlined, + SettingOutlined, + SearchOutlined, + FilterOutlined, + EditOutlined, + DeleteOutlined, + EyeOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; +const { Search } = Input; +const { Option } = Select; +const { TabPane } = Tabs; + +const IntegrationDemo: React.FC = () => { + const [searchText, setSearchText] = useState(''); + const [status, setStatus] = useState('all'); + const [dateRange, setDateRange] = useState(null); + + // 模拟用户数据 + const userData = [ + { + id: 1, + name: '张三', + email: 'zhangsan@example.com', + role: '管理员', + status: '活跃', + createTime: '2024-01-15' + }, + { + id: 2, + name: '李四', + email: 'lisi@example.com', + role: '用户', + status: '活跃', + createTime: '2024-01-20' + }, + { + id: 3, + name: '王五', + email: 'wangwu@example.com', + role: '用户', + status: '禁用', + createTime: '2024-02-01' + }, + { + id: 4, + name: '赵六', + email: 'zhaoliu@example.com', + role: '编辑', + status: '活跃', + createTime: '2024-02-10' + } + ]; + + const columns = [ + { title: 'ID', dataIndex: 'id', key: 'id', width: 80 }, + { title: '姓名', dataIndex: 'name', key: 'name', width: 120 }, + { title: '邮箱', dataIndex: 'email', key: 'email', width: 200 }, + { + title: '角色', + dataIndex: 'role', + key: 'role', + width: 100, + render: (role: string) => { + const colorMap: { [key: string]: string } = { + 管理员: 'red', + 编辑: 'blue', + 用户: 'green' + }; + return {role}; + } + }, + { + title: '状态', + dataIndex: 'status', + key: 'status', + width: 100, + render: (val: string) => ( + {val} + ) + }, + { + title: '创建时间', + dataIndex: 'createTime', + key: 'createTime', + width: 120 + }, + { + title: '操作', + key: 'action', + width: 200, + render: (_: any, record: any) => ( + + + + + + ) + } + ]; + + return ( + +
+

集成使用

+ + +
+

PageHeader 组件在实际页面中的完整集成使用:

+
+ + {/* 页面头部 */} + + + 用户管理系统 + + 管理平台用户、权限和角色配置 +
+ } + extra={ + + + + + + + } + style={{ + backgroundColor: '#fafafa', + border: '1px solid #d9d9d9', + borderRadius: '8px', + marginBottom: '20px' + }} + /> + + {/* 搜索和筛选区域 */} + + + setSearchText(e.target.value)} + style={{ width: 300 }} + /> + + + + + + + {/* 主要内容区域 */} + + + +
+ user.name + .toLowerCase() + .includes(searchText.toLowerCase()) && + (status === 'all' || + user.status === (status === 'active' ? '活跃' : '禁用')) + )} + rowKey="id" + pagination={{ + total: userData.length, + pageSize: 10, + showSizeChanger: true, + showQuickJumper: true, + showTotal: (total, range) => + `第 ${range[0]}-${range[1]} 条/共 ${total} 条` + }} + size="middle" + /> + + + +
+ 角色管理模块 + 这里可以管理用户角色和权限配置 +
+
+ + +
+ 权限配置模块 + 这里可以配置系统权限和访问控制 +
+
+ + + + + +
+

在数据统计页面中使用 PageHeader:

+
+ + +
+ 📊 +
+
+ + 数据统计中心 + + 实时监控系统运行状态和用户行为 +
+ + } + extra={ +
+
+
+ 最后更新 +
+
+ 2分钟前 +
+
+
+
+ 系统状态 +
+
+ 正常 +
+
+ + +
+ } + style={{ + background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', + color: '#ffffff', + border: 'none', + borderRadius: '8px', + marginBottom: '20px' + }} + /> + +
+ +
+
+ {userData.length} +
+
总用户数
+
+
+ +
+
+ {userData.filter((u) => u.status === '活跃').length} +
+
活跃用户
+
+
+ +
+
+ {userData.filter((u) => u.role === '管理员').length} +
+
管理员
+
+
+ +
+
+ 99.9% +
+
系统可用性
+
+
+
+
+ + +
+

集成特性:

+
    +
  • + 页面布局: 作为页面的主要导航和操作区域 +
  • +
  • + 功能集成: 与搜索、筛选、表格等组件协同工作 +
  • +
  • + 状态展示: 显示页面相关的状态信息和统计数据 +
  • +
  • + 操作入口: 提供页面主要功能的快捷访问 +
  • +
+
+ +
+

最佳实践:

+
    +
  • 在页面顶部使用 PageHeader 提供主要导航
  • +
  • 将最常用的操作按钮放在 extra 区域
  • +
  • 使用图标和颜色增强视觉层次
  • +
  • 保持页面头部与内容区域的视觉一致性
  • +
  • 考虑响应式设计,在小屏幕上适当调整布局
  • +
+
+
+ + + ); +}; + +export default IntegrationDemo; diff --git a/packages/shared/lib/components/PageHeader/index.ts b/packages/dms-kit/src/components/PageHeader/index.ts similarity index 100% rename from packages/shared/lib/components/PageHeader/index.ts rename to packages/dms-kit/src/components/PageHeader/index.ts diff --git a/packages/shared/lib/components/PageHeader/style.ts b/packages/dms-kit/src/components/PageHeader/style.ts similarity index 100% rename from packages/shared/lib/components/PageHeader/style.ts rename to packages/dms-kit/src/components/PageHeader/style.ts diff --git a/packages/dms-kit/src/components/ReminderInformation/README.md b/packages/dms-kit/src/components/ReminderInformation/README.md new file mode 100644 index 000000000..a938e5c46 --- /dev/null +++ b/packages/dms-kit/src/components/ReminderInformation/README.md @@ -0,0 +1,143 @@ +--- +group: + title: 展示组件 + order: 17 +--- + +# ReminderInformation 提醒信息 + +基于 Ant Design Typography 组件封装的提醒信息组件,提供了统一的样式规范和状态反馈,支持成功和错误两种状态,适用于操作结果提示和状态反馈。 + +## 何时使用 + +- 需要显示操作成功或失败的反馈信息时 +- 需要统一的提醒信息样式时 +- 需要图标和文字组合的状态提示时 +- 需要保持与设计系统一致的提醒组件样式时 +- 需要简洁明了的状态反馈时 + +## 代码演示 + +### 基础用法 + + + +### 状态类型 + + + +### 消息内容 + + + +### 集成使用 + + + +## API + +### ReminderInformation + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| status | 提醒信息的状态类型 | `'success' \| 'error'` | - | - | +| message | 提醒信息的文本内容 | `string` | - | - | + +## 设计规范 + +### 样式特性 + +- 统一的图标和文字样式 +- 基于主题的色彩系统 +- 支持成功和错误两种状态 +- 响应式布局支持 +- 清晰的视觉层次 + +### 状态规范 + +- **成功状态**: 绿色主题,显示成功图标 +- **错误状态**: 红色主题,显示错误图标 +- 图标和文字垂直居中对齐 +- 统一的间距和字体大小 + +### 主题配置 + +组件样式通过主题系统进行配置,支持以下主题变量: + +```typescript +theme.sharedTheme.components.reminderInformation = { + // 继承 CommonIconStyleWrapper 的主题配置 +} +``` + +## 功能特性 + +### 状态管理 + +组件支持两种状态类型: +- **success**: 成功状态,显示绿色主题和成功图标 +- **error**: 错误状态,显示红色主题和错误图标 + +### 图标显示 + +- 自动根据状态显示对应的图标 +- 成功状态:CheckCircleOutlined 图标 +- 错误状态:CloseCircleOutlined 图标 +- 图标大小和颜色与主题保持一致 + +### 文本渲染 + +- 使用 Typography.Text 组件渲染文本 +- 自动继承状态对应的主题色彩 +- 支持长文本自动换行 +- 使用 pre 标签保持文本格式 + +### 布局对齐 + +- 图标和文字垂直居中对齐 +- 使用 Flexbox 布局实现对齐 +- 统一的间距和边距设置 +- 响应式适配不同屏幕尺寸 + +## 使用场景 + +### 表单提交反馈 + +在表单提交后显示操作结果,告知用户提交是否成功。 + +### 操作状态提示 + +在各种操作(如保存、删除、上传等)后显示状态反馈。 + +### 系统消息通知 + +显示系统级别的成功或错误消息,如配置更新、连接状态等。 + +### 数据操作结果 + +在数据增删改查操作后显示操作结果和相关信息。 + +## 注意事项 + +1. 组件需要包裹在 `ConfigProvider` 中以确保主题正常工作 +2. `status` 属性只支持 'success' 和 'error' 两种值 +3. `message` 属性支持任意字符串内容,建议保持简洁明了 +4. 组件会自动处理图标和文字的对齐,无需额外配置 +5. 长文本会自动换行,建议控制消息长度以保持良好的视觉效果 + +## 最佳实践 + +1. **消息简洁**: 保持提醒信息简洁明了,避免冗长的描述 +2. **状态一致**: 在整个应用中使用一致的状态类型和图标 +3. **位置合理**: 将提醒信息放置在用户容易看到的位置 +4. **及时反馈**: 在操作完成后立即显示相应的提醒信息 +5. **样式统一**: 通过主题系统保持提醒信息的样式一致性 + +## 更新日志 + +- **1.0.0**: 初始版本,基于 Typography 组件封装 +- 支持成功和错误两种状态 +- 集成状态对应的图标显示 +- 统一的样式规范和主题系统集成 +- 响应式布局和自动对齐支持 +- 完整的 TypeScript 类型支持 diff --git a/packages/shared/lib/components/ReminderInformation/ReminderInformation.tsx b/packages/dms-kit/src/components/ReminderInformation/ReminderInformation.tsx similarity index 100% rename from packages/shared/lib/components/ReminderInformation/ReminderInformation.tsx rename to packages/dms-kit/src/components/ReminderInformation/ReminderInformation.tsx diff --git a/packages/shared/lib/components/ReminderInformation/ReminderInformation.types.ts b/packages/dms-kit/src/components/ReminderInformation/ReminderInformation.types.ts similarity index 100% rename from packages/shared/lib/components/ReminderInformation/ReminderInformation.types.ts rename to packages/dms-kit/src/components/ReminderInformation/ReminderInformation.types.ts diff --git a/packages/shared/lib/components/ReminderInformation/__tests__/ReminderInformation.test.tsx b/packages/dms-kit/src/components/ReminderInformation/__tests__/ReminderInformation.test.tsx similarity index 100% rename from packages/shared/lib/components/ReminderInformation/__tests__/ReminderInformation.test.tsx rename to packages/dms-kit/src/components/ReminderInformation/__tests__/ReminderInformation.test.tsx diff --git a/packages/shared/lib/components/ReminderInformation/__tests__/__snapshots__/ReminderInformation.test.tsx.snap b/packages/dms-kit/src/components/ReminderInformation/__tests__/__snapshots__/ReminderInformation.test.tsx.snap similarity index 100% rename from packages/shared/lib/components/ReminderInformation/__tests__/__snapshots__/ReminderInformation.test.tsx.snap rename to packages/dms-kit/src/components/ReminderInformation/__tests__/__snapshots__/ReminderInformation.test.tsx.snap diff --git a/packages/dms-kit/src/components/ReminderInformation/demo/basic.tsx b/packages/dms-kit/src/components/ReminderInformation/demo/basic.tsx new file mode 100644 index 000000000..dfcead319 --- /dev/null +++ b/packages/dms-kit/src/components/ReminderInformation/demo/basic.tsx @@ -0,0 +1,113 @@ +import React, { useState } from 'react'; +import { Card, Space, Button, message } from 'antd'; +import { ReminderInformation, ConfigProvider } from '@actiontech/dms-kit'; + +const BasicDemo: React.FC = () => { + const [showSuccess, setShowSuccess] = useState(false); + const [showError, setShowError] = useState(false); + + const handleSuccess = () => { + setShowSuccess(true); + setShowError(false); + message.success('操作成功!'); + }; + + const handleError = () => { + setShowError(true); + setShowSuccess(false); + message.error('操作失败!'); + }; + + const reset = () => { + setShowSuccess(false); + setShowError(false); + }; + + return ( + +
+

基础用法

+ + +
+

点击下方按钮查看不同状态的提醒信息:

+
+ + + + + + + +
+ {showSuccess && ( + + )} + + {showError && ( + + )} + + {!showSuccess && !showError && ( +
+ 点击上方按钮查看提醒信息 +
+ )} +
+
+ + +
+

组件特点:

+
    +
  • + 状态反馈: 支持成功和错误两种状态类型 +
  • +
  • + 图标显示: 自动根据状态显示对应的图标 +
  • +
  • + 文本内容: 支持自定义提醒消息内容 +
  • +
  • + 样式统一: 与设计系统保持一致的视觉风格 +
  • +
  • + 响应式布局: 自动适配不同屏幕尺寸 +
  • +
+
+ +
+

使用场景:

+
    +
  • 表单提交后的结果反馈
  • +
  • 数据操作的状态提示
  • +
  • 系统配置的更新通知
  • +
  • 用户操作的实时反馈
  • +
+
+
+
+
+ ); +}; + +export default BasicDemo; diff --git a/packages/dms-kit/src/components/ReminderInformation/demo/integration.tsx b/packages/dms-kit/src/components/ReminderInformation/demo/integration.tsx new file mode 100644 index 000000000..7a0687a27 --- /dev/null +++ b/packages/dms-kit/src/components/ReminderInformation/demo/integration.tsx @@ -0,0 +1,293 @@ +import React, { useState } from 'react'; +import { + Card, + Space, + Button, + Typography, + Form, + Input, + Select, + message, + Divider, + Alert +} from 'antd'; +import { ReminderInformation, ConfigProvider } from '@actiontech/dms-kit'; +import { + UserOutlined, + LockOutlined, + MailOutlined, + SaveOutlined, + ReloadOutlined +} from '@ant-design/icons'; + +const { Title, Paragraph, Text } = Typography; +const { Option } = Select; + +const IntegrationDemo: React.FC = () => { + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const [showSuccess, setShowSuccess] = useState(false); + const [showError, setShowError] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + + const handleSubmit = async (values: any) => { + setLoading(true); + setShowSuccess(false); + setShowError(false); + + // 模拟异步提交 + try { + await new Promise((resolve, reject) => { + setTimeout(() => { + // 模拟随机成功/失败 + if (Math.random() > 0.3) { + resolve(values); + } else { + reject(new Error('网络连接失败,请检查网络设置')); + } + }, 1500); + }); + + setShowSuccess(true); + message.success('用户创建成功!'); + form.resetFields(); + } catch (error: any) { + setErrorMessage(error.message || '操作失败,请重试'); + setShowError(true); + message.error('用户创建失败!'); + } finally { + setLoading(false); + } + }; + + const resetForm = () => { + form.resetFields(); + setShowSuccess(false); + setShowError(false); + }; + + return ( + +
+

集成使用

+ + +
+

在表单提交后使用 ReminderInformation 显示操作结果:

+
+ +
+ + } placeholder="请输入用户名" /> + + + + } placeholder="请输入邮箱" /> + + + + + + + + } + placeholder="请输入密码" + /> + + + + + + + + + + + {/* 操作结果反馈 */} +
+ {showSuccess && ( + + )} + + {showError && ( + + )} +
+
+ + +
+

在批量操作中使用 ReminderInformation 显示操作结果:

+
+ + +
+ 批量导入结果: + +
+ +
+ 批量删除结果: + +
+ +
+ 权限批量更新: + +
+
+
+ + +
+

在系统状态监控中使用 ReminderInformation:

+
+ + +
+ 系统维护通知: + +
+ +
+ 数据库连接状态: + +
+ +
+ 备份任务状态: + +
+
+
+ + +
+

集成场景:

+
    +
  • + 表单操作: 在表单提交后显示操作结果 +
  • +
  • + 批量操作: 在批量处理完成后显示结果统计 +
  • +
  • + 系统状态: 显示系统运行状态和重要通知 +
  • +
  • + 异步操作: 在异步操作完成后提供反馈 +
  • +
+
+ + + +
+

集成方式:

+
    +
  • + 条件渲染: 根据操作状态条件性显示组件 +
  • +
  • + 状态管理: 通过状态管理控制显示时机 +
  • +
  • + 事件驱动: 在用户操作事件后触发显示 +
  • +
  • + 定时更新: 定时更新系统状态信息 +
  • +
+
+ +
+

最佳实践:

+
    +
  • 在操作完成后立即显示结果反馈
  • +
  • 提供具体的操作结果和后续指导
  • +
  • 使用合适的消息长度和详细程度
  • +
  • 考虑消息的自动消失和手动关闭
  • +
  • 保持与整体界面风格的一致性
  • +
+
+ +
+ +
+
+
+
+ ); +}; + +export default IntegrationDemo; diff --git a/packages/dms-kit/src/components/ReminderInformation/demo/messageContent.tsx b/packages/dms-kit/src/components/ReminderInformation/demo/messageContent.tsx new file mode 100644 index 000000000..32a87b18e --- /dev/null +++ b/packages/dms-kit/src/components/ReminderInformation/demo/messageContent.tsx @@ -0,0 +1,227 @@ +import React, { useState } from 'react'; +import { Card, Space, Typography, Input, Button, Divider, Alert } from 'antd'; +import { ReminderInformation, ConfigProvider } from '@actiontech/dms-kit'; + +const { Title, Paragraph, Text } = Typography; +const { TextArea } = Input; + +const MessageContentDemo: React.FC = () => { + const [successMessage, setSuccessMessage] = useState('操作已成功完成!'); + const [errorMessage, setErrorMessage] = useState('操作失败,请检查后重试。'); + const [customMessage, setCustomMessage] = useState('这是一条自定义的提醒信息,可以包含较长的文本内容。'); + + return ( + +
+

消息内容

+ + +
+

自定义成功和错误状态的消息内容:

+
+ + +
+ 成功消息: +