2024-07-03 19:59:39 +08:00
|
|
|
|
"use client";
|
|
|
|
|
|
2024-07-11 23:57:26 +08:00
|
|
|
|
import React, { useState, useRef, useEffect, useCallback } from "react";
|
2024-07-03 19:59:39 +08:00
|
|
|
|
|
|
|
|
|
import baseRequest from "@/utils/baseRequest";
|
|
|
|
|
import { generateSignature } from "@/utils/crypto";
|
|
|
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
|
|
|
import { faAngleLeft } from "@fortawesome/free-solid-svg-icons";
|
2024-07-12 22:52:48 +08:00
|
|
|
|
import { Input, Button, Toast, Avatar, DotLoading } from "antd-mobile";
|
2024-07-03 19:59:39 +08:00
|
|
|
|
import { useRouter } from "next/navigation";
|
|
|
|
|
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
2024-07-11 23:57:26 +08:00
|
|
|
|
import { get } from "@/utils/storeInfo";
|
|
|
|
|
import require from "@/utils/require";
|
|
|
|
|
import { formatDeadline } from "@/utils/tools";
|
2024-07-03 19:59:39 +08:00
|
|
|
|
/*
|
|
|
|
|
params格式:
|
|
|
|
|
{
|
|
|
|
|
mid: item.mid,
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
export default function MessageDetail({}) {
|
2024-07-11 23:57:26 +08:00
|
|
|
|
// const [hasMore, setHasMore] = useState(true);
|
2024-07-03 19:59:39 +08:00
|
|
|
|
const router = useRouter();
|
2024-07-11 23:57:26 +08:00
|
|
|
|
const [oldMessages, setOldMessages] = useState([]);
|
|
|
|
|
const [messages, setMessages] = useState([]);
|
|
|
|
|
const [handledmessages, setHandledmessages] = useState([]);
|
|
|
|
|
const [sessionId, setSessionId] = useState();
|
|
|
|
|
const [userInfo, setUserInfo] = useState(null);
|
|
|
|
|
const [newMessage, setNewMessage] = useState("");
|
2024-07-12 22:52:48 +08:00
|
|
|
|
const [loading, setLoading] = useState(false);
|
2024-07-11 23:57:26 +08:00
|
|
|
|
|
|
|
|
|
const [offset, setOffset] = useState(0);
|
|
|
|
|
const [more, setMore] = useState(1);
|
|
|
|
|
const scrollBox = useRef();
|
|
|
|
|
const toScrollBottom = useRef(0);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const userData = get("account");
|
|
|
|
|
setUserInfo(userData);
|
|
|
|
|
getSession(userData.mid);
|
|
|
|
|
}, []);
|
2024-07-12 22:52:48 +08:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
const intervalId = setInterval(() => {
|
|
|
|
|
// console.log("oldMessages[0]", oldMessages[0]);
|
|
|
|
|
if (oldMessages[0]) {
|
|
|
|
|
updateMessages(oldMessages[0]?.id, 0, oldMessages);
|
|
|
|
|
toScrollBottom.current = 1;
|
|
|
|
|
}
|
|
|
|
|
}, 3000); // 间隔时间为3秒
|
|
|
|
|
|
|
|
|
|
// 在组件卸载时清除定时器
|
|
|
|
|
return () => {
|
|
|
|
|
clearInterval(intervalId);
|
|
|
|
|
};
|
|
|
|
|
}, [oldMessages]);
|
2024-07-11 23:57:26 +08:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (toScrollBottom.current) {
|
2024-07-12 22:52:48 +08:00
|
|
|
|
scrollBox.current?.scrollTo(0, scrollBox.current.scrollHeight+50);
|
2024-07-11 23:57:26 +08:00
|
|
|
|
toScrollBottom.current = 0;
|
|
|
|
|
}
|
|
|
|
|
}, [toScrollBottom.current]);
|
|
|
|
|
// useEffect(() => {
|
|
|
|
|
// if (offset == 12) {
|
|
|
|
|
// console.log("offset--------", offset);
|
|
|
|
|
|
|
|
|
|
// scrollBox.current?.scrollTo(0, scrollBox.current.scrollHeight);
|
|
|
|
|
|
|
|
|
|
// // console.log("scrollBox.current",scrollBox.current.scrollHeight,scrollBox.current.scrollTop)
|
|
|
|
|
// }
|
|
|
|
|
// }, [offset]);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (sessionId && userInfo.mid) {
|
|
|
|
|
loadEarlierHistory().then((res) => {
|
|
|
|
|
setMessages((old) => {
|
|
|
|
|
toScrollBottom.current = 1;
|
|
|
|
|
return res;
|
|
|
|
|
});
|
2024-07-03 19:59:39 +08:00
|
|
|
|
});
|
2024-07-11 23:57:26 +08:00
|
|
|
|
}
|
|
|
|
|
}, [sessionId]);
|
|
|
|
|
//查询session
|
|
|
|
|
const getSession = async (mid) => {
|
|
|
|
|
try {
|
|
|
|
|
const data =
|
|
|
|
|
await require("POST", "/api/contact_customer_service_session/list_by_mid", {
|
|
|
|
|
body: {
|
|
|
|
|
mid: Number(mid),
|
2024-07-03 19:59:39 +08:00
|
|
|
|
},
|
2024-07-11 23:57:26 +08:00
|
|
|
|
});
|
|
|
|
|
if (data.ret === -1) {
|
2024-07-03 19:59:39 +08:00
|
|
|
|
Toast.show({
|
2024-07-06 11:05:19 +08:00
|
|
|
|
icon: "fail",
|
|
|
|
|
content: data.msg,
|
|
|
|
|
position: "top",
|
2024-07-03 19:59:39 +08:00
|
|
|
|
});
|
2024-07-11 23:57:26 +08:00
|
|
|
|
}
|
|
|
|
|
if (data.data.session) {
|
|
|
|
|
setSessionId(data.data.session.id);
|
2024-07-03 19:59:39 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2024-07-11 23:57:26 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
//创建session
|
|
|
|
|
const createSession = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const data =
|
|
|
|
|
await require("POST", "/api/contact_customer_service_session/create", {
|
|
|
|
|
body: {
|
|
|
|
|
sub_mid: Number(mid),
|
|
|
|
|
obj_mid: 0,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
if (data.ret === -1) {
|
|
|
|
|
Toast.show({
|
|
|
|
|
icon: "fail",
|
|
|
|
|
content: data.msg,
|
|
|
|
|
position: "top",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
setSessionId(data.data.session_id);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
//请求历史记录
|
|
|
|
|
const loadEarlierHistory = async () => {
|
|
|
|
|
if (!more) return;
|
|
|
|
|
try {
|
2024-07-12 22:52:48 +08:00
|
|
|
|
setLoading(true)
|
2024-07-11 23:57:26 +08:00
|
|
|
|
const data =
|
|
|
|
|
await require("POST", "/api/contact_customer_service/list_by_session_id", {
|
|
|
|
|
body: {
|
|
|
|
|
session_id: sessionId,
|
|
|
|
|
offset: offset,
|
|
|
|
|
limit: 12,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
if (data.ret === -1) {
|
|
|
|
|
Toast.show({
|
|
|
|
|
icon: "fail",
|
|
|
|
|
content: data.msg,
|
|
|
|
|
position: "top",
|
|
|
|
|
});
|
2024-07-03 19:59:39 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2024-07-11 23:57:26 +08:00
|
|
|
|
setOffset(data.data.offset);
|
|
|
|
|
setMore(data.data.more);
|
2024-07-12 22:52:48 +08:00
|
|
|
|
let mathNewMessages = handleData([...oldMessages,...data.data.list]);
|
2024-07-11 23:57:26 +08:00
|
|
|
|
// setMessages((prev) => [...prev, ...temMessages]);
|
2024-07-12 22:52:48 +08:00
|
|
|
|
setLoading(false)
|
2024-07-11 23:57:26 +08:00
|
|
|
|
return mathNewMessages;
|
2024-07-03 19:59:39 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-07-11 23:57:26 +08:00
|
|
|
|
//发送私信功能
|
|
|
|
|
const onSend = useCallback(
|
|
|
|
|
async (message, lastId, oldArr) => {
|
|
|
|
|
if (message == "") {
|
|
|
|
|
Toast.show({
|
|
|
|
|
icon: "error",
|
|
|
|
|
content: "不可发送空内容",
|
|
|
|
|
position: "top",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//如果是第一次发送,需要创建session
|
|
|
|
|
if (!sessionId) await createSession();
|
|
|
|
|
|
|
|
|
|
//查询历史记录的时候后移一位,防止记录重复
|
|
|
|
|
setOffset((prev) => prev + 1);
|
|
|
|
|
//请求接口发送私信
|
|
|
|
|
try {
|
|
|
|
|
const data =
|
|
|
|
|
await require("POST", "/api/contact_customer_service/create", {
|
|
|
|
|
body: {
|
|
|
|
|
session_id: sessionId,
|
|
|
|
|
predicate: 0,
|
|
|
|
|
message,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
if (data.ret === -1) {
|
|
|
|
|
Toast.show({
|
|
|
|
|
icon: "error",
|
|
|
|
|
content: data.msg,
|
|
|
|
|
position: "top",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// updateLatestHistory();
|
2024-07-12 22:52:48 +08:00
|
|
|
|
// console.log("oldArr", oldArr);
|
|
|
|
|
updateMessages(lastId, 0, oldArr).then(res=>{
|
|
|
|
|
setNewMessage("");
|
|
|
|
|
toScrollBottom.current = 1;
|
|
|
|
|
});
|
2024-07-11 23:57:26 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
// //每次发送都缓存信息到本地
|
|
|
|
|
// addArr(`${selfData.mid}_to_${params.mid}_messages`, messages);
|
|
|
|
|
},
|
|
|
|
|
[userInfo, sessionId]
|
|
|
|
|
);
|
|
|
|
|
// async function doRefresh() {
|
|
|
|
|
// await sleep(1000);
|
|
|
|
|
// Toast.show({
|
|
|
|
|
// icon: "fail",
|
|
|
|
|
// content: "刷新失败",
|
|
|
|
|
// });
|
|
|
|
|
// throw new Error("刷新失败");
|
|
|
|
|
// }
|
2024-07-03 19:59:39 +08:00
|
|
|
|
async function loadMore() {
|
2024-07-11 23:57:26 +08:00
|
|
|
|
if (sessionId && userInfo.mid && offset && more) {
|
|
|
|
|
const append = await loadEarlierHistory();
|
|
|
|
|
if (append) {
|
|
|
|
|
// setMessages((val) => [...val, ...append]);
|
|
|
|
|
setMessages(append);
|
|
|
|
|
// setHasMore(append.length > 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-03 19:59:39 +08:00
|
|
|
|
}
|
2024-07-11 23:57:26 +08:00
|
|
|
|
|
|
|
|
|
const handleData = (list) => {
|
|
|
|
|
// console.log("list", list);
|
|
|
|
|
const account = get("account");
|
|
|
|
|
const temMessages = list.map((item) => {
|
|
|
|
|
if (item.predicate === 0) {
|
|
|
|
|
return {
|
|
|
|
|
predicate: item.predicate,
|
|
|
|
|
_id: item.id,
|
|
|
|
|
// createdAt: new Date(item.ct * 1000).toISOString(),
|
|
|
|
|
createdAt: item.ct,
|
|
|
|
|
text: item.message,
|
|
|
|
|
user: {
|
|
|
|
|
_id: account?.mid,
|
|
|
|
|
name: account?.name,
|
|
|
|
|
avatar: account?.avatar?.images[0]?.urls[0],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
return {
|
|
|
|
|
predicate: item.predicate,
|
|
|
|
|
_id: item.id,
|
|
|
|
|
createdAt: item.ct,
|
|
|
|
|
text: item.message,
|
|
|
|
|
user: {
|
|
|
|
|
_id: 0,
|
|
|
|
|
name: "客服",
|
|
|
|
|
avatar: "images/icon.png",
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-07-12 22:52:48 +08:00
|
|
|
|
// console.log("handledmessages......", handledmessages);
|
|
|
|
|
// console.log("[...messages, ...temMessages]", temMessages);
|
|
|
|
|
setHandledmessages(temMessages);
|
|
|
|
|
setOldMessages(list);
|
|
|
|
|
let newMessages = temMessages.reverse();
|
2024-07-11 23:57:26 +08:00
|
|
|
|
let mathNewMessages = newMessages.reduce(
|
|
|
|
|
(accumulator, currentValue, index, sourceArray) => {
|
|
|
|
|
// console.log(
|
|
|
|
|
// accumulator.time,
|
|
|
|
|
// "----",
|
|
|
|
|
// currentValue.createdAt,
|
|
|
|
|
// "---",
|
|
|
|
|
// index
|
|
|
|
|
// );
|
|
|
|
|
if (accumulator.time > currentValue.createdAt) {
|
|
|
|
|
let newData = {
|
|
|
|
|
...accumulator,
|
|
|
|
|
time: accumulator.time,
|
|
|
|
|
messages: [...accumulator.messages, currentValue],
|
|
|
|
|
totalArr:
|
|
|
|
|
index == sourceArray.length - 1
|
|
|
|
|
? [
|
|
|
|
|
...accumulator.totalArr,
|
|
|
|
|
[...accumulator.messages, currentValue],
|
|
|
|
|
]
|
|
|
|
|
: [...accumulator.totalArr],
|
|
|
|
|
};
|
|
|
|
|
return newData;
|
|
|
|
|
} else {
|
|
|
|
|
let newData = {
|
|
|
|
|
...accumulator,
|
|
|
|
|
time: currentValue.createdAt + 60 * 3,
|
|
|
|
|
messages: [currentValue],
|
|
|
|
|
totalArr:
|
|
|
|
|
index == sourceArray.length - 1
|
|
|
|
|
? [
|
|
|
|
|
...accumulator.totalArr,
|
|
|
|
|
accumulator.messages,
|
|
|
|
|
[currentValue],
|
|
|
|
|
]
|
|
|
|
|
: [...accumulator.totalArr, accumulator.messages],
|
|
|
|
|
};
|
|
|
|
|
return newData;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{ time: newMessages[0]?.createdAt + 60 * 3, messages: [], totalArr: [] }
|
|
|
|
|
);
|
|
|
|
|
return mathNewMessages.totalArr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const updateMessages = async (lastId, currentOffset, oldArr) => {
|
2024-07-12 22:52:48 +08:00
|
|
|
|
// console.log("lastId", lastId);
|
2024-07-11 23:57:26 +08:00
|
|
|
|
try {
|
|
|
|
|
const data =
|
|
|
|
|
await require("POST", "/api/contact_customer_service/list_by_session_id", {
|
|
|
|
|
body: {
|
|
|
|
|
session_id: sessionId,
|
|
|
|
|
offset: currentOffset,
|
|
|
|
|
limit: 12,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
if (data.ret === -1) {
|
|
|
|
|
Toast.show({
|
|
|
|
|
icon: "fail",
|
|
|
|
|
content: data.msg,
|
|
|
|
|
position: "top",
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let newData = data.data.list.filter((element) => {
|
|
|
|
|
return element.id > lastId;
|
|
|
|
|
});
|
2024-07-12 22:52:48 +08:00
|
|
|
|
// console.log("[...messages,...newData]", [...newData]);
|
|
|
|
|
let mathNewMessages = handleData([...newData,...oldArr]);
|
2024-07-11 23:57:26 +08:00
|
|
|
|
setMessages((old) => {
|
|
|
|
|
toScrollBottom.current = 1;
|
|
|
|
|
return mathNewMessages;
|
|
|
|
|
});
|
2024-07-12 22:52:48 +08:00
|
|
|
|
return
|
2024-07-11 23:57:26 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-07-03 19:59:39 +08:00
|
|
|
|
return (
|
2024-07-11 23:57:26 +08:00
|
|
|
|
<div className="bg-[#13121F] h-screen overflow-y-auto" ref={scrollBox}>
|
2024-07-03 19:59:39 +08:00
|
|
|
|
<div className="p-4 fixed top-0 z-10 w-full bg-black">
|
|
|
|
|
<div className="flex items-center justify-center absolute">
|
|
|
|
|
<FontAwesomeIcon
|
|
|
|
|
icon={faAngleLeft}
|
|
|
|
|
size="xl"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
router.back();
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-base text-center">在线服务</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
2024-07-11 23:57:26 +08:00
|
|
|
|
<div className="my-[57px]">
|
|
|
|
|
<div className="flex justify-center py-2">
|
2024-07-12 22:52:48 +08:00
|
|
|
|
<div
|
2024-07-11 23:57:26 +08:00
|
|
|
|
className="px-3 py-2 rounded-full bg-[#FFFFFF1A]"
|
2024-07-12 22:52:48 +08:00
|
|
|
|
|
2024-07-11 23:57:26 +08:00
|
|
|
|
>
|
2024-07-12 22:52:48 +08:00
|
|
|
|
{loading? <DotLoading /> : more ? <span onClick={loadMore}>查看更早</span>:<span>无更早消息</span>}
|
|
|
|
|
</div>
|
2024-07-11 23:57:26 +08:00
|
|
|
|
</div>
|
|
|
|
|
<ul className="py-2">
|
|
|
|
|
{messages?.map((item, index) => (
|
|
|
|
|
<li key={index}>
|
|
|
|
|
<p className="my-2 text-center">
|
|
|
|
|
{formatDeadline(item[0].createdAt)}
|
|
|
|
|
</p>
|
|
|
|
|
<ul className="px-4 overflow-y-auto scrollbarBox_hidden">
|
|
|
|
|
{item.map((it) => (
|
|
|
|
|
<li key={it?._id} className="py-3 rounded-lg ">
|
|
|
|
|
<div className="flex w-full">
|
|
|
|
|
{it?.predicate == 1 ? (
|
|
|
|
|
<div className="flex justify-start w-full items-center">
|
|
|
|
|
<Avatar
|
|
|
|
|
className="mr-2"
|
|
|
|
|
style={{ "--border-radius": "50px" }}
|
|
|
|
|
width={32}
|
|
|
|
|
height={32}
|
|
|
|
|
src={it?.user.avatar}
|
|
|
|
|
/>
|
|
|
|
|
<div
|
|
|
|
|
className="block rounded-lg py-2 px-3 bg-blue-500"
|
|
|
|
|
style={{ borderTopLeftRadius: 0 }}
|
|
|
|
|
>
|
|
|
|
|
{it?.text}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="flex justify-end w-full items-center">
|
|
|
|
|
<div
|
|
|
|
|
className="block rounded-lg py-2 px-3 bg-blue-500"
|
|
|
|
|
style={{ borderTopRightRadius: 0 }}
|
|
|
|
|
>
|
|
|
|
|
{it?.text}
|
|
|
|
|
</div>
|
|
|
|
|
<Avatar
|
|
|
|
|
className="ml-2"
|
|
|
|
|
style={{ "--border-radius": "50px" }}
|
|
|
|
|
width={32}
|
|
|
|
|
height={32}
|
|
|
|
|
src={it?.user?.avatar}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
{}
|
|
|
|
|
{/* <InfiniteScroll loadMore={loadMore} hasMore={more} /> */}
|
|
|
|
|
</ul>
|
2024-07-03 19:59:39 +08:00
|
|
|
|
</div>
|
2024-07-11 23:57:26 +08:00
|
|
|
|
<div className="w-full h-16 fixed bottom-0 grid grid-cols-[1fr_68px] bg-black items-center p-2 border-t-2 border-[#ffffff2a]">
|
2024-07-03 19:59:39 +08:00
|
|
|
|
<div className="rounded bg-[#222036] px-4 py-2 mr-2">
|
2024-07-11 23:57:26 +08:00
|
|
|
|
<Input
|
|
|
|
|
placeholder="输入新消息"
|
|
|
|
|
className=""
|
|
|
|
|
value={newMessage}
|
|
|
|
|
onChange={setNewMessage}
|
|
|
|
|
/>
|
2024-07-03 19:59:39 +08:00
|
|
|
|
</div>
|
|
|
|
|
<Button
|
|
|
|
|
size="middle"
|
|
|
|
|
block
|
2024-07-11 23:57:26 +08:00
|
|
|
|
onClick={() => onSend(newMessage, oldMessages[0].id, oldMessages)}
|
2024-07-03 19:59:39 +08:00
|
|
|
|
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
|
|
|
|
|
>
|
|
|
|
|
发送
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|