Bladeren bron

feat: 增加modalStore组件

lanjianrong 4 jaren geleden
bovenliggende
commit
7a1e977a7a

+ 2 - 8
src/app.tsx

@@ -3,12 +3,12 @@ import { history } from 'umi'
 import RightContent from '@/components/RightContent'
 import { message, notification } from 'antd'
 import logo from '../public/logo.svg'
-import BasicModal, { BasicDrawer } from '@/components/Modal'
 import { getToken } from '@/utils/auth'
 import { tryChangeWorkStatus } from './components/RightContent/Book'
 import { getAuthCache, setAuthCache } from './utils/auth'
 import { LAYOUT_COLLAPSED_KEY } from './utils/cache/cacheEnum'
 import consts from './consts'
+import ModalStore from './components/Modal1'
 
 const loginPath = '/user/login'
 
@@ -108,13 +108,7 @@ export const layout = ({ initialState, setInitialState }) => {
       //   permData && setInitialState({ ...initialState, permData })
       // }
     },
-    childrenRender: children => (
-      <>
-        {children}
-        <BasicDrawer />
-        <BasicModal />
-      </>
-    ),
+    childrenRender: children => <ModalStore>{children}</ModalStore>,
     // links: [
     //   <div className="ant-menu-title-content">
     //     <AddressBook theme="outline" className="anticon" />

+ 18 - 0
src/components/Modal1/index.tsx

@@ -0,0 +1,18 @@
+import React from 'react'
+import { createModalHook, ModalStore } from './src'
+import ContactDetail from '@/pages/Customer/Client/components/ClientDetail'
+import CompanyDetail from '@/pages/Customer/Company/components/CompanyDetail'
+import ConnectCompany from '@/pages/Customer/Company/components/ConnectCompany'
+
+const modalMap = {
+  D_CLIENT_DETAIL: ContactDetail,
+  D_COMPANY_DETAIL: CompanyDetail,
+  M_CONNECT_COMPANY: ConnectCompany
+}
+
+export const useModal = createModalHook<typeof modalMap>()
+export default ({ children }) => (
+  <ModalStore modalMap={modalMap} destroyOnClose="afterClose">
+    {children}
+  </ModalStore>
+)

+ 124 - 0
src/components/Modal1/src/CreateProvider.tsx

@@ -0,0 +1,124 @@
+import React from 'react'
+import { ModalContext } from './context'
+
+export interface ModalFullConfig<T = any> {
+  destroyOnClose?: boolean | string
+  visiblePropName?: string
+  // onClosePropName?: string
+  component: React.ComponentType<T>
+}
+
+export type ModalConfig<T = any> = ModalFullConfig<T> | React.ComponentType<T>
+
+export type ModalConfigMap = Record<string, ModalConfig>
+
+export interface ModalStoreProps extends Omit<ModalFullConfig, 'component'> {
+  children: React.ReactNode
+  modalMap: ModalConfigMap
+}
+
+export interface ModalItem extends Record<string, any> {
+  key: string
+}
+
+export interface ModalStoreState {
+  currentModal: ModalItem[]
+}
+
+class ModalStore extends React.Component<ModalStoreProps, ModalStoreState> {
+  constructor(props: ModalStoreProps) {
+    super(props)
+    this.state = {
+      currentModal: []
+    }
+  }
+
+  // 获取modal的config
+  private getModalConfig(key: string) {
+    const { modalMap = {}, visiblePropName = 'visible', destroyOnClose = true } = this.props
+    let config = modalMap[key]
+    if (typeof config === 'function') config = { component: config }
+    const onClosePropName = key.startsWith('M') ? 'onCancel' : 'onClose'
+
+    return { visiblePropName, onClosePropName, destroyOnClose, config }
+  }
+
+  private setModalState(fn: (prev: ModalItem[]) => ModalItem[]) {
+    this.setState(prev => ({ currentModal: fn(prev.currentModal) }))
+  }
+
+  private getCloseFunction(key: string, cb?: (...args: any[]) => void) {
+    return (...args: any[]) => {
+      const { visiblePropName } = this.getModalConfig(key)
+      this.setModalState(prev => {
+        return prev.map(item => {
+          if (item.key === key) {
+            return { ...item, [visiblePropName]: false }
+          }
+          return item
+        })
+      })
+      if (typeof cb === 'function') {
+        cb(...args)
+      }
+    }
+  }
+
+  private getDestroyFunction(key: string, cb?: (...args: any[]) => void) {
+    return (...args: any[]) => {
+      this.setModalState(prev => prev.filter(v => v.key !== key))
+      if (typeof cb === 'function') {
+        cb(...args)
+      }
+    }
+  }
+
+  private push = (key: string, state: any) => {
+    const { visiblePropName, onClosePropName, destroyOnClose } = this.getModalConfig(key)
+
+    this.setModalState(prevModals => {
+      const defaultProps: any = {
+        [visiblePropName]: true,
+        [onClosePropName]: this.getCloseFunction(key, state[onClosePropName])
+      }
+
+      if (destroyOnClose) {
+        const prop = typeof destroyOnClose === 'string' ? destroyOnClose : onClosePropName
+        defaultProps[prop] = this.getDestroyFunction(key)
+      }
+      const newModal = { ...state, ...defaultProps, key }
+      const nextModals = prevModals.slice()
+      const index = nextModals.findIndex(item => item.key === key)
+      if (index !== -1) nextModals.splice(index, 1)
+      nextModals.push(newModal)
+
+      return nextModals
+    })
+  }
+
+  private renderModal = (item: ModalItem) => {
+    const { config } = this.getModalConfig(item.key)
+    if (config) {
+      // 弹窗
+      if ('component' in config) {
+        return React.createElement(config.component, item)
+      }
+      // 抽屉
+      return React.createElement(config, item)
+    }
+    return null
+  }
+
+  render() {
+    const { currentModal } = this.state
+    const { children } = this.props
+    return (
+      <ModalContext.Provider value={this.push}>
+        {children}
+        {currentModal.map(this.renderModal)}
+      </ModalContext.Provider>
+    )
+  }
+}
+
+export default ModalStore

+ 17 - 0
src/components/Modal1/src/context.ts

@@ -0,0 +1,17 @@
+import React from 'react'
+import type { ModalConfigMap, ModalConfig } from './CreateProvider'
+
+type ReturnModalState<T> = T extends ModalConfig<infer P> ? Partial<P> : T
+
+export type ModalDispatch<T extends ModalConfigMap = any> = <K extends keyof T & string>(
+  key: K,
+  state: ReturnModalState<T[K]>
+) => void
+
+export const ModalContext = React.createContext<ModalDispatch<any>>(() => {})
+
+// export const useModal = () => React.useContext(ModalContext)
+
+export function createModalHook<T extends ModalConfigMap>() {
+  return () => React.useContext<ModalDispatch<T>>(ModalContext)
+}

+ 4 - 0
src/components/Modal1/src/index.ts

@@ -0,0 +1,4 @@
+import { ModalContext, createModalHook } from './context'
+import ModalStore from './CreateProvider'
+
+export { ModalStore, ModalContext, createModalHook }

+ 1 - 1
src/global.less

@@ -192,7 +192,7 @@ input:-webkit-autofill:active {
   color: unset;
 }
 
-.my-drawer.ant-drawer-open {
+.zh-drawer.ant-drawer-open {
   // width: 100% !important; // mask: false
   > .ant-drawer-content-wrapper {
     width: 70% !important;