소스 검색

feat: 添加useModal相关

lanjianrong 5 년 전
부모
커밋
fb5c433db7

+ 1 - 1
src/components/EditableForm/editableFormItem.jsx

@@ -107,7 +107,7 @@ const EditableFormItem = ({
             ref={iRef}
             defaultValue={val}
             className="zh-width-100P"
-            onBlur={save}
+            // onBlur={save}
             onChange={(value, local) => save({ currentTarget: { value, local } })}
           />
         )

+ 3 - 2
src/components/Modal/index.jsx

@@ -1,5 +1,6 @@
 import BasicDrawer from './src/BasicDrawer'
+import BasicModal from './src/BasicModal'
 import { useModal } from './src/index'
 
-export { useModal }
-export default BasicDrawer
+export { useModal, BasicDrawer }
+export default BasicModal

+ 2 - 2
src/components/Modal/src/BasicDrawer.jsx

@@ -2,7 +2,7 @@ import { Drawer } from 'antd'
 import { connect } from 'dva'
 import React, { useState, Fragment, useEffect } from 'react'
 
-const Index = props => {
+const BasicDrawer = props => {
   const {
     visible,
     config: { children, ...resetProps }
@@ -32,4 +32,4 @@ export default connect(({ single }) => ({
   visible: single.drawer.visible,
   drawer: single.drawer,
   config: single.drawer.config
-}))(Index)
+}))(BasicDrawer)

+ 24 - 0
src/components/Modal/src/BasicModal.jsx

@@ -0,0 +1,24 @@
+import { Modal } from 'antd'
+import { connect } from 'dva'
+import React, { Fragment } from 'react'
+
+const BasicModal = props => {
+  const {
+    visible,
+    config: { children, ...resetProps }
+  } = props
+
+  return (
+    <Fragment>
+      <Modal visible={visible} {...resetProps}>
+        {children}
+      </Modal>
+    </Fragment>
+  )
+}
+
+export default connect(({ single }) => ({
+  visible: single.modal.visible,
+  modal: single.modal,
+  config: single.modal.config
+}))(BasicModal)

+ 71 - 0
src/components/Modal/src/components/addCustomerModal/index.jsx

@@ -0,0 +1,71 @@
+import React from 'react'
+import { Modal, Form, Input, Checkbox, Row, Col } from 'antd'
+import { validCascaderRule } from '@/components/LazyCascader'
+import { customerTypeOptions } from '@/consts/customer'
+import LazyCascader from '@/components/LazyCascader'
+
+const AddCustomerModal = props => {
+  const { form } = Form.useForm()
+  return (
+    <Modal {...props}>
+      <Form form={form}>
+        <Form.Item
+          name="companyName"
+          label="客户全称"
+          rules={[{ required: true, message: '请输入客户全称' }]}>
+          <Input />
+        </Form.Item>
+        <Form.Item
+          name="district"
+          label="客户地区"
+          rules={[{ required: true, message: '请选择客户地区' }, { validator: validCascaderRule }]}>
+          <LazyCascader />
+        </Form.Item>
+        <Form.Item name="nature" label="客户性质">
+          <Checkbox.Group options={customerTypeOptions} />
+        </Form.Item>
+        <Form.Item name="address" label="客户地址">
+          <Input />
+        </Form.Item>
+        <Row>
+          <Col span={12}>
+            <Form.Item label="客户传真">
+              <Input />
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="网址">
+              <Input />
+            </Form.Item>
+          </Col>
+        </Row>
+        <Row>
+          <Col span={12}>
+            <Form.Item label="乘车路线">
+              <Input />
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="地标建筑">
+              <Input />
+            </Form.Item>
+          </Col>
+        </Row>
+        <Row>
+          <Col span={12}>
+            <Form.Item label="参考住宿">
+              <Input />
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="备注">
+              <Input />
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    </Modal>
+  )
+}
+
+export default AddCustomerModal

+ 91 - 0
src/components/Modal/src/components/customerModal/index.jsx

@@ -0,0 +1,91 @@
+import { Input, Form, Button } from 'antd'
+import React, { useState, useEffect } from 'react'
+import styles from './index.less'
+import { SearchOutlined, CloseOutlined, PlusOutlined } from '@ant-design/icons'
+import { useDebounceFn } from 'ahooks'
+import { connect } from 'dva'
+import AddCustomerModal from '../addCustomerModal'
+import { createCustomer } from '@/services/customer'
+import consts from '@/basic/consts'
+import { formatValues } from '@/components/LazyCascader'
+
+const SearchModal = ({ data, total, dispatch }) => {
+  const [form] = Form.useForm()
+  const initData = payload => {
+    dispatch({
+      type: 'customer/fetch',
+      payload
+    })
+  }
+  useEffect(() => {
+    if (!data.length) {
+      initData({ page: 1, size: 10 })
+    }
+  }, [])
+  const [state, setState] = useState({
+    searchVal: '',
+    page: 1,
+    size: 10
+  })
+
+  const [visible, setVisible] = useState(false)
+  const onChange = e => {
+    const { value = '' } = e.target || e.currentTarget
+    initData({ search: value, page: state.page, size: state.size })
+  }
+
+  const closeModal = () => {
+    dispatch({
+      type: 'single/changeModal'
+    })
+  }
+  const { run } = useDebounceFn(onChange)
+
+  const addConfirm = async values => {
+    const payload = formatValues(values)
+
+    const { code = -1 } = await createCustomer(payload)
+    if (code === consts.RET_CODE.SUCCESS) {
+      initData()
+    }
+  }
+  return (
+    <div className={['ant-modal-content', styles.modalContainer].join(' ')}>
+      <div className={styles.modalHeader}>
+        <Input
+          prefix={<SearchOutlined />}
+          onChange={run}
+          className={styles.inputSearch}
+          placeholder="输入客户名称搜索"
+        />
+        <span className={styles.closeIcon}>
+          <CloseOutlined onClick={closeModal} />
+        </span>
+      </div>
+      <div className={styles.modalContent}>
+        <span>11</span>
+      </div>
+      <div className={styles.modalFooter}>
+        <Button prefix={<PlusOutlined />} type="primary" onClick={() => setVisible(true)}>
+          添加新客户
+        </Button>
+      </div>
+      <AddCustomerModal
+        visible={visible}
+        title="添加新客户"
+        onCancel={() => setVisible(false)}
+        onOk={() => {
+          form.validateFields().then(values => {
+            form.resetFields()
+            addConfirm(values)
+          })
+        }}
+      />
+    </div>
+  )
+}
+
+export default connect(({ customer }) => ({
+  data: customer.customer,
+  total: customer.total
+}))(SearchModal)

+ 23 - 0
src/components/Modal/src/components/customerModal/index.less

@@ -0,0 +1,23 @@
+.modalContainer {
+  width: 60vw;
+  .modalHeader {
+    position: relative;
+    padding: 1.5rem;
+    .inputSearch {
+      width: 90%;
+    }
+    .closeIcon {
+      position: absolute;
+      top: 5px;
+      right: 7px;
+    }
+  }
+  .modalContent {
+    border-top: 1px solid #dee2e6;
+    border-bottom: 1px solid #dee2e6;
+  }
+
+  .modalFooter {
+    padding: 1.5rem;
+  }
+}

+ 1 - 1
src/components/PopContent/Contacts/index.jsx

@@ -46,7 +46,7 @@ const PopContent = props => {
           </div>
         </Col>
         <Col span={12}>
-          <ContanctTabList clientid={id} />
+          <ContanctTabList />
           <ContanctLowerList log={state.log} servicelist={state.serviceLog} />
         </Col>
       </Row>

+ 1 - 0
src/consts.js

@@ -1,5 +1,6 @@
 import BASE_CONSTS from '@/basic/consts'
 
+// 基础变量,  类型特定的变量请移步consts文件夹进行管理
 export default {
   ...BASE_CONSTS,
   // 自定义变量

+ 17 - 0
src/consts/customer.js

@@ -0,0 +1,17 @@
+export const customerTypeOptions = [
+  { label: '设计', value: '设计' },
+  { label: '造价管理', value: '造价管理' },
+  { label: '业主', value: '业主' },
+  { label: '交通局', value: '交通局' },
+  { label: '公安局', value: '公安局' },
+  { label: '审计', value: '审计' },
+  { label: '财政', value: '财政' },
+  { label: '审核', value: '审核' },
+  { label: '施工', value: '施工' },
+  { label: '咨询', value: '咨询' },
+  { label: '招标代理', value: '招标代理' },
+  { label: '监理', value: '监理' },
+  { label: '学校', value: '学校' },
+  { label: '个人', value: '个人' },
+  { label: '合作伙伴', value: '合作伙伴' }
+]

+ 3 - 1
src/layouts/BasicLayout.jsx

@@ -17,7 +17,8 @@ import { CSSTransition, TransitionGroup } from 'react-transition-group'
 import './amimate.scss'
 import '@icon-park/react/styles/index.less'
 import { IconPark } from '@/components/SvgIcon'
-import BasicDrawer from '@/components/Modal'
+import BasicModal from '@/components/Modal'
+import { BasicDrawer } from '@/components/Modal'
 
 const noMatch = (
   <Result
@@ -156,6 +157,7 @@ const BasicLayout = props => {
       {/* <Authorized authority={authorized.authority} noMatch={noMatch}> */}
       {/* </Authorized> */}
       <BasicDrawer />
+      <BasicModal />
     </ProLayout>
   )
 }

+ 32 - 0
src/models/customer.js

@@ -0,0 +1,32 @@
+import consts from '@/consts'
+import { queryCustomers } from '@/services/customer'
+
+export default {
+  namespace: 'customer',
+  state: {
+    customer: [], // 客户列表
+    total: 0
+  },
+  effects: {
+    *fetch({ payload }, { call, put }) {
+      const response = yield call(queryCustomers, payload)
+      if (response && response.code === consts.RET_CODE.SUCCESS) {
+        yield put({
+          type: 'changeState',
+          payload: {
+            data: response.data
+          }
+        })
+      }
+    }
+  },
+  reducers: {
+    // 通用reducer
+    changeState(state, action) {
+      return {
+        ...state,
+        ...action.payload
+      }
+    }
+  }
+}

+ 26 - 20
src/models/district.js

@@ -20,28 +20,34 @@ export default {
         })
       }
     },
-    *fetchWithValues({ payload = [] }, { call, put }) {
+    *fetchWithValues({ payload = [] }, { call, put, select }) {
       const provinceId = payload[0] //
       const cityId = payload[1]
-      const { code = -1, data = [] } = yield call(queryDistrict, { parentId: provinceId })
-      if (code === consts.RET_CODE.SUCCESS) {
-        const response = yield call(queryDistrict, { parentId: cityId })
-        if (response && response.code === consts.RET_CODE.SUCCESS) {
-          const newData = data.map(item => {
-            const newItem = { ...item }
-            if (item.id === cityId) {
-              newItem.children = response.data
-            }
-            return newItem
-          })
-          yield put({
-            type: 'changeState',
-            payload: {
-              data: newData,
-              parentId: provinceId,
-              level: 1
-            }
-          })
+      const currProvince = yield select(state =>
+        state.district.data.find(item => item.id === provinceId)
+      )
+      // 判断市的数据是否拉取过了
+      if (currProvince && (!currProvince.children || !currProvince.children.length)) {
+        const { code = -1, data = [] } = yield call(queryDistrict, { parentId: provinceId })
+        if (code === consts.RET_CODE.SUCCESS) {
+          const response = yield call(queryDistrict, { parentId: cityId })
+          if (response && response.code === consts.RET_CODE.SUCCESS) {
+            const newData = data.map(item => {
+              const newItem = { ...item }
+              if (item.id === cityId) {
+                newItem.children = response.data
+              }
+              return newItem
+            })
+            yield put({
+              type: 'changeState',
+              payload: {
+                data: newData,
+                parentId: provinceId,
+                level: 1
+              }
+            })
+          }
         }
       }
     }

+ 13 - 5
src/models/single.js

@@ -9,6 +9,7 @@ export default {
     },
     modal: {
       visible: false,
+      // search: null,
       config: {}
     }
   },
@@ -31,15 +32,16 @@ export default {
         payload
       })
     }
+    // *setModalSearchVal({ payload }, { put }) {
+    //   yield put({
+    //     type: 'changeState',
+    //     payload
+    //   })
+    // }
   },
   reducers: {
     // 改变state对应type的config
     changeState(state, action) {
-      console.log('action', action)
-      const a = {
-        [action.payload.type]: { ...state[action.payload.type], config: action.payload.config }
-      }
-      console.log('a', a)
       return {
         ...state,
         [action.payload.type]: { ...state[action.payload.type], config: action.payload.config }
@@ -57,5 +59,11 @@ export default {
         modal: { ...state.modal, visible: !state.modal.visible }
       }
     }
+    // changeModalSearch(state, action) {
+    //   return {
+    //     ...state,
+    //     modal: { ...state.modal, search: action.payload }
+    //   }
+    // }
   }
 }

+ 4 - 1
src/pages/Customer/Contact/index.jsx

@@ -344,9 +344,12 @@ const Contact = props => {
     if (shouldUpdate) {
       initData()
     }
-    // initData()
   }, [shouldUpdate])
 
+  useEffect(() => {
+    initData()
+  }, [])
+
   const handleSearch = value => {
     initData({ search: value })
   }

+ 27 - 4
src/pages/Customer/Test/index.jsx

@@ -1,8 +1,13 @@
 import React, { useRef } from 'react'
-import { Button, Card, Cascader } from 'antd'
+import { Button, Card, Cascader, Input } from 'antd'
 import EditableForm from '@/components/EditableForm'
+import { useModal } from '@/components/Modal'
+import { connect } from 'dva'
+import SearchModal from '@/components/Modal/src/components/customerModal'
 
 const Test = () => {
+  const { toggleModal, setModalProps, dispatch } = useModal()
+
   const iRef = useRef(null)
   const options = [
     {
@@ -62,9 +67,27 @@ const Test = () => {
     }
   ]
   const onClick = () => {
-    console.log(iRef)
-    iRef.current.input.focus()
+    setModalProps({
+      // title: (
+      //   <Input
+      //     prefix={<IconPark type="search" />}
+      //     placeholder="输入客户名称搜索"
+      //     style={{ width: '90%' }}
+      //   />
+      // ),
+      modalRender: node => <SearchModal node={node} />,
+      onCancel: () => toggleModal()
+    })
+    toggleModal()
+    // console.log(iRef)
+    // iRef.current.input.focus()
   }
+  // const modalSearchChange = e => {
+  //   dispatch({
+  //     type: 'single/setModalSearchVal',
+  //     payload
+  //   })
+  // }
   return (
     <Card bordered={false}>
       <EditableForm dataSource={record} columns={columns} />
@@ -74,4 +97,4 @@ const Test = () => {
   )
 }
 
-export default Test
+export default connect()(Test)

+ 27 - 0
src/services/customer.js

@@ -0,0 +1,27 @@
+import request from '@/basic/utils/request'
+import consts from '@/consts'
+
+/**
+ * 获取客户列表
+ * @param {*} payload
+ * @returns 结果集
+ */
+export async function queryCustomers(payload) {
+  const params = { page: 1, size: consts.PAGE_SIZE, ...payload }
+  const data = await request('/api/customer/list', {
+    params: { ...params }
+  })
+  return data
+}
+
+/**
+ * 新建用户
+ * @param {*} payload
+ * @returns
+ */
+export async function createCustomer(payload) {
+  const data = await request.post('/api/customer/add', {
+    data: { ...payload }
+  })
+  return data
+}