|
@@ -1,48 +1,156 @@
|
|
|
-import { Select } from 'antd'
|
|
|
|
|
-import React from 'react'
|
|
|
|
|
|
|
+/* eslint-disable no-nested-ternary */
|
|
|
|
|
+import { Modal, Tooltip, Menu, Dropdown, message } from 'antd'
|
|
|
|
|
+import React, { useMemo } from 'react'
|
|
|
import styles from './index.less'
|
|
import styles from './index.less'
|
|
|
|
|
+import { useRequest, useDispatch } from 'umi'
|
|
|
|
|
+import { changeGroupStatus } from '@/services/customer'
|
|
|
|
|
+import { CloseOne, SmilingFaceWithSquintingEyes } from '@icon-park/react'
|
|
|
|
|
+import { MinusCircleOutlined, DownOutlined } from '@ant-design/icons'
|
|
|
|
|
|
|
|
-const Step = () => {
|
|
|
|
|
|
|
+const Step = ({ id, statusId, groupStatus = [] }) => {
|
|
|
|
|
+ const dispatch = useDispatch()
|
|
|
|
|
+ const { run: tryChangeStatus } = useRequest(params => changeGroupStatus(params), {
|
|
|
|
|
+ manual: true,
|
|
|
|
|
+ onSuccess: () => {
|
|
|
|
|
+ dispatch({
|
|
|
|
|
+ type: 'refresh/commitAction',
|
|
|
|
|
+ payload: 'business'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const stateMap = {
|
|
|
|
|
+ 1: {
|
|
|
|
|
+ class: 'state-fail',
|
|
|
|
|
+ text: '输单',
|
|
|
|
|
+ icon: <CloseOne className="mr-1" />,
|
|
|
|
|
+ fontColor: 'text-red-500'
|
|
|
|
|
+ },
|
|
|
|
|
+ 2: {
|
|
|
|
|
+ class: 'state-suc',
|
|
|
|
|
+ text: '赢单',
|
|
|
|
|
+ icon: <SmilingFaceWithSquintingEyes className="mr-1" />,
|
|
|
|
|
+ fontColor: 'text-primary'
|
|
|
|
|
+ },
|
|
|
|
|
+ 3: {
|
|
|
|
|
+ class: 'state-invalid',
|
|
|
|
|
+ text: '无效',
|
|
|
|
|
+ icon: <MinusCircleOutlined className="mr-1" />,
|
|
|
|
|
+ fontColor: 'text-gray-500'
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ const op = useMemo(() => {
|
|
|
|
|
+ const mainItems = groupStatus.filter(item => !item.endProcess).sort((a, b) => a.sort - b.sort)
|
|
|
|
|
+ const otherItems = groupStatus.filter(item => item.endProcess).sort((a, b) => a.sort - b.sort)
|
|
|
|
|
+ const selectedItemIdx = mainItems.findIndex(item => item.selected)
|
|
|
|
|
+ const endItemIdx = otherItems.findIndex(item => item.id === statusId)
|
|
|
|
|
+ const isSelected = mainItems.findIndex(item => item.selected) !== -1
|
|
|
|
|
+ const isEnd = otherItems.findIndex(item => item.id === statusId) !== -1
|
|
|
|
|
+ return { mainItems, otherItems, isSelected, isEnd, selectedItemIdx, endItemIdx }
|
|
|
|
|
+ }, [id, statusId])
|
|
|
|
|
+
|
|
|
|
|
+ const menu = (
|
|
|
|
|
+ <Menu
|
|
|
|
|
+ className="w-120px"
|
|
|
|
|
+ onClick={e => {
|
|
|
|
|
+ if (!op.isSelected) {
|
|
|
|
|
+ return message.error('请选选择阶段再结束')
|
|
|
|
|
+ }
|
|
|
|
|
+ return Modal.confirm({
|
|
|
|
|
+ title: '提示',
|
|
|
|
|
+ content: `确认进行${op.otherItems.find(item => item.id === e.key).name}操作`,
|
|
|
|
|
+ onOk: () => {
|
|
|
|
|
+ tryChangeStatus({ id, businessStatusId: e.key })
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }}>
|
|
|
|
|
+ {op.otherItems.map(item => (
|
|
|
|
|
+ <Menu.Item key={item.id}>
|
|
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
|
|
+ <span className={stateMap[item.key]?.fontColor}>
|
|
|
|
|
+ {stateMap[item.key]?.icon}
|
|
|
|
|
+ {stateMap[item.key]?.text}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span>{item.percentage}%</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Menu.Item>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </Menu>
|
|
|
|
|
+ )
|
|
|
return (
|
|
return (
|
|
|
<div className={['busi-state', styles.businessStep].join(' ')}>
|
|
<div className={['busi-state', styles.businessStep].join(' ')}>
|
|
|
- <div className="busi-state-item state-suc">
|
|
|
|
|
- <span className="title ">验证客户</span>
|
|
|
|
|
- <div className="state-circle circle-left" />
|
|
|
|
|
- <div className="state-arrow arrow-right" />
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="busi-state-item state-doing">
|
|
|
|
|
- <span className="title">需求分析</span>
|
|
|
|
|
- <div className="state-arrow arrow-left" />
|
|
|
|
|
- <div className="state-arrow arrow-right" />
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="busi-state-item state-doing">
|
|
|
|
|
- <span className="title">需求分析</span>
|
|
|
|
|
- <div className="state-arrow arrow-left" />
|
|
|
|
|
- <div className="state-arrow arrow-right" />
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="busi-state-item state-doing">
|
|
|
|
|
- <span className="title">需求分析</span>
|
|
|
|
|
- <div className="state-arrow arrow-left" />
|
|
|
|
|
- <div className="state-arrow arrow-right" />
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="busi-state-item state-undo">
|
|
|
|
|
- <span className="title">方案/报价</span>
|
|
|
|
|
- <div className="state-arrow arrow-left" />
|
|
|
|
|
- <div className="state-arrow arrow-right" />
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="busi-state-item state-undo">
|
|
|
|
|
|
|
+ {op.mainItems.map((item, idx) => (
|
|
|
|
|
+ <Tooltip
|
|
|
|
|
+ placement="bottom"
|
|
|
|
|
+ title={
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <p>{item.name}</p>
|
|
|
|
|
+ <p>赢单率{item.percentage}%</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }
|
|
|
|
|
+ key={item.id}>
|
|
|
|
|
+ <div
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ if (!op.isEnd) {
|
|
|
|
|
+ if (idx < op.selectedItemIdx) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (idx > op.selectedItemIdx + 1) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ Modal.confirm({
|
|
|
|
|
+ title: '提示',
|
|
|
|
|
+ content: `确认进入${item.name}阶段`,
|
|
|
|
|
+ onOk: () => {
|
|
|
|
|
+ tryChangeStatus({ id, businessStatusId: item.id })
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }}
|
|
|
|
|
+ className={`busi-state-item ${
|
|
|
|
|
+ op.isEnd
|
|
|
|
|
+ ? item.selected
|
|
|
|
|
+ ? 'state-suc'
|
|
|
|
|
+ : 'state-invalid'
|
|
|
|
|
+ : op.selectedItemIdx === idx
|
|
|
|
|
+ ? 'state-doing'
|
|
|
|
|
+ : op.selectedItemIdx > idx
|
|
|
|
|
+ ? 'state-suc'
|
|
|
|
|
+ : 'state-undo'
|
|
|
|
|
+ }`}>
|
|
|
|
|
+ <span className="title ">{item.name}</span>
|
|
|
|
|
+ {idx === 0 ? (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <div className="state-circle circle-left " />
|
|
|
|
|
+ <div className="state-arrow arrow-right" />
|
|
|
|
|
+ </>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <div className="state-arrow arrow-left " />
|
|
|
|
|
+ <div className="state-arrow arrow-right" />
|
|
|
|
|
+ </>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Tooltip>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`busi-state-item ${
|
|
|
|
|
+ op.isEnd ? stateMap[op.otherItems[op.endItemIdx].endProcess].class : 'state-undo'
|
|
|
|
|
+ }`}>
|
|
|
<span className="title">
|
|
<span className="title">
|
|
|
- <Select
|
|
|
|
|
- dropdownStyle={{ width: '60px' }}
|
|
|
|
|
- placeholder="结束"
|
|
|
|
|
- dropdownMatchSelectWidth={false}
|
|
|
|
|
- bordered={false}
|
|
|
|
|
- options={[
|
|
|
|
|
- { label: '赢单', value: '1' },
|
|
|
|
|
- { label: '输单', value: '2' },
|
|
|
|
|
- { label: '无效', value: '3' }
|
|
|
|
|
- ]}
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ {op.isEnd ? (
|
|
|
|
|
+ <>
|
|
|
|
|
+ {stateMap[op.otherItems[op.endItemIdx].endProcess].icon}
|
|
|
|
|
+ {stateMap[op.otherItems[op.endItemIdx].endProcess].text}
|
|
|
|
|
+ </>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <Dropdown overlay={menu}>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <span className="mr-1">结束</span>
|
|
|
|
|
+ <DownOutlined />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Dropdown>
|
|
|
|
|
+ )}
|
|
|
</span>
|
|
</span>
|
|
|
<div className="state-arrow arrow-left" />
|
|
<div className="state-arrow arrow-left" />
|
|
|
<div className="state-circle circle-right" />
|
|
<div className="state-circle circle-right" />
|