Merge branch 'main' of github.com:hainatravel/global-sales

dev/mobile
Jimmy Liow 2 years ago
commit 107edbf614

@ -0,0 +1,3 @@
import { fetchJSON } from '@/utils/request';
import { API_HOST } from '@/config';

@ -70,6 +70,7 @@ export const sentMsgTypeMapped = {
}), }),
contentToRender: (msg) => ({ contentToRender: (msg) => ({
...msg, ...msg,
whatsapp_msg_type: 'text',
actionId: msg.id, actionId: msg.id,
conversationid: msg.id.split('.')[0], conversationid: msg.id.split('.')[0],
originText: msg.text, originText: msg.text,
@ -96,6 +97,7 @@ export const sentMsgTypeMapped = {
contentToRender: (msg) => ({ contentToRender: (msg) => ({
...msg, ...msg,
...mediaMsg.contentToRender(msg), ...mediaMsg.contentToRender(msg),
whatsapp_msg_type: 'image',
}), }),
}, },
video: { video: {
@ -107,6 +109,7 @@ export const sentMsgTypeMapped = {
contentToRender: (msg) => ({ contentToRender: (msg) => ({
...msg, ...msg,
...mediaMsg.contentToRender(msg), ...mediaMsg.contentToRender(msg),
whatsapp_msg_type: 'video',
}), }),
}, },
whatsappTemplate: { whatsappTemplate: {

@ -26,6 +26,8 @@ const initialConversationState = {
// activeConversations: {}, // 激活的对话的消息列表: { [conversationId]: <messageItem>[] } // activeConversations: {}, // 激活的对话的消息列表: { [conversationId]: <messageItem>[] }
// referenceMsg: {}, // referenceMsg: {},
aliOSSToken: {},
}; };
const templatesSlice = (set) => ({ const templatesSlice = (set) => ({
@ -282,10 +284,11 @@ export const useConversationStore = create(
// state actions // state actions
addError: (error) => set((state) => ({ errors: [...state.errors, error] })), addError: (error) => set((state) => ({ errors: [...state.errors, error] })),
setInitial: (v) => set({ initialState: v }), setInitial: (v) => set({ initialState: v }),
setAliOSSToken: (v) => set({ aliOSSToken: v }),
// side effects // side effects
fetchInitialData: async (userId) => { fetchInitialData: async (userId) => {
const { addToConversationList, setTemplates, setInitial, receivedMessageList } = get(); const { addToConversationList, setTemplates, setInitial, receivedMessageList, setAliOSSToken } = get();
const conversationsList = await fetchConversationsList({ opisn: userId }); const conversationsList = await fetchConversationsList({ opisn: userId });
addToConversationList(conversationsList); addToConversationList(conversationsList);

@ -70,7 +70,7 @@ function AuthApp() {
let interval; let interval;
if (totalNotify > 0) { if (totalNotify > 0) {
interval = setInterval(() => { interval = setInterval(() => {
document.title = isTitleVisible ? `🔔🔥【${totalNotify}条新消息】` : '聊天式销售平台'; document.title = isTitleVisible ? `🔔🔥💬${totalNotify}条新消息】` : '聊天式销售平台';
setIsTitleVisible(!isTitleVisible); setIsTitleVisible(!isTitleVisible);
}, 500); }, 500);
} else { } else {

@ -87,6 +87,9 @@ const Conversations = () => {
const handleConversationItemClose = async (item) => { const handleConversationItemClose = async (item) => {
await fetchConversationItemClose({ conversationid: item.sn, opisn: item.opi_sn }); await fetchConversationItemClose({ conversationid: item.sn, opisn: item.opi_sn });
delConversationitem(item); delConversationitem(item);
if (String(order_sn) === String(item.coli_sn)) {
navigate(`/order/chat`, { replace: true });
}
}; };
return ( return (
<> <>

@ -1,21 +1,13 @@
import { createContext, useContext, useEffect, useState } from 'react'; import { useState } from 'react';
import { Upload, Button, message } from 'antd'; import { Upload, Button, message } from 'antd';
import { import {
SendOutlined,
MessageOutlined,
SmileOutlined,
PictureOutlined,
FileImageOutlined, FileImageOutlined,
CommentOutlined,
UploadOutlined,
CloudUploadOutlined,
FolderAddOutlined,
FilePdfOutlined,
CloseCircleOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import useConversationStore from '@/stores/ConversationStore'; import useConversationStore from '@/stores/ConversationStore';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { API_HOST } from '@/config';
const aliOSSHost = `https://haina-sale-system.oss-cn-shenzhen.aliyuncs.com/WAMedia/`;
/** /**
* image * image
* ext: ani;bmp;gif;ico;jpe;jpeg;jpg;pcx;png;psd;tga;tif;tiff;wmf * ext: ani;bmp;gif;ico;jpe;jpeg;jpg;pcx;png;psd;tga;tif;tiff;wmf
@ -32,26 +24,15 @@ const fileTypes = {
'video': ['3g2','3gp','3gp2','3gpp','amr','amv','asf','avi','bdmv','bik','d2v','divx','drc','dsa','dsm','dsv','evo','f4v','flc','fli','flic','flv','hdmov','ifo','ivf','m1v','m2p','m2t','m2ts','m2v','m4b','m4p','m4v','mkv','mp2v','mp4','mp4v','mpe','mpeg','mpg','mpls','mpv2','mpv4','mov','mts','ogm','ogv','pss','pva','qt','ram','ratdvd','rm','rmm','rmvb','roq','rpm','smil','smk','swf','tp','tpr','ts','vob','vp6','webm','wm','wmp','wmv'], 'video': ['3g2','3gp','3gp2','3gpp','amr','amv','asf','avi','bdmv','bik','d2v','divx','drc','dsa','dsm','dsv','evo','f4v','flc','fli','flic','flv','hdmov','ifo','ivf','m1v','m2p','m2t','m2ts','m2v','m4b','m4p','m4v','mkv','mp2v','mp4','mp4v','mpe','mpeg','mpg','mpls','mpv2','mpv4','mov','mts','ogm','ogv','pss','pva','qt','ram','ratdvd','rm','rmm','rmvb','roq','rpm','smil','smk','swf','tp','tpr','ts','vob','vp6','webm','wm','wmp','wmv'],
}; };
const mockGetOSSData = () => ({ const ImageUpload = ({ disabled }) => {
dir: 'user-dir/', // const currentConversation = useConversationStore(state => state.currentConversation);
expire: '1577811661',
host: '//haina-sale-system.oss-cn-shenzhen.aliyuncs.com',
accessId: 'LTAI5t8FBxiMYTd4tBSZzVy5',
// todo:
policy: 'eGl4aWhhaGFrdWt1ZGFkYQ==',
signature: 'ZGFob25nc2hhbw==',
});
const ImageUpload = ({ disabled, invokeSendMessage }) => {
const currentConversation = useConversationStore(state => state.currentConversation);
const setComplexMsg = useConversationStore(state => state.setComplexMsg); const setComplexMsg = useConversationStore(state => state.setComplexMsg);
const complexMsg = useConversationStore(state => state.complexMsg); const complexMsg = useConversationStore(state => state.complexMsg);
// const aliOSSToken = useConversationStore(state => state.aliOSSToken);
const [uploading, setUploading] = useState(false); const [uploading, setUploading] = useState(false);
const [OSSData, setOSSData] = useState();
const handleSendImage = (file) => { const handleSendImage = (file) => {
console.log(file);
const msgObj = { const msgObj = {
type: file.type, // 'photo', type: file.type, // 'photo',
name: file.name, name: file.name,
@ -60,50 +41,29 @@ const ImageUpload = ({ disabled, invokeSendMessage }) => {
id: uuid(), id: uuid(),
}; };
setComplexMsg(msgObj); setComplexMsg(msgObj);
// invokeSendMessage(msgObj);
}; };
const beforeUpload = async (file) => { const beforeUpload = async (file) => {
console.log('beforeUpload', file);
// 使 FileReader // 使 FileReader
const reader = new FileReader(); const reader = new FileReader();
// let ret = true;
// //
reader.onload = (event) => { reader.onload = (event) => {
const previewSrc = event.target.result; const previewSrc = event.target.result;
// test: src
const dataUri = `https://images.chinahighlights.com/allpicture/2020/04/9330cd3c78a34c81afd3b1fb.jpg`;
// const dataUri = `https://data.chinahighlights.com/video/CH-homepage-video.mp4`;
const suffix = file.name.slice(file.name.lastIndexOf('.')+1); const suffix = file.name.slice(file.name.lastIndexOf('.')+1);
const type = Object.keys(fileTypes).find((type) => fileTypes[type].includes(suffix)); const type = Object.keys(fileTypes).find((type) => fileTypes[type].includes(suffix));
const name = file.name; const name = file.name;
// ret = type === 'photo';
// const filename = Date.now() + suffix; // const filename = Date.now() + suffix;
// file.url = OSSData.dir + filename; const dataUri = aliOSSHost + file.name;
handleSendImage({ previewSrc, dataUri, type, suffix, name}); handleSendImage({ previewSrc, dataUri, type, suffix, name});
}; };
// dataURL // dataURL
reader.readAsDataURL(file); reader.readAsDataURL(file);
return file; return file;
// return ret ? file : false;
// if (!OSSData) return false;
// const expire = Number(OSSData.expire) * 1000;
// if (expire < Date.now()) {
// // await init();
// const result = await mockGetOSSData();
// setOSSData(result);
// }
// const suffix = file.name.slice(file.name.lastIndexOf('.'));
// const filename = Date.now() + suffix;
// file.url = OSSData.dir + filename;
// return file;
}; };
const uploadProps = { const uploadProps = {
name: 'file', name: 'file',
action: 'https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188', action: `${API_HOST}/WAFileUpload`,
// action: OSSData?.host,
headers: { headers: {
authorization: 'authorization-text', 'X-Requested-With': null
}, },
showUploadList: false, showUploadList: false,
// onChange: handleChange, // onChange: handleChange,
@ -115,19 +75,20 @@ const ImageUpload = ({ disabled, invokeSendMessage }) => {
<Upload <Upload
{...uploadProps} {...uploadProps}
onChange={(info) => { onChange={(info) => {
console.log('fileList', info.fileList); // console.log('fileList', info.fileList);
setUploading(info.file.status === 'uploading'); setUploading(info.file.status === 'uploading');
setComplexMsg({...complexMsg, status: 'loading'}) setComplexMsg({...complexMsg, status: 'loading'})
if (info.file.status !== 'uploading') { if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList); // console.log(info.file, info.fileList);
setComplexMsg({...complexMsg, status: info.file.status}) setComplexMsg({...complexMsg, status: info.file.status})
} }
if (info.file.status === 'done') { if (info.file.status === 'done') {
// todo: //
setComplexMsg({...complexMsg, status: info.file.status, data: { ...complexMsg.data, uri: complexMsg.data.dataUri}}) setComplexMsg({...complexMsg, status: info.file.status, data: { ...complexMsg.data, uri: complexMsg.data.dataUri}})
// message.success(`${info.file.name} file uploaded successfully`); // message.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') { } else if (info.file.status === 'error') {
message.error(`图片添加失败`); message.error(`添加失败`);
setComplexMsg({ ...complexMsg, status: info.file.status, data: { ...complexMsg.data, uri: ''} })
} }
}} }}
> >

@ -22,7 +22,7 @@ import { v4 as uuid } from 'uuid';
import { sentMsgTypeMapped } from '@/lib/msgUtils'; import { sentMsgTypeMapped } from '@/lib/msgUtils';
import InputTemplate from './Input/Template'; import InputTemplate from './Input/Template';
import InputEmoji from './Input/Emoji'; import InputEmoji from './Input/Emoji';
import InputImageUpload from './Input/ImageUpload'; import InputMediaUpload from './Input/MediaUpload';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
const InputComposer = () => { const InputComposer = () => {
@ -46,6 +46,7 @@ const InputComposer = () => {
const invokeSendMessage = (msgObj) => { const invokeSendMessage = (msgObj) => {
const msgObjMerge = { const msgObjMerge = {
sender: 'me', sender: 'me',
senderName: 'me',
to: currentConversation.whatsapp_phone_number, to: currentConversation.whatsapp_phone_number,
date: new Date(), date: new Date(),
status: 'waiting', status: 'waiting',
@ -107,11 +108,12 @@ const InputComposer = () => {
{complexMsg.id && ( {complexMsg.id && (
<Flex justify='space-between' className='reply-to bg-gray-100 p-1 rounded-none text-slate-500'> <Flex justify='space-between' className='reply-to bg-gray-100 p-1 rounded-none text-slate-500'>
<div className='pl-2 pr-1 py-1'> <div className='pl-2 pr-1 py-1'>
{complexMsg.type === 'photo' && <Image width={100} src={complexMsg.data.uri} />} {(complexMsg.type === 'photo' && complexMsg.data.uri) && <Image width={100} src={complexMsg.data.uri} />}
{complexMsg.type === 'video' && <FileOutlined className=' text-red-400' />} {complexMsg.type === 'video' && <FileOutlined className=' text-red-400' />}
{complexMsg.type !== 'photo' && <span className='px-1'>{complexMsg.name}</span>} {complexMsg.type !== 'photo' && <span className='px-1'>{complexMsg.name}</span>}
{complexMsg.status === 'loading' && <LoadingOutlined className='px-1' />} {complexMsg.status === 'loading' && <LoadingOutlined className='px-1' />}
{complexMsg.status === 'done' && <CheckCircleOutlined className='px-1 text-primary' />} {complexMsg.status === 'done' && <CheckCircleOutlined className='px-1 text-primary' />}
{complexMsg.status === 'error' && <><CloseCircleOutlined className='px-1 text-red-400' /> <span>添加失败</span> </>}
</div> </div>
<Button type='text' title='删除' className=' rounded-none text-slate-500' icon={<CloseCircleOutlined />} size={'middle'} onClick={() => setComplexMsg({})} /> <Button type='text' title='删除' className=' rounded-none text-slate-500' icon={<CloseCircleOutlined />} size={'middle'} onClick={() => setComplexMsg({})} />
</Flex> </Flex>
@ -137,7 +139,7 @@ const InputComposer = () => {
<Flex gap={4} className='*:text-primary *:rounded-none'> <Flex gap={4} className='*:text-primary *:rounded-none'>
<InputTemplate key='templates' disabled={!talkabled || textabled} invokeSendMessage={invokeSendMessage} /> <InputTemplate key='templates' disabled={!talkabled || textabled} invokeSendMessage={invokeSendMessage} />
<InputEmoji key='emoji' disabled={!textabled} inputEmoji={addEmoji} /> <InputEmoji key='emoji' disabled={!textabled} inputEmoji={addEmoji} />
{/* <InputImageUpload key={'addNewPic'} disabled={!textabled} invokeSendMessage={invokeSendMessage} /> */} <InputMediaUpload key={'addNewMedia'} disabled={!textabled} />
{/* <Button type='text' className='' icon={<YoutubeOutlined />} size={'middle'} /> {/* <Button type='text' className='' icon={<YoutubeOutlined />} size={'middle'} />
<Button type='text' className='' icon={<AudioOutlined />} size={'middle'} /> <Button type='text' className='' icon={<AudioOutlined />} size={'middle'} />
<Button type='text' className='' icon={<FolderAddOutlined />} size={'middle'} /> <Button type='text' className='' icon={<FolderAddOutlined />} size={'middle'} />

Loading…
Cancel
Save