Browse Source

feat: 商机新增关联联系人模块

lanjianrong 5 năm trước cách đây
mục cha
commit
88028b04d4

+ 3 - 3
src/components/EditableForm/src/useOptions.js

@@ -23,9 +23,9 @@ export default function useOptions(type) {
 
   useEffect(() => {
     if (type === typeEnum.NATUREIDS) {
-      if (!store.getState().customer.natures.length) {
+      if (!store.getState().company.natures.length) {
         dispatch({
-          type: 'customer/fetch'
+          type: 'company/fetch'
         })
       }
     }
@@ -41,7 +41,7 @@ export default function useOptions(type) {
     return genderOptions
   }
   if (type === typeEnum.NATUREIDS) {
-    return store.getState().customer.natures
+    return store.getState().company.natures
   }
   if (type === typeEnum.DEPARTMENTID) {
     return store.getState().staff.departments

+ 3 - 1
src/pages/Customer/Business/components/BusinessDetail/Form.jsx

@@ -1,7 +1,9 @@
 import { Row, Col } from 'antd'
 import React from 'react'
 import EditableForm from '@/components/EditableForm'
-import ChangeCompanyInput, { ChangeCompMap } from '@/pages/Customer/Client/components/ChangeCompany'
+import ChangeCompanyInput, {
+  ChangeCompMap
+} from '@/pages/Customer/Company/components/ChangeCompany'
 import ChangeStaff from '../ChangeStaff/index'
 import Step from './Step/index'
 

+ 67 - 32
src/pages/Customer/Business/components/BusinessDetail/TabList.jsx

@@ -1,41 +1,46 @@
-import { message, Tabs } from 'antd'
+import { Button, message, Tabs } from 'antd'
 import React, { useEffect, useState } from 'react'
 import consts from '@/consts'
 import { apiAddBusiService } from '@/services/customer'
-import { useDispatch } from 'dva'
-// import ProTable from '@ant-design/pro-table'
+import { useDispatch } from 'umi'
+import { Plus } from '@icon-park/react'
+import ProTable from '@ant-design/pro-table'
 import AddRecord from '@/pages/Customer/Client/components/ContactDetail/AddRecord'
+import ConnectClient from '@/pages/Customer/Client/components/ConnectClient'
+import { ChangeCompMap } from '@/pages/Customer/Company/components/ChangeCompany'
+import { useModal } from '@/components/Modal'
 
-const ContanctTabList = ({ businessId }) => {
+const ContanctTabList = ({ businessId, clientList }) => {
+  const { toggleModal, setModalProps } = useModal()
   const dispatch = useDispatch()
   const [state, setState] = useState({
     params: {},
     visible: false
   })
   // const tRef = useRef()
-  // const columns = [
-  //   {
-  //     dataIndex: 'index',
-  //     valueType: 'indexBorder',
-  //     width: 48
-  //   },
-  //   {
-  //     title: '姓名',
-  //     dataIndex: 'name'
-  //   },
-  //   {
-  //     title: '昵称',
-  //     dataIndex: 'nickname'
-  //   },
-  //   {
-  //     title: '手机',
-  //     dataIndex: 'mobile'
-  //   },
-  //   {
-  //     title: 'QQ',
-  //     dataIndex: 'qq'
-  //   }
-  // ]
+  const columns = [
+    {
+      dataIndex: 'index',
+      valueType: 'indexBorder',
+      width: 48
+    },
+    {
+      title: '姓名',
+      dataIndex: 'clientName'
+    },
+    {
+      title: '昵称',
+      dataIndex: 'nickname'
+    },
+    {
+      title: '手机',
+      dataIndex: 'telephone'
+    },
+    {
+      title: 'QQ',
+      dataIndex: 'qq'
+    }
+  ]
   const [addService, setAddService] = useState({
     visible: false,
     loading: false
@@ -53,13 +58,36 @@ const ContanctTabList = ({ businessId }) => {
     // 刷新数据
     dispatch({
       type: 'refresh/commitAction',
-      payload: 'client'
+      payload: ChangeCompMap.BUSINESS.key
     })
     // await initData()
   }
   useEffect(() => {
     setState({ ...state, params: { ...state.params, businessId } })
   }, [businessId])
+
+  const refreshClient = () => {
+    dispatch({
+      type: 'refresh/commitAction',
+      payload: ChangeCompMap.BUSINESS.key
+    })
+  }
+
+  const showConnectClientModal = () => {
+    setModalProps({
+      width: '60vw',
+      modalRender: () => (
+        <ConnectClient
+          dataId={businessId}
+          onSelect={refreshClient}
+          preUrl={ChangeCompMap.BUSINESS.key}
+        />
+      ),
+      onCancel: () => toggleModal()
+    })
+    toggleModal()
+  }
+
   const { TabPane } = Tabs
   return (
     <div>
@@ -67,16 +95,15 @@ const ContanctTabList = ({ businessId }) => {
         <Tabs>
           <TabPane tab="联系人" key="1">
             <div className="sheet-right-panel">
-              {/* <ProTable
+              <ProTable
                 columns={columns}
                 search={false}
                 toolBarRender={false}
                 params={state.params}
-                actionRef={tRef}
                 rowKey={record => record.id}
-                dataSource={software.longle}
+                dataSource={clientList}
                 pagination={false}
-              /> */}
+              />
             </div>
           </TabPane>
           <TabPane tab="发票" key="2">
@@ -86,6 +113,14 @@ const ContanctTabList = ({ businessId }) => {
       </div>
       <div className="sheet-btns pl-15px pt-15px">
         <AddRecord onConfirm={handleAddService} />
+        <Button
+          type="primary"
+          ghost
+          size="small"
+          className="mr-1"
+          onClick={() => showConnectClientModal()}>
+          <Plus className="mr-1" /> 联系人
+        </Button>
       </div>
     </div>
   )

+ 5 - 4
src/pages/Customer/Business/components/BusinessDetail/index.jsx

@@ -18,13 +18,14 @@ const Detail = props => {
     business: {},
     log: {},
     serviceLog: {},
-    software: {}
+    // software: {},
+    linkClient: {} // 关联的联系人
   })
 
   const initData = async id => {
     setState({ ...state, loading: true })
     const {
-      data: { business = {}, log = {}, service = {} },
+      data: { business = {}, log = {}, linkClient = {}, service = {} },
       code = -1
     } = await getBusinessDetailById({ id })
     if (code === consts.RET_CODE.SUCCESS) {
@@ -34,7 +35,7 @@ const Detail = props => {
           payload: 'business'
         })
       }
-      setState({ ...state, business, serviceLog: service, log, loading: false })
+      setState({ ...state, business, serviceLog: service, log, linkClient, loading: false })
     }
   }
 
@@ -83,7 +84,7 @@ const Detail = props => {
             </div>
           </Col>
           <Col span={12} className="sheet-box-right">
-            <TabList businessId={state.business.id} />
+            <TabList businessId={state.business.id} clientList={state.linkClient.client} />
             <LowerList log={state.log} serviceLog={state.serviceLog} />
           </Col>
         </Row>

+ 31 - 6
src/pages/Customer/Client/components/AddContact/index.jsx

@@ -1,31 +1,56 @@
-import React from 'react'
+import React, { useState, useRef } from 'react'
 import { Form, Row, Col, Button } from 'antd'
 import LazyCascader, { validCascaderRule } from '@/components/LazyCascader'
 import { ModalForm, ProFormSelect, ProFormText } from '@ant-design/pro-form'
 import { Plus } from '@icon-park/react'
 import ModalDrag from '@/components/DragmModal'
+import { ChangeCompMap } from '@/pages/Customer/Company/components/ChangeCompany'
 
-const Addcontact = props => {
-  const { onConfirm, buttonProps } = props
+const AddClient = props => {
+  const { onConfirm, buttonProps, dataId, dataType, btnTitle = '联系人' } = props
+  const formRef = useRef(null)
   const layout = {
     layout: 'horizontal',
     labelCol: { flex: '100px' }
   }
-
+  const [showDataItem, setShowDataItem] = useState(false)
   return (
     <ModalForm
       {...layout}
+      formRef={formRef}
       title={<ModalDrag title={'添加联系人'} />}
       trigger={
         <Button type="primary" {...buttonProps} className="mr-1">
           <Plus className="mr-1" />
-          联系人
+          {btnTitle}
         </Button>
       }
+      submitter={{
+        render: ({ submit }, defaultDoms) => [
+          ...defaultDoms,
+          dataId ? (
+            <Button
+              type="primary"
+              key="2"
+              onClick={() => {
+                setShowDataItem(true)
+                const values = {}
+                if (dataType === ChangeCompMap.BUSINESS.key) {
+                  values.businessId = dataId
+                }
+                formRef.current && formRef.current.setFieldsValue(values)
+                submit()
+              }}>
+              添加并关联
+            </Button>
+          ) : null
+        ]
+      }}
       onFinish={async values => {
         await onConfirm(values)
         return true
       }}>
+      {showDataItem ? <ProFormText name={`${dataType}Id`} hidden /> : null}
       <ProFormText
         name="clientName"
         label="姓名"
@@ -74,4 +99,4 @@ const Addcontact = props => {
   )
 }
 
-export default Addcontact
+export default AddClient

+ 141 - 0
src/pages/Customer/Client/components/ConnectClient/index.jsx

@@ -0,0 +1,141 @@
+import { Input, Button, Spin, message } from 'antd'
+import React, { useState, useEffect, useRef } from 'react'
+import styles from '@/pages/Customer/Company/components/ConnectCompany/index.less'
+import { SearchOutlined, CloseOutlined } from '@ant-design/icons'
+import { useDebounceFn } from 'ahooks'
+import { useDispatch } from 'dva'
+import { apiAddClient, linkBusiWithClient, queryClient } from '@/services/customer'
+import consts from '@/basic/consts'
+import { formatValues } from '@/components/LazyCascader'
+import AddClient from '../AddClient'
+
+const ConnectClient = ({ dataId, onSelect, preUrl }) => {
+  const dispatch = useDispatch()
+  const scrollRef = useRef()
+  const [state, setState] = useState({
+    laoding: true,
+    client: [],
+    searchVal: '',
+    current: 1,
+    pageSize: 10,
+    total: 0
+  })
+  const initData = async params => {
+    const { data: { client, total } = { client: [], total: 0 }, code = -1 } = await queryClient(
+      params
+    )
+    if (code === consts.RET_CODE.SUCCESS) {
+      if (params?.current === 1) {
+        scrollRef.current?.scrollTo({ top: 0 })
+        // 请求的是第一页或者搜索框
+        setState({ ...state, client, total, laoding: false, searchVal: params?.search })
+      } else {
+        setState({
+          ...state,
+          client: state.client.concat(client),
+          total,
+          searchVal: params?.search,
+          laoding: false,
+          current: params?.current || 1
+        })
+      }
+    }
+  }
+
+  useEffect(() => {
+    initData({ current: 1, pageSize: 10 })
+  }, [])
+  const onChange = e => {
+    const { value = '' } = e.target || e.currentTarget
+    initData({ search: value, current: 1, pageSize: state.pageSize })
+  }
+
+  const { run: handleInputChange } = useDebounceFn(onChange)
+  const closeModal = () => {
+    dispatch({
+      type: 'single/changeModal'
+    })
+  }
+
+  const addConfirm = async values => {
+    const payload = formatValues(values)
+    const { code = -1, msg = '新增成功' } = await apiAddClient(payload)
+    if (code === consts.RET_CODE.SUCCESS) {
+      if (Object.hasOwnProperty.call(values, `${preUrl}Id`)) {
+        message.success('新增成功并且绑定成功')
+        onSelect(values.name)
+        closeModal()
+      } else {
+        message.success(msg)
+        initData()
+      }
+    }
+  }
+
+  // 商机关联联系人
+  const connectClient = async clientId => {
+    const { code = -1 } = await linkBusiWithClient({ id: dataId, clientId })
+    if (code === consts.RET_CODE.SUCCESS) {
+      onSelect()
+      closeModal()
+    }
+  }
+
+  const handleListScroll = () => {
+    // 未滚动到底部
+    if (
+      scrollRef.current.scrollHeight - scrollRef.current.clientHeight <=
+      scrollRef.current.scrollTop
+    ) {
+      // 已到底部
+
+      state.current * state.pageSize < state.total &&
+        initData({ current: state.current + 1, pageSize: state.pageSize, search: state.searchVal })
+    }
+  }
+  // const { run: listScroller } = useThrottleFn(handleListScroll)
+
+  return (
+    <div className={['ant-modal-content', styles.modalContainer].join(' ')}>
+      <div className={styles.modalHeader}>
+        <Input
+          prefix={<SearchOutlined />}
+          className={styles.inputSearch}
+          placeholder="输入联系人名称搜索"
+          onChange={handleInputChange}
+        />
+        <span className={styles.closeIcon}>
+          <CloseOutlined onClick={closeModal} />
+        </span>
+      </div>
+      <div className={styles.modalContent} ref={scrollRef} onScroll={handleListScroll}>
+        <Spin spinning={state.laoding}>
+          {state.client.map(item => (
+            <div key={item.id} className={styles.card}>
+              <span className="w-1/6">{item.clientName}</span>
+              <span className="w-1/6">{item.position}</span>
+              <span className="w-1/6">{item.telephone}</span>
+              <span className="w-1/2 flex justify-between">
+                <span>{item.companyName}</span>
+                <Button type="primary" size="small" onClick={() => connectClient(item.id)}>
+                  选择ta
+                </Button>
+              </span>
+            </div>
+          ))}
+        </Spin>
+      </div>
+      <div className={styles.modalFooter}>
+        <AddClient
+          onConfirm={addConfirm}
+          dataId={dataId}
+          dataType={preUrl}
+          buttonProps={{ ghost: true }}
+          btnTitle={'添加并关联到新联系人'}
+        />
+      </div>
+    </div>
+  )
+}
+
+export default ConnectClient

+ 1 - 1
src/pages/Customer/Client/components/ContactDetail/ContanctForm.jsx

@@ -1,7 +1,7 @@
 import { Row, Col, Tooltip } from 'antd'
 import React from 'react'
 import EditableForm from '@/components/EditableForm'
-import ChangeCompanyInput from '@/pages/Customer/Client/components/ChangeCompany'
+import ChangeCompanyInput from '@/pages/Customer/Company/components/ChangeCompany'
 import { connect } from 'umi'
 import PersonLabel from '@/pages/Customer/Company/components/PersonLabel'
 import { Add } from '@icon-park/react'

+ 3 - 3
src/pages/Customer/Client/index.jsx

@@ -1,6 +1,6 @@
 import ContactDetail from '@/pages/Customer/Client/components/ContactDetail'
 import CompanyDetail from '@/pages/Customer/Company/components/CompanyDetail'
-import AddContact from '@/pages/Customer/Client/components/AddContact'
+import AddContact from '@/pages/Customer/Client/components/AddClient'
 import ProTable from '@ant-design/pro-table'
 import { Input, Button, message, Tooltip, Select } from 'antd'
 import { connect } from 'dva'
@@ -17,7 +17,7 @@ import {
 } from '../Company/components/PersonLabel/const'
 import { Add, Down, Check } from '@icon-park/react'
 import { useTableScroll } from '@/hooks/useAutoTable'
-import { apiAddClient, queryContact } from '@/services/customer'
+import { apiAddClient, queryClient } from '@/services/customer'
 import { apiBatchLink } from '@/services/customer'
 import styles from './index.less'
 import { getPermDataList } from '@/utils/auth'
@@ -552,7 +552,7 @@ const Contact = props => {
           const {
             code = -1,
             data: { client = [], total = 0 }
-          } = await queryContact({ ...params, ...sort, ...filter })
+          } = await queryClient({ ...params, ...sort, ...filter })
           setState({ ...state, orderIds: client.map(item => item.id) })
           return {
             data: client,

+ 1 - 1
src/pages/Customer/Company/components/AddCompany/index.jsx

@@ -5,7 +5,7 @@ import LazyCascader from '@/components/LazyCascader'
 import { ModalForm, ProFormText, ProFormCheckbox } from '@ant-design/pro-form'
 import { PlusOutlined } from '@ant-design/icons'
 import { connect } from 'dva'
-import { ChangeCompMap } from '../../../Client/components/ChangeCompany'
+import { ChangeCompMap } from '../ChangeCompany'
 
 const AddCompanyModal = ({ dataId, dataType, onConfirm, dispatch, natures }) => {
   const formRef = useRef()

+ 1 - 1
src/pages/Customer/Client/components/ChangeCompany/index.jsx

@@ -3,7 +3,7 @@ import { LinkOne, LinkInterrupt, Switch } from '@icon-park/react'
 import { Card, Tooltip } from 'antd'
 import React from 'react'
 import styles from './index.less'
-import SearchModal from '@/pages/Customer/Client/components/ConnectCompany'
+import SearchModal from '@/pages/Customer/Company/components/ConnectCompany'
 import { apiDelCustomer } from '@/services/customer'
 import { useDispatch } from 'dva'
 import consts from '@/consts'

src/pages/Customer/Client/components/ChangeCompany/index.less → src/pages/Customer/Company/components/ChangeCompany/index.less


+ 1 - 1
src/pages/Customer/Company/components/CompanyDetail/TabList.jsx

@@ -1,7 +1,7 @@
 import ContactDetail from '@/pages/Customer/Client/components/ContactDetail'
 import React, { useRef, useState } from 'react'
 import { Tabs, message } from 'antd'
-import AddContact from '@/pages/Customer/Client/components/AddContact'
+import AddContact from '@/pages/Customer/Client/components/AddClient'
 import { apiAddClient, apiAddCustomerService } from '@/services/customer'
 import { formatValues } from '@/components/LazyCascader'
 import consts from '@/consts'

+ 2 - 2
src/pages/Customer/Client/components/ConnectCompany/index.jsx

@@ -10,7 +10,7 @@ import consts from '@/basic/consts'
 import { formatValues } from '@/components/LazyCascader'
 import { apiChangeCustomer } from '@/services/customer'
 
-const SearchModal = ({ dataId, onSelect, preUrl }) => {
+const ConnectCompany = ({ dataId, onSelect, preUrl }) => {
   const dispatch = useDispatch()
   const scrollRef = useRef()
   const [state, setState] = useState({
@@ -130,4 +130,4 @@ const SearchModal = ({ dataId, onSelect, preUrl }) => {
   )
 }
 
-export default SearchModal
+export default ConnectCompany

src/pages/Customer/Client/components/ConnectCompany/index.less → src/pages/Customer/Company/components/ConnectCompany/index.less


+ 2 - 2
src/pages/Product/Lock/Lockstore/components/LocksDetail/LockModal.jsx

@@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from 'react'
 import { Modal, Form, Select, Input, Spin, Button, Radio } from 'antd'
 import styles from './index.less'
 import { SearchOutlined } from '@ant-design/icons'
-import { queryContact } from '@/services/customer'
+import { queryClient } from '@/services/customer'
 import { queryLock } from '@/services/lock'
 import consts from '@/basic/consts'
 import { useDebounceFn } from 'ahooks'
@@ -61,7 +61,7 @@ const LockModal = props => {
       }
     }
     if (type === lockTypeEnum.SALE) {
-      const { data: { client, total } = { client: [], total: 0 }, code = -1 } = await queryContact(
+      const { data: { client, total } = { client: [], total: 0 }, code = -1 } = await queryClient(
         params
       )
       if (code === consts.RET_CODE.SUCCESS) {

+ 8 - 1
src/services/customer.js

@@ -72,7 +72,7 @@ export async function apiBatchLink(payload) {
  * 请求联系人列表
  * @param {*} payload 载荷
  */
-export async function queryContact(payload) {
+export async function queryClient(payload) {
   const data = await request.post('/client/list', {
     data: payload
   })
@@ -207,3 +207,10 @@ export async function getBusinessDetailById(params) {
     params
   })
 }
+
+/** 商机关联联系人 */
+export async function linkBusiWithClient(params) {
+  return request.post('/business/link/client', {
+    data: params
+  })
+}