style: 历史记录; 即时聊天页的点击滚动

fix: 从订单进入后没有置顶和选中
优化体验: 缓存表单数据: 订单跟踪-高级查询
emoji font
fix:发送引用的消息返回状态时没有原文
获取消息记录
历史记录: 搜索顾问
dev/mobile
Lei OT 2 years ago
parent c73cec8bbc
commit 39f7a35e3d

@ -1,3 +1,10 @@
import { fetchJSON } from '@/utils/request';
import { API_HOST } from '@/config';
/**
* 顾问列表
*/
export const fetchSalesAgent = async (q) => {
const { errcode, result } = await fetchJSON(`https://p9axztuwd7x8a7.mycht.cn/service-Analyse2/GetOperatorInfo`, { q });
return errcode !== 0 ? [] : result.map((ele) => ({ ...ele, label: ele.cn_name, value: ele.op_id }));
};

@ -24,11 +24,18 @@ export const fetchConversationsList = async (params) => {
/**
*
* @param {object} params { opisn, whatsappid, }
* @param {object} params { opisn, whatsappid, lasttime, pagesize }
*/
export const fetchMessages = async (params) => {
const { result } = await fetchJSON(`${API_HOST}/getcusmessages`, params);
return parseRenderMessageList(result || []);
const defaultParams = {
opisn: '',
whatsappid: '',
// lasttime: '',
lasttime: '2024-01-01T00:25:30', // test:
pagesize: 100,
};
const { errcode, result } = await fetchJSON(`${API_HOST}/getcusmessages`, {...defaultParams, ...params});
return errcode !== 0 ? [] : parseRenderMessageList(result || []);
}
export const fetchCustomerProfile = async (colisn) => {

Binary file not shown.

@ -0,0 +1,46 @@
import React, { useMemo, useRef, useState } from 'react';
import { Select, Spin } from 'antd';
import { debounce } from '@/utils/utils';
function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) {
const [fetching, setFetching] = useState(false);
const [options, setOptions] = useState([]);
const fetchRef = useRef(0);
const debounceFetcher = useMemo(() => {
const loadOptions = (value) => {
fetchRef.current += 1;
const fetchId = fetchRef.current;
setOptions([]);
setFetching(true);
fetchOptions(value).then((newOptions) => {
if (fetchId !== fetchRef.current) {
// for fetch callback order
return;
}
setOptions(newOptions);
setFetching(false);
});
};
return debounce(loadOptions, debounceTimeout);
}, [fetchOptions, debounceTimeout]);
return (
<Select
labelInValue
filterOption={false}
showSearch
allowClear
{...props}
onSearch={debounceFetcher}
notFoundContent={fetching ? <Spin size='small' /> : null}
optionFilterProp='label'
>
{options.map((d) => (
<Select.Option key={d.value} title={d.label}>
{d.label}
</Select.Option>
))}
</Select>
);
}
export default DebounceSelect;

@ -213,6 +213,13 @@ export const msgStatusRenderMapped = {
'read': 'read',
'failed': 'failed',
};
export const msgStatusRenderMappedCN = {
'accepted': '[发送ing]',
'sent': '[已发送]',
'delivered': '[已送达]',
'read': '[已读]',
'failed': '❗',
};
export const receivedMsgTypeMapped = {
...cloneDeep(whatsappMsgMapped),
'message': {
@ -272,7 +279,7 @@ export const whatsappMsgTypeMapped = {
photoURL: msg.image.link,
width: '100%',
height: 200,
alt: '',
alt: msg.image?.caption || '',
}),
},
sticker: {
@ -333,6 +340,10 @@ export const whatsappMsgTypeMapped = {
audioURL: msg.audio.link,
},
}),
renderForReply: (msg) => ({
id: msg.wamid,
message: '[语音]',
}),
},
// unsupported: { type: 'system', data: (msg) => ({ text: 'Message type is currently not supported.' }) },
unsupported: {
@ -367,6 +378,10 @@ export const whatsappMsgTypeMapped = {
text: msg.contacts.map((ele) => `${ele.name.formatted_name}: ${ele.phones[0].wa_id}`).join('\n'),
data: msg.contacts.map((ele) => ({ id: ele.phones[0].wa_id, wa_id: ele.phones[0].wa_id, name: ele.name.formatted_name })),
}),
renderForReply: (msg) => ({
id: msg.wamid,
message: '[联系人]',
}),
},
location: {
type: 'location',
@ -381,6 +396,10 @@ export const whatsappMsgTypeMapped = {
},
originText: msg.location?.address || '',
}),
renderForReply: (msg) => ({
id: msg.wamid,
message: '[位置]',
}),
},
// contact: 'contact',
// 'contact-card': 'contact-card',
@ -419,7 +438,9 @@ export const parseRenderMessageItem = (msg) => {
whatsapp_name: msg?.customerProfile?.name || '',
whatsapp_phone_number: msg.from,
whatsapp_msg_type: msg.type,
...((isEmpty(msg.context) && isEmpty(msg.reaction)) || msg.context?.forwarded === true
statusCN: msgStatusRenderMappedCN[msg?.status || 'failed'],
statusTitle: msgStatusRenderMappedCN[msg?.status || 'failed'],
...((isEmpty(msg.context) && isEmpty(msg.reaction)) || msg.context?.forwarded === true || isEmpty(msg.messageorigin)
? {}
: {
reply: {
@ -451,7 +472,7 @@ export const parseRenderMessageList = (messages, conversationid = null) => {
type: msgContent.type,
...(typeof whatsappMsgTypeMapped[msgType].type === 'function' ? whatsappMsgTypeMapped[msgType].type(msg) : { type: whatsappMsgTypeMapped[msgType].type || 'text' }),
date: msgContent?.sendTime || msg.msgtime || '',
localDate: msg.msgtime || '',
localDate: (msg.msgtime || '').replace('T', ' '),
from: msgContent.from,
sender: msgContent.from,
senderName: msgContent?.customerProfile?.name || msgContent.from,
@ -461,6 +482,8 @@ export const parseRenderMessageList = (messages, conversationid = null) => {
senderName: 'me',
status: msgStatusRenderMapped[msgContent?.status || 'failed'],
dateString: msgStatusRenderMapped[msgContent?.status || 'failed'] === 'failed' ? `发送失败 ${whatsappError?.[msgContent.errorCode] || msgContent.errorMessage}` : '',
statusCN: msgStatusRenderMappedCN[msgContent?.status || 'failed'],
statusTitle: msgStatusRenderMappedCN[msgContent?.status || 'failed'],
}
: {}),
...((isEmpty(msg.messageorigin_AsJOSN) && isEmpty(msgContent.context))

@ -27,7 +27,6 @@ const initialConversationState = {
// referenceMsg: {},
aliOSSToken: {},
};
const templatesSlice = (set) => ({
@ -144,13 +143,16 @@ const conversationSlice = (set, get) => ({
return set({ conversationsList, activeConversations: conversationsMapped });
},
addToConversationList: (newList) => {
const { activeConversations } = get();
const { activeConversations, conversationsList } = get();
const conversationsIds = Object.keys(activeConversations);
const newConversations = newList.filter((conversation) => !conversationsIds.includes(`${conversation.sn}`));
const newConversationsMapped = newConversations.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {});
const newListIds = newList.map((chatItem) => `${chatItem.sn}`);
const withoutNew = conversationsList.filter(item => !newListIds.includes(`${item.sn}`));
return set((state) => ({
conversationsList: [...newConversations, ...state.conversationsList],
conversationsList: [...newList, ...withoutNew],
activeConversations: { ...activeConversations, ...newConversationsMapped },
totalNotify: state.totalNotify + newConversations.map((ele) => ele.unread_msg_count).reduce((acc, cur) => acc + (cur || 0), 0),
}));
@ -284,11 +286,10 @@ export const useConversationStore = create(
// state actions
addError: (error) => set((state) => ({ errors: [...state.errors, error] })),
setInitial: (v) => set({ initialState: v }),
setAliOSSToken: (v) => set({ aliOSSToken: v }),
// side effects
fetchInitialData: async (userId) => {
const { addToConversationList, setTemplates, setInitial, receivedMessageList, setAliOSSToken } = get();
const { addToConversationList, setTemplates, setInitial, receivedMessageList } = get();
const conversationsList = await fetchConversationsList({ opisn: userId });
addToConversationList(conversationsList);
@ -298,12 +299,12 @@ export const useConversationStore = create(
setInitial(true);
const autoGetMsgs = conversationsList.length > 5 ? 5 : conversationsList.length;
for (let index = 0; index < autoGetMsgs; index++) {
const chatItem = conversationsList[index];
const msgData = await fetchMessages({ opisn: chatItem.opi_sn, whatsappid: chatItem.whatsapp_phone_number });
receivedMessageList(chatItem.sn, msgData);
}
// const autoGetMsgs = conversationsList.length > 5 ? 5 : conversationsList.length;
// for (let index = 0; index < autoGetMsgs; index++) {
// const chatItem = conversationsList[index];
// const msgData = await fetchMessages({ opisn: chatItem.opi_sn, whatsappid: chatItem.whatsapp_phone_number });
// receivedMessageList(chatItem.sn, msgData);
// }
// for (const chatItem of conversationsList) {
// }
},

@ -1,13 +1,25 @@
import { create } from 'zustand';
import { RealTimeAPI } from '@/lib/realTimeAPI';
import { olog, isEmpty } from '@/utils/utils';
import { receivedMsgTypeMapped, handleNotification } from '@/lib/msgUtils';
import { fetchConversationsList, fetchTemplates, fetchMessages } from '@/actions/ConversationActions';
import { devtools } from 'zustand/middleware';
import { WS_URL } from '@/config';
export const useFormStore = create(devtools((set, get) => ({
chatHistory: {},
setChatHistory: (chatHistory) => set({ chatHistory }),
})));
export const useFormStore = create(
devtools((set, get) => ({
// 历史记录页面
chatHistoryForm: {},
setChatHistoryForm: (chatHistoryForm) => set({ chatHistoryForm, chatHistorySelectChat: {} }),
chatHistorySelectChat: {},
setChatHistorySelectChat: (chatHistorySelectChat) => set({ chatHistorySelectChat }),
// 订单跟踪页面
orderFollowForm: {
type: 'today',
// orderStatus: '新状态',
// orderNumber: '订单号',
// orderLabel: '订单标签',
// startDate: '走团时间',
},
setOrderFollowForm: (orderFollowForm) => set({ orderFollowForm }),
orderFollowAdvanceChecked: false,
setOrderFollowAdvanceChecked: (orderFollowAdvanceChecked) => set({ orderFollowAdvanceChecked }),
}))
);
export default useFormStore;

@ -311,6 +311,20 @@ export const stringToColour = (str) => {
return color;
};
export const debounce = (func, wait, immediate) => {
var timeout;
return function () {
var context = this,
args = arguments;
clearTimeout(timeout);
if (immediate && !timeout) func.apply(context, args);
timeout = setTimeout(function () {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
};
}
export const olog = (text, ...args) => {
console.log(
`%c ${text} `,

@ -8,61 +8,15 @@ import { isEmpty } from '@/utils/utils';
import useFormStore from '@/stores/FormStore';
import { useShallow } from 'zustand/react/shallow';
import { fetchSalesAgent } from '@/actions/CommonActions';
// import SearchInput from '@/components/SearchInput2';
import SearchInput from '@/components/SearchInput';
const { Sider, Content, Header, Footer } = Layout;
const { Search } = Input;
const { RangePicker } = DatePicker;
// https://media-xsp2-1.cdn.whatsapp.net/v/t61.24694-24/424735646_380563021285029_2962758854250800176_n.jpg?ccb=11-4&oh=01_AdTogiVdUE-ToI9uH-VQKTTLyDbP7bocXUQe1OETOeCgcg&oe=65F7C6AB&_nc_sid=e6ed6c&_nc_cat=104
const data = [
{
title: 'Ann',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=0',
msgTime: '03-04 13:45:29',
content:
'Hi, this is Ann from China Highlights travel and it is my pleasure to help your Beijing trip. I have sent you an email with the general idea about you trip. Please check it and if any question or new idea just let me know. We are specailized in customizing tour and I would like to work with you to create a tour itinerary that you like. Look forward to your reply.',
},
{
title: 'David Azhari',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=2',
msgTime: '03-04 16:33:08',
content: 'Hi! I just replied to your email saying that I have a few questions and notes',
},
{
title: 'David Azhari',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=2',
msgTime: '03-04 16:33:34',
content: 'So first, is it possible for you guys to write a PU Invitation letter for visas or no?',
},
{
title: 'Ann',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=0',
msgTime: '03-04 16:33:41',
content: 'you prefer we discuss here or go on by mail ?',
},
{
title: 'David Azhari',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=2',
msgTime: '03-04 16:34:03',
content: 'I prefer by mail if its ok with you',
},
{
title: 'Ann',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=0',
msgTime: '03-04 16:34:28',
content: 'both is okay ,I am typing mail to you now lol and receive your message here.',
},
{
title: 'David Azhari',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=2',
msgTime: '03-05 02:56:37',
content: 'Ok thank you so much',
},
{
title: 'Ann',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=0',
msgTime: '03-04 16:44:03',
content: 'you are welcome I have sent the mail to you ,please check.it is my pleasure to assist you with your tour.',
},
];
// eslint-disable-next-line react/display-name
const SearchForm = memo(function ({ initialValues, onSubmit }) {
@ -79,47 +33,8 @@ const SearchForm = memo(function ({ initialValues, onSubmit }) {
style={{
maxWidth: 'none',
}}>
<Form.Item label='顾问' name='travel' style={{ width: '200px' }}>
<Select
showSearch
placeholder='请选择'
optionFilterProp='children'
filterOption={(input, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
options={[
{
value: '354',
label: '宁艳',
},
{
value: '487',
label: '杨新玲',
},
{
value: '495',
label: '黄雪荣',
},
{
value: '骆梅玉',
label: '骆梅玉',
},
{
value: '586',
label: '秦宇尘',
},
{
value: '606',
label: '莫梦瑶',
},
{
value: '603',
label: '秦雯萱',
},
{
value: '601',
label: '王露加',
},
]}
/>
<Form.Item label='顾问' name='agent' style={{ width: '200px' }}>
<SearchInput placeholder='搜索顾问' fetchOptions={fetchSalesAgent} />
</Form.Item>
<Form.Item label='客人' name='orderLabel' style={{ width: '200px' }}>
<Select
@ -188,10 +103,8 @@ const SearchForm = memo(function ({ initialValues, onSubmit }) {
function ChatHistory() {
// const [formValues, setFormValues] = useState({});
const [formValues, setFormValues] = useFormStore(
useShallow((state) => [state.chatHistory, state.setChatHistory]),
)
const [formValues, setFormValues] = useFormStore(useShallow((state) => [state.chatHistoryForm, state.setChatHistoryForm]));
const [selectedConversation, setSelectedConversation] = useFormStore(useShallow((state) => [state.chatHistorySelectChat, state.setChatHistorySelectChat]));
const handleSubmit = useCallback((values) => {
setFormValues({ ...values });
@ -199,12 +112,11 @@ function ChatHistory() {
const [loading, setLoading] = useState(false);
const [conversationsList, setConversationsList] = useState([]);
const [selectedConversation, setSelectedConversation] = useState({});
const [chatItemMessages, setChatItemMessages] = useState([]);
const getConversationsList = async () => {
setLoading(true);
setChatItemMessages([]);
const data = await fetchConversationsList({ opisn: formValues.travel });
const data = await fetchConversationsList({ opisn: formValues.agent?.value || -1 });
setLoading(false);
setConversationsList(data);
if (data.length === 1) {
@ -239,7 +151,7 @@ function ChatHistory() {
const parts = str.split(/(https?:\/\/[^\s]+|\p{Emoji_Presentation})/gmu).filter((s) => s !== '');
const links = str.match(/https?:\/\/[\S]+/gi) || [];
const emojis = str.match(/([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g) || [];
const extraClass = isEmpty(emojis) ? '' : 'text-base leading-5 emoji-text';
const extraClass = isEmpty(emojis) ? '' : '';
const objArr = parts.reduce((prev, curr, index) => {
if (links.includes(curr)) {
prev.push({ type: 'link', key: curr });
@ -251,16 +163,15 @@ function ChatHistory() {
return prev;
}, []);
return (
<span className={extraClass}>
<span className={`text-base leading-5 emoji-text ${extraClass}`}>
{(objArr || []).map((part, index) => {
if (part.type === 'link') {
return (
<a href={part.key} target='_blank' key={`${part.key}${index}`} rel='noreferrer' className='text-sm'>
<a href={part.key} target='_blank' key={`${part.key}${index}`} rel='noreferrer' className='text-base'>
{part.key}
</a>
);
} else {
// if (part.type === 'emoji')
return part.key;
}
})}
@ -290,7 +201,7 @@ function ChatHistory() {
};
// eslint-disable-next-line react/display-name
const MessageBoxWithRef = forwardRef((props, ref) => (
<li ref={ref}>
<li ref={ref} >
<MessageBox {...props} />
</li>
));
@ -343,10 +254,13 @@ function ChatHistory() {
onTitleClick={() => handlePreview(message)}
notch={false}
text={<RenderText str={message?.text || ''} />}
copiableDate={true}
dateString={message.dateString || message.localDate}
className={['whitespace-pre-wrap', message.whatsapp_msg_type === 'sticker' ? 'bg-transparent' : '', message.sender === 'me' ? 'whatsappme-container' : ''].join(
' '
)}
className={[
'whitespace-pre-wrap mb-2',
message.whatsapp_msg_type === 'sticker' ? 'bg-transparent' : '',
message.sender === 'me' ? 'whatsappme-container' : '',
].join(' ')}
style={{
backgroundColor: message.sender === 'me' ? '#ccd4ae' : '#fff',
}}
@ -362,6 +276,15 @@ function ChatHistory() {
],
}
: {})}
renderAddCmp={
<div className='border-dashed border-0 border-t border-slate-300 text-slate-600 space-x-2 emoji'>
<span>{message.senderName}</span>
<span>{message.dateString || message.localDate}</span>
<span>{message.statusCN}</span>
</div>
}
// date={null}
// status={null}
/>
)}
/>

@ -19,14 +19,16 @@ const Conversations = () => {
const userId = useAuthStore((state) => state.loginUser.userId);
const initialState = useConversationStore((state) => state.initialState);
const activeConversations = useConversationStore((state) => state.activeConversations);
const currentConversation = useConversationStore((state) => state.currentConversation);
const [currentConversation, setCurrentConversation] = useConversationStore((state) => [state.currentConversation, state.setCurrentConversation]);
const conversationsList = useConversationStore((state) => state.conversationsList);
const addToConversationList = useConversationStore((state) => state.addToConversationList);
const delConversationitem = useConversationStore((state) => state.delConversationitem);
const setCurrentConversation = useConversationStore((state) => state.setCurrentConversation);
const receivedMessageList = useConversationStore((state) => state.receivedMessageList);
const setMsgLoading = useConversationStore((state) => state.setMsgLoading);
const [tabSelectedConversation, setTabSelectedConversation] = useState({});
const [tabCnt, setTabCnt] = useState(-1);
const [dataSource, setDataSource] = useState(conversationsList);
useEffect(() => {
setDataSource(conversationsList);
@ -46,16 +48,23 @@ const Conversations = () => {
const getOrderConversationList = async (colisn) => {
const { whatsapp_phone_number } = switchToC;
const whatsappID = coli_guest_WhatsApp || whatsapp_phone_number || '';
let findCurrent = conversationsList.findIndex((item) => item.coli_sn === Number(colisn));
if (!isEmpty(whatsappID)) {
let findCurrentOrderChats = conversationsList.filter((item) => `${item.coli_sn}` === `${colisn}`);
let findCurrentIndex = isEmpty(findCurrentOrderChats) ? -1 : 0; // findCurrentOrderChats.length-1;
let findCurrent = findCurrentOrderChats[findCurrentIndex];
if (findCurrentIndex !== -1) {
addToConversationList(findCurrentOrderChats);
} else if (!isEmpty(whatsappID)) {
const data = await fetchOrderConversationsList({ opisn: userId, colisn: colisn, whatsappid: whatsappID });
if (!isEmpty(data)) {
addToConversationList(data);
findCurrentIndex = 0; // data.length-1; // data.lastIndexOf((item) => item.coli_sn === Number(colisn));
findCurrent = data[findCurrentIndex];
} else {
// findCurrentIndex = conversationsList.findIndex((item) => item.coli_sn === Number(colisn)); // data.findIndex((item) => item.sn === currentConversation.sn);
}
findCurrent = conversationsList.findIndex((item) => item.coli_sn === Number(colisn)); // data.findIndex((item) => item.sn === currentConversation.sn);
}
if (findCurrent !== -1) {
switchConversation(conversationsList[findCurrent]);
if (findCurrentIndex >= 0) {
switchConversation(findCurrent);
} else {
// reset chat window
setCurrentConversation({ sn: '', customer_name: '', coli_sn: order_sn });
@ -64,7 +73,7 @@ const Conversations = () => {
};
const getMessages = async (item) => {
setMsgLoading(true);
const data = await fetchMessages({ opisn: userId, whatsappid: item.whatsapp_phone_number });
const data = await fetchMessages({ opisn: userId, whatsappid: item.whatsapp_phone_number, lasttime: '2024-01-01T00:25:30' });
setMsgLoading(false);
receivedMessageList(item.sn, data);
};
@ -130,11 +139,23 @@ const Conversations = () => {
onChange={(e) => {
setSearchContent(e.target.value);
handleSearchConversations(e.target.value);
setTabCnt(-1);
setTabSelectedConversation({});
}}
onKeyDown={e => {
if (e.key === 'Tab') {
e.preventDefault();
const _this = tabCnt >= dataSource.length-1 ? 0 : tabCnt + 1
setTabCnt(_this);
setTabSelectedConversation(dataSource[_this]);
}
}}
onPressEnter={(e) => {
handleSearchConversations(e.target.value);
searchInputRef.current.blur();
onSwitchConversation(dataSource[0]);
onSwitchConversation(dataSource[(tabCnt < 0 ? 0 : tabCnt)]);
setTabCnt(-1);
setTabSelectedConversation({});
return false;
}}
placeholder='搜索名称'
@ -169,7 +190,9 @@ const Conversations = () => {
date={item.last_received_time}
unread={item.unread_msg_count}
className={
String(item.sn) === String(currentConversation.sn) ? '__active text-primary border-y-0 border-e-0 border-s-4 border-solid border-whatsapp-bg bg-whatsapp-bg' : ''
[String(item.sn) === String(currentConversation.sn) ? '__active text-primary border-y-0 border-e-0 border-s-4 border-solid border-whatsapp-bg bg-whatsapp-bg' : '',
String(item.sn) === String(tabSelectedConversation?.sn) ? ' bg-neutral-200' : ''
].join(' ')
}
onClick={() => onSwitchConversation(item)}
/>

@ -38,8 +38,8 @@ const MessagesList = ({ messages, handlePreview, reference }) => {
const scrollToMessage = (id, index) => {
const _i = index || messages.findIndex((msg) => msg.id === id);
if (reference.current && messageRefs.current[_i]) {
reference.current.scrollTop = messageRefs.current[_i].offsetTop;
if (_i >= 0) {
messageRefs.current[_i].scrollIntoView({ behavior: 'smooth', block: 'start' });
}
};
@ -61,7 +61,7 @@ const MessagesList = ({ messages, handlePreview, reference }) => {
const parts = str.split(/(https?:\/\/[^\s]+|\p{Emoji_Presentation})/gmu).filter((s) => s !== '');
const links = str.match(/https?:\/\/[\S]+/gi) || [];
const emojis = str.match(/([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g) || [];
const extraClass = isEmpty(emojis) ? '' : 'text-base leading-5 emoji-text';
const extraClass = isEmpty(emojis) ? '' : '';
const objArr = parts.reduce((prev, curr, index) => {
if (links.includes(curr)) {
prev.push({ type: 'link', key: curr });
@ -73,11 +73,11 @@ const MessagesList = ({ messages, handlePreview, reference }) => {
return prev;
}, []);
return (
<span className={extraClass}>
<span className={`text-base leading-5 emoji-text ${extraClass}`}>
{(objArr || []).map((part, index) => {
if (part.type === 'link') {
return (
<a href={part.key} target='_blank' key={`${part.key}${index}`} rel='noreferrer' className='text-sm'>
<a href={part.key} target='_blank' key={`${part.key}${index}`} rel='noreferrer' className='text-base'>
{part.key}
</a>
);

@ -1,3 +1,24 @@
@font-face {
font-family: 'Noto Sans';
src: url('/src/assets/noto-sans.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Noto Color Emoji';
src: url('/src/assets/noto-color-emoji.0.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Noto Color Emoji';
src: url('/src/assets/noto-color-emoji.1.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Noto Color Emoji';
src: url('/src/assets/noto-color-emoji.2.woff2') format('woff2');
@ -5,6 +26,34 @@
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Noto Color Emoji';
src: url('/src/assets/noto-color-emoji.3.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Noto Color Emoji';
src: url('/src/assets/noto-color-emoji.4.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Noto Color Emoji';
src: url('/src/assets/noto-color-emoji.5.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Noto Color Emoji';
src: url('/src/assets/noto-color-emoji.6.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Noto Color Emoji';
src: url('/src/assets/noto-color-emoji.7.woff2') format('woff');
@ -53,7 +102,7 @@
}
.chatwindow-wrapper .bg-transparent .rce-mbox{
background: unset;
box-shadow: none;
/* box-shadow: none; */
}
.chatwindow-wrapper .bg-transparent .rce-mbox-left-notch,
.chatwindow-wrapper .bg-transparent .rce-mbox-right-notch
@ -66,11 +115,12 @@
color: #00000073;
}
.chatwindow-wrapper .rce-mbox-text .emoji-text,
.chatwindow-wrapper .rce-mbox-time,
.chatwindow-wrapper .referrer-msg,
.chatwindow-wrapper .rce-mbox-reply-message,
.chatwindow-wrapper .emoji
{
font-family: "Noto Color Emoji", 'Apple Color Emoji', 'Twemoji Mozilla', 'Segoe UI Emoji', 'Segoe UI Symbol', 'EmojiOne Color', 'Android Emoji', Arial, sans-serif;
font-family: 'Noto Sans',"Noto Color Emoji", 'Apple Color Emoji', 'Twemoji Mozilla', 'Segoe UI Emoji', 'Segoe UI Symbol', 'EmojiOne Color', 'Android Emoji', Arial, sans-serif;
font-weight: 500;
}
.chatwindow-wrapper .rce-mbox-text a{
@ -84,6 +134,9 @@
}
.chatwindow-wrapper .rce-mbox-photo .rce-mbox-text{
padding-left: 8px;
padding-right: 8px;
margin: unset;
max-width: unset;
}
.chatwindow-wrapper .rce-mbox-left-notch {
width: 10px;
@ -120,3 +173,10 @@
{
display: inline-block;
}
/** Chat history */
/* .chathistory-wrapper .rce-mbox-time {
user-select: auto;
-webkit-user-select: auto;
-moz-user-select: auto;
}*/

@ -9,10 +9,13 @@ import { Conditional } from '@/components/Conditional'
import useOrderStore from '@/stores/OrderStore'
import useAuthStore from '@/stores/AuthStore'
import { copy } from '@/utils/commons'
import useFormStore from '@/stores/FormStore';
import { useShallow } from 'zustand/react/shallow';
const { RangePicker } = DatePicker
const AdvanceSearchForm = memo(function ({ onSubmit }) {
// eslint-disable-next-line react/display-name
const AdvanceSearchForm = memo(function ({ initialValues, onSubmit }) {
const DATE_RANGE_PRESETS = [
{
@ -49,7 +52,7 @@ const AdvanceSearchForm = memo(function ({ onSubmit }) {
layout={'vertical'}
form={form}
initialValues={{
orderLabel: '', orderStatus: '', remindState: ''
orderLabel: '', orderStatus: '', remindState: '', ...initialValues
}}
onFinish={handleSubmit}
>
@ -164,7 +167,7 @@ function OrderGroupTable({ formValues }) {
if (record.buytime > 0) regularText = '(R' + record.buytime + ')'
return (
<Space>
<Link to={`/order/chat/${record.COLI_SN}`} state={record}>{text + regularText}</Link>
<Link to={`/order/chat/${record.COLI_SN}`} state={record} title={record.coli_guest_WhatsApp}>{text + regularText}</Link>
<Badge
count={record.unread_msg}
style={{
@ -205,7 +208,7 @@ function OrderGroupTable({ formValues }) {
const [loading, setLoading] = useState(false)
const { orderList, fetchOrderList } = useOrderStore()
const { loginUser } = useAuthStore()
useEffect(() => {
let canSearch = true
@ -301,7 +304,7 @@ function OrderGroupTable({ formValues }) {
children: <Table key={'Order Table' + deptNo} loading={loading} dataSource={deptOrderList}
columns={orderColumns}
pagination={deptOrderList.length <= 10 ? false : paginationProps} />
}
}
)
})
@ -311,14 +314,16 @@ function OrderGroupTable({ formValues }) {
function OrderFollow() {
const [advanceChecked, toggleAdvance] = useState(false)
const [formValues, setFormValues] = useState({
type: 'today',
orderStatus: '新状态',
orderNumber: '订单号',
orderLabel: '订单标签',
startDate: '走团时间'
})
// const [advanceChecked, toggleAdvance] = useState(false)
// const [formValues, setFormValues] = useState({
// type: 'today',
// orderStatus: '',
// orderNumber: '',
// orderLabel: '',
// startDate: ''
// })
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' })
@ -352,7 +357,7 @@ function OrderFollow() {
defaultChecked={false}
onChange={() => { toggleAdvance(!advanceChecked) }} />
</Flex>
<Conditional condition={advanceChecked} whenTrue={<AdvanceSearchForm onSubmit={handleSubmit} />}
<Conditional condition={advanceChecked} whenTrue={<AdvanceSearchForm onSubmit={handleSubmit} initialValues={formValues} />}
/>
<OrderGroupTable formValues={formValues} />
</Space>

Loading…
Cancel
Save