| | |
| | | import { PageContainer } from '@ant-design/pro-components'; |
| | | import { Button, Cascader, Checkbox, Empty, Input, message, Spin, Tag } from 'antd'; |
| | | import { PlusOutlined } from '@ant-design/icons'; |
| | | import { useEffect, useMemo, useState } from 'react'; |
| | | import { allAreaList } from '@/utils/area'; |
| | | import { Button, Checkbox, Empty, message, Spin } from 'antd'; |
| | | import { useEffect, useState } from 'react'; |
| | | import { getList, update } from './service'; |
| | | import styles from './style.less'; |
| | | |
| | | const PLATFORM_OPTIONS = [ |
| | | { label: '京东', value: 'jd' }, |
| | | { label: '淘宝', value: 'tm' }, |
| | | { label: '抖音', value: 'douyin' }, |
| | | { label: '拼多多', value: 'pdd' }, |
| | | ]; |
| | | const commaTextToNumberArray = (value) => |
| | | value |
| | | ? String(value) |
| | | .split(',') |
| | | .map((item) => Number(item.trim())) |
| | | .filter(Number.isFinite) |
| | | : []; |
| | | |
| | | const commaTextToArray = (value) => (value ? String(value).split(',').filter(Boolean) : []); |
| | | |
| | | const arraysEqual = (a = [], b = []) => a.length === b.length && a.join(',') === b.join(','); |
| | | |
| | | const buildAreaOptions = () => { |
| | | const codeMap = {}; |
| | | const options = (allAreaList || []).map((provinceItem) => { |
| | | codeMap[provinceItem.value] = provinceItem.province; |
| | | return { |
| | | label: provinceItem.province, |
| | | value: provinceItem.value, |
| | | children: (provinceItem.data || []).map((cityItem) => { |
| | | codeMap[cityItem.value] = cityItem.city; |
| | | return { |
| | | label: cityItem.city, |
| | | value: cityItem.value, |
| | | children: (cityItem.dataList || []).map((areaItem) => { |
| | | codeMap[areaItem.value] = areaItem.area; |
| | | return { |
| | | label: areaItem.area, |
| | | value: areaItem.value, |
| | | }; |
| | | }), |
| | | }; |
| | | }), |
| | | }; |
| | | }); |
| | | return { options, codeMap }; |
| | | }; |
| | | const arraysEqual = (a = [], b = []) => |
| | | a.length === b.length && [...a].sort().join(',') === [...b].sort().join(','); |
| | | |
| | | export default function OutboundRobotSetting() { |
| | | const { options: areaOptions, codeMap } = useMemo(() => buildAreaOptions(), []); |
| | | const [loading, setLoading] = useState(false); |
| | | const [saving, setSaving] = useState(false); |
| | | const [robotList, setRobotList] = useState([]); |
| | | const [draftArea, setDraftArea] = useState({}); |
| | | const [siteOptions, setSiteOptions] = useState([]); |
| | | const [originList, setOriginList] = useState([]); |
| | | |
| | | const loadList = async () => { |
| | |
| | | try { |
| | | const res = await getList(); |
| | | if (String(res?.code) === '200') { |
| | | const list = (res.data || []).map((item) => ({ |
| | | const list = (res?.data?.robotSettings || []).map((item) => ({ |
| | | ...item, |
| | | orderPlatformsArr: commaTextToArray(item.orderPlatforms), |
| | | dialAreaCodesArr: commaTextToArray(item.dialAreaCodes), |
| | | siteIds: commaTextToNumberArray(item.siteIds), |
| | | })); |
| | | setSiteOptions( |
| | | (res?.data?.sites || []).map((item) => ({ label: item.siteName, value: item.id })), |
| | | ); |
| | | setRobotList(list); |
| | | setOriginList( |
| | | list.map((item) => ({ |
| | | id: item.id, |
| | | orderPlatformsArr: [...item.orderPlatformsArr], |
| | | dialAreaCodesArr: [...item.dialAreaCodesArr], |
| | | robotConfigInfo: item.robotConfigInfo || '', |
| | | siteIds: [...item.siteIds], |
| | | })), |
| | | ); |
| | | } else { |
| | |
| | | loadList(); |
| | | }, []); |
| | | |
| | | const setPlatformValue = (id, value) => { |
| | | setRobotList((prev) => prev.map((item) => (item.id === id ? { ...item, orderPlatformsArr: value } : item))); |
| | | }; |
| | | |
| | | const setAreaValue = (id, value) => { |
| | | setDraftArea((prev) => ({ ...prev, [id]: value })); |
| | | }; |
| | | |
| | | const addArea = (id) => { |
| | | const value = draftArea[id]; |
| | | const code = Array.isArray(value) ? value[value.length - 1] : value; |
| | | if (!code) { |
| | | return; |
| | | } |
| | | const setSiteIds = (id, value) => { |
| | | setRobotList((prev) => |
| | | prev.map((item) => { |
| | | if (item.id !== id || item.dialAreaCodesArr.includes(code)) { |
| | | return item; |
| | | } |
| | | return { ...item, dialAreaCodesArr: [...item.dialAreaCodesArr, code] }; |
| | | }), |
| | | prev.map((item) => (item.id === id ? { ...item, siteIds: value } : item)), |
| | | ); |
| | | setDraftArea((prev) => ({ ...prev, [id]: undefined })); |
| | | }; |
| | | |
| | | const removeArea = (id, area) => { |
| | | setRobotList((prev) => |
| | | prev.map((item) => |
| | | item.id === id ? { ...item, dialAreaCodesArr: item.dialAreaCodesArr.filter((text) => text !== area) } : item, |
| | | ), |
| | | ); |
| | | }; |
| | | |
| | | const setConfigInfo = (id, value) => { |
| | | setRobotList((prev) => prev.map((item) => (item.id === id ? { ...item, robotConfigInfo: value } : item))); |
| | | }; |
| | | |
| | | const save = async () => { |
| | |
| | | if (!origin) { |
| | | return true; |
| | | } |
| | | return ( |
| | | !arraysEqual(origin.orderPlatformsArr, item.orderPlatformsArr) || |
| | | !arraysEqual(origin.dialAreaCodesArr, item.dialAreaCodesArr) || |
| | | (origin.robotConfigInfo || '') !== (item.robotConfigInfo || '') |
| | | ); |
| | | return !arraysEqual(origin.siteIds, item.siteIds); |
| | | }); |
| | | |
| | | if (changedList.length === 0) { |
| | |
| | | for (const item of changedList) { |
| | | const res = await update({ |
| | | id: item.id, |
| | | orderPlatforms: (item.orderPlatformsArr || []).join(','), |
| | | dialAreaCodes: (item.dialAreaCodesArr || []).join(','), |
| | | robotConfigInfo: item.robotConfigInfo || '', |
| | | siteIds: item.siteIds || [], |
| | | }); |
| | | if (String(res?.code) !== '200') { |
| | | message.error(res?.msg || `机器人 ${item.robotNumber || item.id} 保存失败`); |
| | |
| | | <Spin spinning={loading}> |
| | | <div className={styles.page}> |
| | | <div className={styles.header}> |
| | | <div className={styles.title}>机器人订单接打区域设置</div> |
| | | <div className={styles.subTitle}>按机器人分别配置订单平台和省市县区拨打范围</div> |
| | | <div className={styles.title}>机器人可外呼站点设置</div> |
| | | <div className={styles.subTitle}>按订单所属站点配置机器人可外呼范围</div> |
| | | </div> |
| | | |
| | | {robotList.length === 0 && !loading ? <Empty description="暂无配置" /> : null} |
| | |
| | | <section className={styles.robotBlock} key={item.id}> |
| | | <div className={styles.robotHead}> |
| | | <div className={styles.robotTitle}>{index + 1}号机器人</div> |
| | | {item.updateTime ? <div className={styles.robotTime}>更新时间:{item.updateTime}</div> : null} |
| | | {item.updateTime ? ( |
| | | <div className={styles.robotTime}>更新时间:{item.updateTime}</div> |
| | | ) : null} |
| | | </div> |
| | | |
| | | <div className={styles.fieldRow}> |
| | |
| | | </div> |
| | | |
| | | <div className={styles.fieldRow}> |
| | | <div className={styles.label}>订单平台</div> |
| | | <div className={styles.label}>可外呼站点</div> |
| | | <div className={styles.value}> |
| | | <Checkbox.Group |
| | | className={styles.platformGroup} |
| | | options={PLATFORM_OPTIONS} |
| | | value={item.orderPlatformsArr} |
| | | onChange={(value) => setPlatformValue(item.id, value)} |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | | <div className={styles.fieldRow}> |
| | | <div className={styles.label}>拨打区域</div> |
| | | <div className={styles.value}> |
| | | <div className={styles.tags}> |
| | | {item.dialAreaCodesArr.map((code) => ( |
| | | <Tag key={code} closable onClose={() => removeArea(item.id, code)}> |
| | | {codeMap[code] || code} |
| | | </Tag> |
| | | ))} |
| | | </div> |
| | | <div className={styles.areaRow}> |
| | | <Cascader |
| | | className={styles.cascader} |
| | | value={draftArea[item.id]} |
| | | options={areaOptions} |
| | | placeholder="请选择省 / 市 / 区" |
| | | changeOnSelect |
| | | expandTrigger="hover" |
| | | onChange={(value) => setAreaValue(item.id, value)} |
| | | /> |
| | | <Button icon={<PlusOutlined />} onClick={() => addArea(item.id)}> |
| | | 添加 |
| | | </Button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div className={styles.fieldRow}> |
| | | <div className={styles.label}>机器人配置信息</div> |
| | | <div className={styles.value}> |
| | | <Input.TextArea |
| | | value={item.robotConfigInfo} |
| | | onChange={(e) => setConfigInfo(item.id, e.target.value)} |
| | | placeholder="请输入机器人配置信息" |
| | | autoSize={{ minRows: 3, maxRows: 6 }} |
| | | className={styles.siteGroup} |
| | | options={siteOptions} |
| | | value={item.siteIds} |
| | | onChange={(value) => setSiteIds(item.id, value)} |
| | | /> |
| | | </div> |
| | | </div> |