index.jsx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import React, { useState, useEffect, useRef, useMemo } from 'react'
  2. import { connect, useAccess, useModel } from 'umi'
  3. import { getBusinessList } from '@/services/customer'
  4. import consts from '@/consts'
  5. import { Select, Tooltip, Input, Button } from 'antd'
  6. import { Funnel } from '@ant-design/charts'
  7. import BasicTable from '@/components/Table'
  8. import { getAuthCache, getPermAuthCache, setAuthCache } from '@/utils/auth'
  9. import { PermDataTypeEunm } from '@/pages/Customer/Company/components/PermSelect'
  10. import { BUSINESS_GROUP_KEY } from '@/utils/cache/cacheEnum'
  11. import { Plus } from '@icon-park/react'
  12. import { useModal } from '@/components/ModalStore'
  13. const Business = ({ dispatch, groupList, shouldUpdate, loading, refreshGroupList }) => {
  14. const [defaultPermAuthCache, defaultStaffIds] = getPermAuthCache(PermDataTypeEunm.CUSTOMER)
  15. const hasAddPerm = useAccess()?.validatePermByType('business_add')
  16. const dispatchModal = useModal()
  17. const tRef = useRef(null)
  18. const defaultGroupId = getAuthCache(BUSINESS_GROUP_KEY) || null
  19. const [state, setState] = useState({
  20. orderIds: [],
  21. params: { businessGroupId: defaultGroupId },
  22. groupParams: { staffIds: defaultStaffIds, dataPermission: defaultPermAuthCache }
  23. })
  24. const funnelData = useMemo(() => {
  25. if (!groupList?.length) return null
  26. return groupList
  27. .find(item => item.value === state.params.businessGroupId)
  28. ?.items?.filter(item => !item.endProcess)
  29. ?.map(item => ({ ...item, percentage: parseInt(item.percentage, 10) }))
  30. }, [
  31. groupList,
  32. state.params.businessGroupId,
  33. state.groupParams.dataPermission,
  34. state.groupParams.staffIds
  35. ])
  36. const { initialState: { permData } = { permData: {} } } = useModel('@@initialState')
  37. const handleSearch = value => {
  38. tRef.current?.reloadAndRest()
  39. setState({ ...state, params: { ...state.params, search: value } })
  40. }
  41. const initGroupList = (payload = {}) => {
  42. dispatch({
  43. type: 'business/fetchGroup',
  44. payload
  45. })
  46. }
  47. useEffect(() => {
  48. if (!groupList) {
  49. initGroupList(state.groupParams)
  50. }
  51. if (refreshGroupList) {
  52. initGroupList()
  53. dispatch({
  54. type: 'business/toggleRefreshGroupStatus'
  55. })
  56. }
  57. }, [refreshGroupList])
  58. useEffect(() => {
  59. if (shouldUpdate) {
  60. tRef.current.reload()
  61. }
  62. }, [loading, shouldUpdate])
  63. const columns = [
  64. {
  65. dataIndex: 'name',
  66. title: '商机名称',
  67. width: '10%',
  68. render: (text, record) => (
  69. <span
  70. onClick={() =>
  71. dispatchModal('D_BUSINESS_DETAIL', {
  72. dataId: record.id,
  73. orderIds: state.orderIds,
  74. group: groupList
  75. })
  76. }
  77. className="text-primary cursor-pointer hover:text-hex-967bbd"
  78. >
  79. {text}
  80. </span>
  81. )
  82. },
  83. {
  84. dataIndex: 'customerName',
  85. title: '单位名称',
  86. width: '20%',
  87. render: (text, record) =>
  88. record.customerId && (
  89. <span
  90. onClick={() => dispatchModal('D_COMPANY_DETAIL', { dataId: record.customerId })}
  91. className="text-primary cursor-pointer hover:text-hex-967bbd"
  92. >
  93. {text}
  94. </span>
  95. )
  96. },
  97. {
  98. dataIndex: 'businessStatusName',
  99. title: '商机状态',
  100. width: '10%'
  101. },
  102. {
  103. dataIndex: 'responsible',
  104. width: '10%',
  105. title: '负责人'
  106. },
  107. {
  108. dataIndex: 'remark',
  109. title: '备注',
  110. width: '10%'
  111. },
  112. {
  113. dataIndex: 'updateTime',
  114. title: '最后跟进时间',
  115. ellipsis: true
  116. },
  117. {
  118. dataIndex: 'createTime',
  119. title: '创建时间',
  120. ellipsis: true
  121. },
  122. {
  123. dataIndex: 'staffName',
  124. title: '创建人',
  125. width: '10%'
  126. }
  127. ]
  128. const conifg = {
  129. xField: 'name',
  130. yField: 'count',
  131. shape: 'pyramid',
  132. conversionTag: false,
  133. dynamicHeight: true
  134. }
  135. const handleOnPermChange = ({ staffIds, dataPermission }) => {
  136. setState({ ...state, groupParams: { ...state.groupParams, staffIds, dataPermission } })
  137. initGroupList({ staffIds, dataPermission })
  138. }
  139. const handleBussinessChange = id => {
  140. setAuthCache(BUSINESS_GROUP_KEY, id)
  141. setState({
  142. ...state,
  143. params: { ...state.params, businessGroupId: id }
  144. })
  145. }
  146. return (
  147. <div className="h-full w-full flex flex-row justify-between">
  148. <div className="h-full w-1/5 rounded-4px shadow-card">
  149. <div className="p-4 border-b-1 border-solid border-black border-opacity-10 bg-[#f7f9fa] flex justify-around items-center">
  150. <div className="w-1/2 text-md">商机漏斗</div>
  151. <div className="w-1/2">
  152. {groupList?.length ? (
  153. <Select
  154. placeholder="请选择商机组"
  155. size="small"
  156. className="w-full"
  157. bordered={false}
  158. options={groupList}
  159. defaultValue={defaultGroupId}
  160. onChange={handleBussinessChange}
  161. />
  162. ) : null}
  163. </div>
  164. </div>
  165. <div className="p-4 bg-white " style={{ height: 'calc(100% - 1rem*2 - 25px)' }}>
  166. <div className="max-h-1/3">
  167. {funnelData?.length ? <Funnel data={funnelData} {...conifg} /> : null}
  168. </div>
  169. </div>
  170. </div>
  171. <div className="w-4/5">
  172. <div className="ml-8 bg-white shadow-card">
  173. <BasicTable
  174. actionRef={tRef}
  175. mainMenuType="customer"
  176. columnStateType="BUSINESS"
  177. onPermChange={handleOnPermChange}
  178. params={state.params}
  179. rowKey={record => record.id}
  180. columns={columns}
  181. request={async (params, sort, filter) => {
  182. if (!state.params.businessGroupId) {
  183. return {
  184. data: [],
  185. success: true,
  186. total: 0
  187. }
  188. }
  189. const {
  190. code = -1,
  191. data: { business = [], total = 0 }
  192. } = await getBusinessList({ ...params, ...sort, ...filter })
  193. setState({ ...state, orderIds: business.map(item => item.id) })
  194. return {
  195. data: business,
  196. success: code === consts.RET_CODE.SUCCESS,
  197. total
  198. }
  199. }}
  200. search={false}
  201. toolbar={{
  202. search: (
  203. <Tooltip placement="bottom" title="输入商机名称、单位名称">
  204. <Input.Search
  205. style={{ width: '300px' }}
  206. allowClear={true}
  207. placeholder={`在${
  208. permData[PermDataTypeEunm.CUSTOMER]?.find(
  209. item => item.value === defaultPermAuthCache
  210. )?.label
  211. }下搜索`}
  212. onSearch={handleSearch}
  213. />
  214. </Tooltip>
  215. ),
  216. actions: [
  217. <Button
  218. type="primary"
  219. key="add_business"
  220. className="flex items-center"
  221. disabled={!hasAddPerm}
  222. onClick={() =>
  223. dispatchModal('M_BUSINESS_ADD', {
  224. groupList: state.groupList,
  225. reload: () => tRef.current?.reload()
  226. })
  227. }
  228. >
  229. <Plus className="mr-1" />
  230. 商机
  231. </Button>
  232. ]
  233. }}
  234. />
  235. </div>
  236. </div>
  237. </div>
  238. )
  239. }
  240. export default connect(({ business, refresh, loading }) => ({
  241. groupList: business.groupList,
  242. refreshGroupList: business.refreshGroupList,
  243. loading: loading.models.business,
  244. shouldUpdate: refresh.business
  245. }))(Business)