You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Global-sales/src/views/orders/Follow.jsx

410 lines
13 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { Conditional } from '@/components/Conditional'
import useAuthStore from '@/stores/AuthStore'
import useFormStore from '@/stores/FormStore'
import { useOrderStore, OrderLabelDefaultOptions, OrderStatusDefaultOptions, RemindStateDefaultOptions } from '@/stores/OrderStore'
import { copy, isNotEmpty } from '@/utils/commons'
import { InfoCircleTwoTone, MailTwoTone, MessageTwoTone, PhoneTwoTone, WhatsAppOutlined } from '@ant-design/icons'
import {
App, Badge, Button,
Col,
DatePicker,
Empty,
Flex, Form, Input,
Radio, Row,
Select, Space, Switch, Table,
Tabs,
Tag, Tooltip
} from 'antd'
import dayjs from 'dayjs'
import { memo, useCallback, useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { useShallow } from 'zustand/react/shallow'
const { RangePicker } = DatePicker
const AdvanceSearchForm = memo(function noName({ initialValues, onSubmit }) {
const DATE_RANGE_PRESETS = [
{
label: '本周',
value: [dayjs().startOf('w'), dayjs().endOf('w')],
},
{
label: '上周',
value: [dayjs().startOf('w').subtract(7, 'days'), dayjs().endOf('w').subtract(7, 'days')],
},
{
label: '本月',
value: [dayjs().startOf('M'), dayjs().endOf('M')],
},
{
label: '上月',
value: [dayjs().subtract(1, 'M').startOf('M'), dayjs().subtract(1, 'M').endOf('M')],
},
{
label: '前三月',
value: [dayjs().subtract(2, 'M').startOf('M'), dayjs().endOf('M')],
},
{
label: '本年',
value: [dayjs().startOf('y'), dayjs().endOf('y')],
},
]
const orderLabelOptions = copy(OrderLabelDefaultOptions)
orderLabelOptions.unshift({ value: '', label: '全部' })
const orderStatusOptions = copy(OrderStatusDefaultOptions)
orderStatusOptions.unshift({ value: '', label: '全部' })
const remindStateOptions = copy(RemindStateDefaultOptions)
remindStateOptions.unshift({ value: '', label: '全部' })
const [form] = Form.useForm()
function handleSubmit(values) {
onSubmit?.(values)
}
return (
<Form
layout={'vertical'}
form={form}
initialValues={{
orderLabel: '', orderStatus: '', remindState: '', ...initialValues
}}
onFinish={handleSubmit}
>
<Row justify='start' gutter={16}>
<Col span={4}>
<Form.Item label='订单号' name='orderNumber'>
<Input placeholder='订单号' allowClear />
</Form.Item>
</Col>
<Col span={4}>
<Form.Item label='邮件地址/客人电话' name='emailOrPhone'>
<Input placeholder='邮件地址/客人电话' allowClear />
</Form.Item>
</Col>
<Col span={4}>
<Form.Item label='First name' name='firstName'>
<Input placeholder='First name' allowClear />
</Form.Item>
</Col>
<Col span={4}>
<Form.Item label='Last name' name='lastName'>
<Input placeholder='Last name' allowClear />
</Form.Item>
</Col>
</Row>
<Row justify='start' align='middle' gutter={16}>
<Col span={2}>
<Form.Item label='标签' name='orderLabel'>
<Select
options={orderLabelOptions}
/>
</Form.Item>
</Col>
<Col span={2}>
<Form.Item label='状态' name='orderStatus'>
<Select
options={orderStatusOptions}
/>
</Form.Item>
</Col>
<Col span={2}>
<Form.Item label='催信' name='remindState'>
<Select
options={remindStateOptions}
/>
</Form.Item>
</Col>
<Col span={4}>
<Form.Item label='出发日期' name='startDateRange'>
<RangePicker
allowClear={true}
inputReadOnly={true}
presets={DATE_RANGE_PRESETS}
/>
</Form.Item>
</Col>
<Col span={4}>
<Form.Item label='确认日期' name='confirmDateRange'>
<RangePicker
allowClear={true}
inputReadOnly={true}
presets={DATE_RANGE_PRESETS}
/>
</Form.Item>
</Col>
<Col span={1} offset={1}>
<Button type='primary' htmlType='submit'>搜索</Button>
</Col>
</Row>
</Form>
)
})
function OrderGroupTable({ formValues }) {
const orderColumns = [
{
title: '订单号',
dataIndex: 'COLI_ID',
width: 222,
render: (text, record) => {
let tagIcon = ''
if (record.COLI_LineGrade === 240003) tagIcon = <Tag color='red'>重点</Tag>
else if (record.COLI_LineGrade === 240002) tagIcon = <Tag color='green'>次重点</Tag>
else if (record.COLI_LineGrade === 240001) tagIcon = <Tag color='blue'>一般</Tag>
return (
<Space>
<Link to={`/order/chat/${record.COLI_SN}`} state={record}>
{text}
</Link>
{tagIcon}
</Space>
)
}
},
{
title: '客人姓名',
dataIndex: 'coli_guest',
render: (text, record) => {
let regularText = ''
if (record.buytime > 0) regularText = '(R' + record.buytime + ')'
return (
<Space>
<Conditional
condition={isNotEmpty(record.coli_guest_WhatsApp)}
whenTrue={<Tooltip title={record.coli_guest_WhatsApp}><WhatsAppOutlined className={['pl-1', record.last_received_time ? 'text-whatsapp' : 'text-neutral-500']} /></Tooltip>}
/>
{text + regularText}
<Badge
count={record.unread_msg}
style={{
backgroundColor: '#52c41a',
}}
/>
</Space>
)
}
},
{
title: '订单状态',
dataIndex: 'COLI_State',
width: 120,
render: (text, record) => {
// 1新订单<InfoCircleTwoTone />2未读消息<MessageTwoTone />3需一催4需二催5需三催<PhoneTwoTone />6未处理邮件<MailTwoTone />
const needTo = '要催信' + (record.coli_ordertype - 2)
let statusIcon = ''
if (record.coli_ordertype === 1) statusIcon = <Tooltip title='新订单'><InfoCircleTwoTone /></Tooltip>
else if (record.coli_ordertype === 2) statusIcon = <Tooltip title='新消息'><MessageTwoTone /></Tooltip>
else if (record.coli_ordertype === 3 || record.coli_ordertype === 4 || record.coli_ordertype === 5) statusIcon = <Tooltip title={needTo}><PhoneTwoTone /></Tooltip>
else if (record.coli_ordertype === 6) statusIcon = <Tooltip title='老邮件'><MailTwoTone /></Tooltip>
return (
<Space>
{statusIcon}
{text}
</Space>
)
}
},
{
title: '报价 Title',
dataIndex: 'lettertitle',
ellipsis: true,
hidden: false,
// render: (text, record) => {
// return (
// <Tooltip title={text}>{text}</Tooltip>
// )
// }
},
{
title: '出发日期',
dataIndex: 'COLI_OrderStartDate',
width: 120,
hidden: false
},
{
title: '客人最后一次回复时间',
dataIndex: 'last_received_time',
width: 180,
render: (text, record) => {
if (record.last_received_time) {
return new dayjs(record.last_received_time).format('YYYY-MM-DD HH:mm:ss')
}
}
},
{
title: '附加信息',
ellipsis: true,
dataIndex: 'COLI_Introduction',
},
]
const { notification } = App.useApp()
const [loading, setLoading] = useState(false)
const orderList = useOrderStore((state) => state.orderList)
const fetchOrderList = useOrderStore((state) => state.fetchOrderList)
const loginUser = useAuthStore((state) => state.loginUser)
useEffect(() => {
let canSearch = true
if (formValues.type === 'advance') {
const copyObject = copy(formValues)
delete copyObject.type
const allEmpty = Object.values(copyObject).every(val => {
return val === null || val === '' || val === undefined
})
if (allEmpty) {
canSearch = false
notification.warning({
message: '温馨提示',
description: '请输入至少一个条件',
placement: 'top',
duration: 60,
})
}
}
if (canSearch) {
setLoading(true)
fetchOrderList(formValues, loginUser)
.finally(() => setLoading(false))
.catch(reason => {
notification.error({
message: '查询出错',
description: reason.message,
placement: 'top',
duration: 60,
})
})
}
}, [formValues])
const paginationProps = {
showQuickJumper: true,
showLessItems: true,
showSizeChanger: true,
showTotal: (total) => { return `总数:${total}` }
}
function groupByParam(array, param) {
return array.reduce((result, item) => {
(result[item[param]] = result[item[param]] || []).push(item)
return result
}, {})
}
const deptMap = new Map([
['1', 'CH直销组'],
['2', 'CH大客户组'],
['7', '市场推广'],
['8', '德语市场'],
['9', '日语市场'],
['10', '商旅市场'],
['11', '法语市场'],
['12', '西语市场'],
['13', '英文在线组'],
['14', '商务Biztravel'],
['15', 'CH产品'],
['16', 'APP移动项目组'],
['17', 'ChinaTravel组'],
['18', 'CT市场'],
['20', '俄语市场'],
['21', '意语市场'],
['22', '爱游网'],
['23', '三峡站'],
['24', '桂林站'],
['25', '上海站'],
['26', '北京站'],
['27', '西藏站'],
['28', 'AH亚洲项目组'],
['29', 'DMC地接组'],
['30', 'Trippest项目组'],
['31', '花梨鹰'],
['32', 'Daytours板块'],
['33', 'GH项目组'],
['34', 'trippest网站'],
['35', 'newsletter营销'],
])
const groupOrderData = groupByParam(orderList, 'OPI_DEI_SN')
const deptKeys = Object.keys(groupOrderData)
const deptItems = []
deptKeys.forEach((deptNo, index) => {
const deptOrderList = groupOrderData[deptNo]
deptItems.push(
{
key: index,
label: deptMap.get(deptNo),
children: <Table key={'Order Table' + deptNo} loading={loading} dataSource={deptOrderList}
columns={orderColumns}
pagination={deptOrderList.length <= 10 ? false : paginationProps} />
}
)
})
return (
<Conditional
condition={orderList.length > 0}
whenTrue={<Tabs defaultActiveKey={0} items={deptItems} />}
whenFalse={<Empty />}
/>
)
}
function Follow() {
const [formValues, setFormValues] = useFormStore(useShallow((state) => [state.orderFollowForm, state.setOrderFollowForm]))
const [advanceChecked, toggleAdvance] = useFormStore(useShallow((state) => [state.orderFollowAdvanceChecked, state.setOrderFollowAdvanceChecked]))
const handleSubmit = useCallback((values) => {
setFormValues({ ...values, type: 'advance' })
}, [])
return (
<>
<Space direction='vertical' size='large' style={{ width: '100%' }}>
<Flex gap='large' justify='start' align='center' horizontal='true'>
<Radio.Group
options={[
{ label: '今日任务', value: 'today' },
{ label: '重点订单', value: 'zhongdian' },
{ label: '次重点客户', value: 'qianli' },
{ label: '成行', value: 'chengxing' },
{ label: '走团中', value: 'zoutuan' },
{ label: '走团后一月', value: 'zoutuanhou' }
]}
value={formValues.type}
onChange={({ target: { value } }) => {
setFormValues({
...formValues,
type: value
})
}}
optionType='button'
buttonStyle='solid'
disabled={advanceChecked}
/>
<Switch checkedChildren='高级查询' unCheckedChildren='高级查询'
checked={advanceChecked}
onChange={() => { toggleAdvance(!advanceChecked) }} />
</Flex>
<Conditional condition={advanceChecked} whenTrue={<AdvanceSearchForm onSubmit={handleSubmit} initialValues={formValues} />}
/>
<OrderGroupTable formValues={formValues} />
</Space>
</>
)
}
export default Follow