|
@@ -1,8 +1,9 @@
|
|
|
-import { Button, Checkbox, Popover, Input } from 'antd'
|
|
|
|
|
-import React, { useState, useRef } from 'react'
|
|
|
|
|
|
|
+import { Button, Checkbox, Popover, Input, message, Spin } from 'antd'
|
|
|
|
|
+import React, { useState, useRef, useEffect } from 'react'
|
|
|
import { connect } from 'dva'
|
|
import { connect } from 'dva'
|
|
|
import styles from './index.scss'
|
|
import styles from './index.scss'
|
|
|
-import { apiConnOrDelTag } from '@/services/customer'
|
|
|
|
|
|
|
+import { apiConnOrDelTag, apiUpdateTag } from '@/services/customer'
|
|
|
|
|
+import consts from '@/basic/consts'
|
|
|
|
|
|
|
|
const DropdownTypeEnum = {
|
|
const DropdownTypeEnum = {
|
|
|
check: 0,
|
|
check: 0,
|
|
@@ -22,10 +23,25 @@ export const LabelModeType = {
|
|
|
column: 0, // 列操作
|
|
column: 0, // 列操作
|
|
|
toolbar: 1 // 常用于表格批量操作
|
|
toolbar: 1 // 常用于表格批量操作
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-export const LabelChangeType = {
|
|
|
|
|
- conn: 0, // 关联标签
|
|
|
|
|
- del: 1 // 删除标签
|
|
|
|
|
|
|
+export const LabelStatusColorMap = {
|
|
|
|
|
+ [TagTypeEnum.PERSONTAG]: [
|
|
|
|
|
+ '#16A085',
|
|
|
|
|
+ '#2980B9',
|
|
|
|
|
+ '#8E44AD',
|
|
|
|
|
+ '#f90000',
|
|
|
|
|
+ '#B8651B',
|
|
|
|
|
+ '#2C3E50',
|
|
|
|
|
+ '#efd200'
|
|
|
|
|
+ ],
|
|
|
|
|
+ [TagTypeEnum.TEAMTAG]: [
|
|
|
|
|
+ '#F8AC59',
|
|
|
|
|
+ '#FF69B4',
|
|
|
|
|
+ '#999999',
|
|
|
|
|
+ '#7186ab',
|
|
|
|
|
+ '#778b72',
|
|
|
|
|
+ '#c292ca',
|
|
|
|
|
+ '#a14751'
|
|
|
|
|
+ ]
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const PersonLabel = props => {
|
|
const PersonLabel = props => {
|
|
@@ -42,16 +58,46 @@ const PersonLabel = props => {
|
|
|
} = props
|
|
} = props
|
|
|
const [dropdownType, setDropdownType] = useState(DropdownTypeEnum.check)
|
|
const [dropdownType, setDropdownType] = useState(DropdownTypeEnum.check)
|
|
|
|
|
|
|
|
- if (!personTags?.length) {
|
|
|
|
|
|
|
+ const [checkedIds, setCheckedIds] = useState(tagIds)
|
|
|
|
|
+ const [showOkBtn, setShowOkBtn] = useState(false)
|
|
|
|
|
+ const initData = () => {
|
|
|
dispatch({
|
|
dispatch({
|
|
|
type: 'customer/fetchTags',
|
|
type: 'customer/fetchTags',
|
|
|
payload: { tagType, tagColumn }
|
|
payload: { tagType, tagColumn }
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 监听勾选的标签的变化,实时显示确认按钮
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ // 只对列操作起效
|
|
|
|
|
+ if (modeType === LabelModeType.column) {
|
|
|
|
|
+ setShowOkBtn(true)
|
|
|
|
|
+ }
|
|
|
|
|
+ }, [checkedIds])
|
|
|
|
|
+ // 列操作->更新个人标签勾选情况
|
|
|
|
|
+ const handleOnConfirm = async () => {
|
|
|
|
|
+ const payload = {
|
|
|
|
|
+ tagIds: checkedIds,
|
|
|
|
|
+ dataId,
|
|
|
|
|
+ dataType: tagColumn,
|
|
|
|
|
+ tagType
|
|
|
|
|
+ }
|
|
|
|
|
+ const { code = -1 } = await apiConnOrDelTag(payload)
|
|
|
|
|
+ if (code === consts.RET_CODE.SUCCESS) {
|
|
|
|
|
+ setShowOkBtn(false)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ if (!personTags?.length) {
|
|
|
|
|
+ initData()
|
|
|
|
|
+ }
|
|
|
|
|
+ }, [])
|
|
|
|
|
+
|
|
|
const menu = (
|
|
const menu = (
|
|
|
<div className="zh-mg-tb-7 zh-mg-lf-14">
|
|
<div className="zh-mg-tb-7 zh-mg-lf-14">
|
|
|
<DropDownMenu
|
|
<DropDownMenu
|
|
|
|
|
+ checkedIds={checkedIds}
|
|
|
|
|
+ setCheckedIds={setCheckedIds}
|
|
|
dataId={dataId}
|
|
dataId={dataId}
|
|
|
personTags={personTags}
|
|
personTags={personTags}
|
|
|
tagIds={tagIds}
|
|
tagIds={tagIds}
|
|
@@ -60,23 +106,23 @@ const PersonLabel = props => {
|
|
|
tagColumn={tagColumn}
|
|
tagColumn={tagColumn}
|
|
|
modeType={modeType}
|
|
modeType={modeType}
|
|
|
checkCallBack={checkCallBack}
|
|
checkCallBack={checkCallBack}
|
|
|
|
|
+ initCallBack={initData}
|
|
|
/>
|
|
/>
|
|
|
<div className="zh-mg-top-5">
|
|
<div className="zh-mg-top-5">
|
|
|
{dropdownType === DropdownTypeEnum.check ? (
|
|
{dropdownType === DropdownTypeEnum.check ? (
|
|
|
- <span
|
|
|
|
|
- onClick={() => setDropdownType(DropdownTypeEnum.edit)}
|
|
|
|
|
- className="zh-primary zh-pointer">
|
|
|
|
|
- 编辑标签
|
|
|
|
|
- </span>
|
|
|
|
|
|
|
+ <div className="zh-justify-between">
|
|
|
|
|
+ <span
|
|
|
|
|
+ onClick={() => setDropdownType(DropdownTypeEnum.edit)}
|
|
|
|
|
+ className="zh-primary zh-pointer">
|
|
|
|
|
+ 编辑标签
|
|
|
|
|
+ </span>
|
|
|
|
|
+ {modeType === LabelModeType.column && showOkBtn ? (
|
|
|
|
|
+ <Button onClick={() => handleOnConfirm()}>确认</Button>
|
|
|
|
|
+ ) : null}
|
|
|
|
|
+ </div>
|
|
|
) : (
|
|
) : (
|
|
|
<>
|
|
<>
|
|
|
- <Button type="primary">确认</Button>
|
|
|
|
|
- <Button
|
|
|
|
|
- type="default"
|
|
|
|
|
- className="zh-mg-left-5"
|
|
|
|
|
- onClick={() => setDropdownType(DropdownTypeEnum.check)}>
|
|
|
|
|
- 取消
|
|
|
|
|
- </Button>
|
|
|
|
|
|
|
+ <Button onClick={() => setDropdownType(DropdownTypeEnum.check)}>返回</Button>
|
|
|
</>
|
|
</>
|
|
|
)}
|
|
)}
|
|
|
</div>
|
|
</div>
|
|
@@ -93,56 +139,58 @@ const DropDownMenu = props => {
|
|
|
// 保存选中的checkbox ids
|
|
// 保存选中的checkbox ids
|
|
|
const {
|
|
const {
|
|
|
tagIds,
|
|
tagIds,
|
|
|
|
|
+ checkedIds,
|
|
|
|
|
+ setCheckedIds,
|
|
|
dataId,
|
|
dataId,
|
|
|
menuType,
|
|
menuType,
|
|
|
tagType,
|
|
tagType,
|
|
|
tagColumn,
|
|
tagColumn,
|
|
|
personTags,
|
|
personTags,
|
|
|
modeType,
|
|
modeType,
|
|
|
- checkCallBack
|
|
|
|
|
|
|
+ checkCallBack,
|
|
|
|
|
+ initCallBack
|
|
|
} = props
|
|
} = props
|
|
|
- const [checkedIds, setCheckedIds] = useState(tagIds)
|
|
|
|
|
|
|
|
|
|
- const [activeId, setActiveId] = useState('')
|
|
|
|
|
|
|
+ const [activeState, setActiveState] = useState({
|
|
|
|
|
+ id: '',
|
|
|
|
|
+ activeId: '',
|
|
|
|
|
+ loading: false
|
|
|
|
|
+ })
|
|
|
const inputRef = useRef(null)
|
|
const inputRef = useRef(null)
|
|
|
- const statusColors = {
|
|
|
|
|
- [TagTypeEnum.PERSONTAG]: [
|
|
|
|
|
- '#16A085',
|
|
|
|
|
- '#2980B9',
|
|
|
|
|
- '#8E44AD',
|
|
|
|
|
- '#f90000',
|
|
|
|
|
- '#B8651B',
|
|
|
|
|
- '#2C3E50',
|
|
|
|
|
- '#efd200'
|
|
|
|
|
- ],
|
|
|
|
|
- [TagTypeEnum.TEAMTAG]: [
|
|
|
|
|
- '#F8AC59',
|
|
|
|
|
- '#FF69B4',
|
|
|
|
|
- '#999999',
|
|
|
|
|
- '#7186ab',
|
|
|
|
|
- '#778b72',
|
|
|
|
|
- '#c292ca',
|
|
|
|
|
- '#a14751'
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
const handleOnchange = async (e, id) => {
|
|
const handleOnchange = async (e, id) => {
|
|
|
const { checked } = e.target
|
|
const { checked } = e.target
|
|
|
- if (modeType === LabelModeType.column) {
|
|
|
|
|
- const payload = {
|
|
|
|
|
- type: checked ? LabelChangeType.conn : LabelChangeType.del,
|
|
|
|
|
- data: { tagId: id, dataId, dataType: tagColumn, tagType }
|
|
|
|
|
- }
|
|
|
|
|
- const { code = -1 } = await apiConnOrDelTag(payload)
|
|
|
|
|
- } else {
|
|
|
|
|
- const ids = checked ? [...checkedIds, id] : checkedIds.filter(item => item)
|
|
|
|
|
- setCheckedIds(ids)
|
|
|
|
|
|
|
+ const ids = checked ? [...checkedIds, id] : checkedIds.filter(item => item)
|
|
|
|
|
+ setCheckedIds(ids)
|
|
|
|
|
+ // 如果是toolbar的操作则要触发对应
|
|
|
|
|
+ if (modeType === LabelModeType.toolbar) {
|
|
|
checkCallBack && checkCallBack(ids)
|
|
checkCallBack && checkCallBack(ids)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const labelOnClick = id => {
|
|
const labelOnClick = id => {
|
|
|
- setActiveId(id)
|
|
|
|
|
|
|
+ setActiveState({ ...activeState, id, activeId: id })
|
|
|
|
|
+ }
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ activeState.id && inputRef.current?.focus()
|
|
|
|
|
+ }, [activeState.id])
|
|
|
|
|
+
|
|
|
|
|
+ const labelTextChange = async (e, oldVal) => {
|
|
|
|
|
+ const { value: newVal = '' } = e.currentTarget
|
|
|
|
|
+ if (newVal && oldVal !== newVal) {
|
|
|
|
|
+ const { code = -1 } = await apiUpdateTag({ name: newVal, id: activeState.id })
|
|
|
|
|
+ if (code === consts.RET_CODE.SUCCESS) {
|
|
|
|
|
+ setActiveState({ ...activeState, loading: true })
|
|
|
|
|
+ initCallBack()
|
|
|
|
|
+ const delayUpdate = () => {
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ setActiveState({ ...activeState, activeId: '', loading: false })
|
|
|
|
|
+ message.success('标签已更新')
|
|
|
|
|
+ }, 500)
|
|
|
|
|
+ }
|
|
|
|
|
+ await delayUpdate()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
return (
|
|
return (
|
|
|
<ul className={styles.labelContent}>
|
|
<ul className={styles.labelContent}>
|
|
@@ -155,7 +203,7 @@ const DropDownMenu = props => {
|
|
|
styles.statusIcon,
|
|
styles.statusIcon,
|
|
|
tagType === TagTypeEnum.PERSONTAG ? styles.suqare : ''
|
|
tagType === TagTypeEnum.PERSONTAG ? styles.suqare : ''
|
|
|
].join(' ')}
|
|
].join(' ')}
|
|
|
- style={{ backgroundColor: statusColors[tagType][idx] }}
|
|
|
|
|
|
|
+ style={{ backgroundColor: LabelStatusColorMap[tagType][idx] }}
|
|
|
/>
|
|
/>
|
|
|
<span>{item.name}</span>
|
|
<span>{item.name}</span>
|
|
|
</div>
|
|
</div>
|
|
@@ -170,26 +218,39 @@ const DropDownMenu = props => {
|
|
|
: null}
|
|
: null}
|
|
|
{menuType === DropdownTypeEnum.edit
|
|
{menuType === DropdownTypeEnum.edit
|
|
|
? personTags.map((item, idx) => (
|
|
? personTags.map((item, idx) => (
|
|
|
- <li
|
|
|
|
|
|
|
+ <Spin
|
|
|
key={item.id}
|
|
key={item.id}
|
|
|
- className={[
|
|
|
|
|
|
|
+ spinning={item.id === activeState.id ? activeState.loading : false}
|
|
|
|
|
+ wrapperClassName={[
|
|
|
styles.menuItem,
|
|
styles.menuItem,
|
|
|
styles.editMenuItem,
|
|
styles.editMenuItem,
|
|
|
- item.id === activeId ? styles.active : ''
|
|
|
|
|
- ].join(' ')}
|
|
|
|
|
- onClick={() => labelOnClick(item.id)}>
|
|
|
|
|
- <div className={styles.editLabel}>
|
|
|
|
|
- <div
|
|
|
|
|
- className={[
|
|
|
|
|
- styles.statusIcon,
|
|
|
|
|
- tagType === TagTypeEnum.PERSONTAG ? styles.suqare : ''
|
|
|
|
|
- ].join(' ')}
|
|
|
|
|
- style={{ backgroundColor: statusColors[tagType][idx] }}
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ item.id === activeState.activeId ? styles.active : ''
|
|
|
|
|
+ ].join(' ')}>
|
|
|
|
|
+ <li onClick={() => labelOnClick(item.id)} style={{ width: '100%' }}>
|
|
|
|
|
+ <div className={styles.editLabel}>
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={[
|
|
|
|
|
+ styles.statusIcon,
|
|
|
|
|
+ tagType === TagTypeEnum.PERSONTAG ? styles.suqare : ''
|
|
|
|
|
+ ].join(' ')}
|
|
|
|
|
+ style={{ backgroundColor: statusColors[tagType][idx] }}
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
- {activeId === item.id ? <Input ref={inputRef} /> : <span>{item.name}</span>}
|
|
|
|
|
- </div>
|
|
|
|
|
- </li>
|
|
|
|
|
|
|
+ {activeState.activeId === item.id ? (
|
|
|
|
|
+ <Input
|
|
|
|
|
+ ref={inputRef}
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ bordered={false}
|
|
|
|
|
+ defaultValue={item.name}
|
|
|
|
|
+ onBlur={e => labelTextChange(e, item.name)}
|
|
|
|
|
+ onPressEnter={e => labelTextChange(e, item.name)}
|
|
|
|
|
+ />
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <span>{item.name}</span>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </li>
|
|
|
|
|
+ </Spin>
|
|
|
))
|
|
))
|
|
|
: null}
|
|
: null}
|
|
|
</ul>
|
|
</ul>
|
|
@@ -197,5 +258,6 @@ const DropDownMenu = props => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export default connect(({ customer }) => ({
|
|
export default connect(({ customer }) => ({
|
|
|
- personTags: customer.personTags
|
|
|
|
|
|
|
+ personTags: customer.personTags,
|
|
|
|
|
+ personTagColorMap: customer.personTagColorMap
|
|
|
}))(PersonLabel)
|
|
}))(PersonLabel)
|