空间通知弹窗,客服自动消息回复 (#42)

Co-authored-by: al <al@cdhncy.com>
Reviewed-on: https://git.wishpal.cn/wishpal_ironfan/tiefen_space_h5/pulls/42
This commit is contained in:
yezian 2025-03-10 17:38:16 +08:00
parent 05bda435df
commit ec2d00930b
10 changed files with 214 additions and 50 deletions

View File

@ -209,7 +209,6 @@ export default function MessageDetail({}) {
// });
return;
}
//查询历史记录的时候后移一位,防止记录重复
setOffset((prev) => prev + 1);
//请求接口发送私信
@ -277,6 +276,7 @@ export default function MessageDetail({}) {
// createdAt: new Date(item.ct * 1000).toISOString(),
createdAt: item.ct,
text: item.message,
m_type: item.m_type,
user: {
_id: account?.mid,
name: account?.name,
@ -289,6 +289,7 @@ export default function MessageDetail({}) {
_id: item.id,
createdAt: item.ct,
text: item.message,
m_type: item.m_type,
user: {
_id: 0,
name: "客服",
@ -403,6 +404,40 @@ export default function MessageDetail({}) {
console.error(error);
}
};
const getAutoMessage = useCallback(
(data) => {
if (data.m_type === 1) {
const test = data.text.split("|");
const btns = test[1].split(",");
return (
<div>
<p>{test[0]}</p>
<div className="my-2">
<p>触发按钮</p>
<ul className="grid grid-cols-2 gap-2 mt-2">
{btns.map((item) => {
return (
<li
onClick={() => {
onSend(item, oldMessages[0]?.id || -1, oldMessages);
}}
className="bg-[#3333331A] rounded text-center px-4 py-1"
>
{item}
</li>
);
})}
</ul>
</div>
</div>
);
} else {
return data?.text;
}
// data.m_type===1?it?.text.split("|")it?.text
},
[sessionId]
);
return (
<div className="bg-[#13121F] h-screen overflow-y-auto" ref={scrollBox}>
<div className="p-4 fixed top-0 z-10 w-full bg-deepBg">
@ -441,43 +476,49 @@ export default function MessageDetail({}) {
<p className="my-2 text-center">
{formatDeadline(item[0].createdAt)}
</p>
<ul className="px-4 overflow-y-auto scrollbarBox_hidden">
<ul className="px-2 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">
<div className="flex justify-start items-start w-full">
<Avatar
className="mr-2 w-[32px] h-[32px]"
style={{ "--border-radius": "50px" }}
className="mr-2 w-[44px] h-[44px]"
style={{
"--border-radius": "50px",
"--size": "44px",
}}
width={32}
height={32}
src={it?.user.avatar}
/>
<div
className="rounded-lg py-2 px-3 bg-blue-500 break-words"
className="rounded-lg py-2 px-3 text-base bg-white text-black break-words"
style={{
borderTopLeftRadius: 0,
maxWidth: "calc(100% - 32px - 0.75rem)",
maxWidth: "calc(100% - 44px - 0.75rem)",
}}
>
{it?.text}
{getAutoMessage(it)}
</div>
</div>
) : (
<div className="flex justify-end w-full">
<div className="flex justify-end items-start w-full">
<div
className="max-w-full rounded-lg py-2 px-3 bg-blue-500 break-words"
className="max-w-full rounded-lg py-2 px-3 text-base bg-blue-500 break-words"
style={{
borderTopRightRadius: 0,
maxWidth: "calc(100% - 32px - 0.75rem)",
maxWidth: "calc(100% - 44px - 0.75rem)",
}}
>
{it?.text}
</div>
<Avatar
className="ml-2 w-[32px] h-[32px]"
style={{ "--border-radius": "50px" }}
className="ml-2 w-[44px] h-[44px]"
style={{
"--border-radius": "50px",
"--size": "44px",
}}
width={32}
height={32}
src={it?.user?.avatar}
@ -496,7 +537,7 @@ export default function MessageDetail({}) {
</div>
{!searchParams.get("mid") && (
<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]">
<div className="rounded bg-[#222036] px-4 py-2 mr-2">
<div className="rounded-[10px] bg-[#222036] px-4 py-2 mr-2">
<Input
placeholder="输入新消息"
className=""
@ -511,7 +552,11 @@ export default function MessageDetail({}) {
onClick={() =>
onSend(newMessage, oldMessages[0]?.id || -1, oldMessages)
}
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
style={{
"--background-color": "#FF669E",
"--border-radius": "10px",
color: "#FFFFFF",
}}
>
发送
</Button>

View File

@ -200,7 +200,7 @@ const MessageList = ({ mid, changeNoticeCount, refInstance, noticeCount }) => {
<Badge
status="error"
content={count > 99 ? "99+" : count}
className="text-lg"
className="text-lg min-w-[14px] flex justify-center items-center"
/>
</div>
)}
@ -262,7 +262,7 @@ const MessageList = ({ mid, changeNoticeCount, refInstance, noticeCount }) => {
content={
data.contact_cs_urc > 99 ? "99+" : data.contact_cs_urc
}
className="text-lg"
className="text-lg min-w-[14px] flex justify-center items-center"
/>
</div>
)}

View File

@ -88,11 +88,6 @@ export default function NoticeItem({ leftIcon, hasLink, data }) {
{hasLink.text}
</span>
<div>
{/* <FontAwesomeIcon
icon={faAngleRight}
style={{ maxWidth: "12px" }}
size="xl"
/> */}
<OwnIcon
src="/icons/32DP/angleRight.png"
className="w-[20px] h-[20px]"

View File

@ -45,6 +45,9 @@ export default function PersonSpace() {
const [currentTime, setCurrentTime] = useState();
const scrollRef = useRef(null);
const [createPostMask, setCreatePostMask] = useState(false);
const [popVisible, setPopVisible] = useState(false);
// 通知弹框数据
const [noticesMaskInformation, setNoticesMaskInformation] = useState(false);
//退款中Modal是否展示
const [isRefundingModalVisible, setIsRefundingModalVisible] = useState(false);
const ironFanProgress = useMemo(
@ -55,6 +58,8 @@ export default function PersonSpace() {
[streamerInfo]
);
useEffect(() => {
// 通知弹窗信息
getNoticesMaskInformation();
setScrollHeight(window.innerHeight - 126);
if (contentBox.current) {
contentBox.current.style.transform = "translateY(-12px)";
@ -88,6 +93,9 @@ export default function PersonSpace() {
firstRequest(currentKey);
}
}, [currentKey, streamerInfo]);
useEffect(() => {
setPopVisible(noticesMaskInformation?.enable);
}, [noticesMaskInformation]);
const getCurrentTime = async () => {
setCurrentTime(Math.floor(new Date().getTime() / 1000));
};
@ -99,6 +107,28 @@ export default function PersonSpace() {
// setHasMore(append.length > 0);
}
}
const getNoticesMaskInformation = async () => {
const userMid = base?.b_mid;
if (userMid != id) return;
try {
const data = await requireAPI("POST", "/api/zone/pop_up", {
body: {
mid: parseInt(id),
},
});
if (data.ret === -1) {
Toast.show({
icon: "fail",
content: data.msg,
position: "top",
});
return;
}
setNoticesMaskInformation(data.data);
} catch (error) {
// console.error(error);
}
};
const getPostList = async (zid, activeKey, offset) => {
try {
setLoading(true);
@ -583,6 +613,79 @@ export default function PersonSpace() {
取消
</p>
</Popup>
<Popup
className="z-[9999!important]"
closeOnSwipe={true}
visible={popVisible}
onMaskClick={() => {
setPopVisible(false);
// setIframePageUrl(null);
}}
onClose={() => {
setPopVisible(false);
// setIframePageUrl(null);
}}
position="bottom"
bodyStyle={{
height: "430px",
backgroundColor: "#17161A",
paddingBottom: 0,
borderTopRightRadius: "15px",
borderTopLeftRadius: "15px",
}}
style={{
"--background-color": "#fff",
}}
>
{/* {iframePage} */}
<div className="w-full -mt-[46px]">
<OwnImage
className="w-full h-[160px]"
outClassName="w-full h-[160px]"
fit="cover"
src={process.env.NEXT_PUBLIC_WEB_ASSETS_URL + "/images/newM.png"}
/>
<div className="p-[14px] w-full flex justify-center items-center flex-col">
<p className="text-[#FFFFFFB2] text-[13px] text-center mb-[28px]">
{noticesMaskInformation.content}
</p>
<div className="w-full">
{noticesMaskInformation.action?.map((item, index) => {
return (
<div
key={index}
style={{ display: item.count > 0 ? "flex" : "none" }}
className="w-full h-[56px] p-[14px] rounded-[12px] bg-[#2F2E32] flex justify-between items-center mt-[10px]"
>
<div className="flex items-center">
<OwnIcon
src={item?.icon_url}
className="w-[28px] h-[28px]"
outClassName="w-[28px] h-[28px] mr-[3.5px]"
/>
<span>
{item.text} {item.count}
</span>
</div>
<div
onClick={() => router.push(item.h5_url)}
className="py-[5px] px-[12px] rounded-full text-[13px] font-bold bg-[#FF669E]"
>
前往处理
</div>
</div>
);
})}
</div>
<div
onClick={() => setPopVisible(false)}
className="w-[221px] h-[46px] mt-[41px] flex justify-center items-center rounded-full text-[15px] bg-[#FF669E]"
>
回到空间
</div>
</div>
</div>
</Popup>
</div>
);
}

View File

@ -178,6 +178,7 @@ const VisitingCard = ({ data }) => {
};
const SpacesList = forwardRef(({ scrollHeight }, ref) => {
const router = useRouter();
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const [offset, setOffset] = useState(0);
@ -218,7 +219,7 @@ const SpacesList = forwardRef(({ scrollHeight }, ref) => {
if (list.length == 0) {
setHasMore(false);
}
setSpacesList([...spacesList, ...list]);
setSpacesList((prev) => [...prev, ...list]);
}
const getSpaceList = async (type = 2) => {
setLoading(true);
@ -270,37 +271,39 @@ const SpacesList = forwardRef(({ scrollHeight }, ref) => {
<VisitingCard data={item} />
</li>
))}
<li onClick={() => router.push("/search")}>
<div
// onPress={() => navigation.navigate("Stream")}
// onClick={}
className="w-full h-52"
>
{spacesList.length > 0 && (
<li onClick={() => router.push("/search")}>
<div
className="h-full flex flex-col rounded-lg overflow-hidden bg-[#FFFFFF1A] bg-no-repeat bg-right-bottom bg-40%"
style={{
backgroundImage: `url(${
process.env.NEXT_PUBLIC_WEB_ASSETS_URL +
"/icons/magnifier.png"
})`,
}}
// onPress={() => navigation.navigate("Stream")}
// onClick={}
className="w-full h-52"
>
{/* <div className="w-full z-0"></div>
<div
className="h-full flex flex-col rounded-lg overflow-hidden bg-[#FFFFFF1A] bg-no-repeat bg-right-bottom bg-40%"
style={{
backgroundImage: `url(${
process.env.NEXT_PUBLIC_WEB_ASSETS_URL +
"/icons/magnifier.png"
})`,
}}
>
{/* <div className="w-full z-0"></div>
<div
className="w-full z-0 h-[42px]"
></div> */}
<div className="flex flex-col w-full h-full px-[22px] py-[30px]">
<p className="text-white font-medium text-lg">发现更多</p>
<p className="text-[#FFFFFF40] font-sm">缘分就在不经意间</p>
<OwnIcon
className="w-full h-full"
outClassName="w-[32px] h-[32px] mt-4"
src="/icons/rightarrow_border.png"
/>
<div className="flex flex-col w-full h-full px-[22px] py-[30px]">
<p className="text-white font-medium text-lg">发现更多</p>
<p className="text-[#FFFFFF40] font-sm">缘分就在不经意间</p>
<OwnIcon
className="w-full h-full"
outClassName="w-[32px] h-[32px] mt-4"
src="/icons/rightarrow_border.png"
/>
</div>
</div>
</div>
</div>
</li>
</li>
)}
{/* {spacesList?.length == 0 && !loading && (
<div
className={`flex flex-col items-center justify-center h-screen`}

View File

@ -74,7 +74,7 @@ function BottomNav({ changeNoticeCount, changeInviter, noticeCount }) {
{!!noticeCount && (
<Badge
content={noticeCount > 99 ? "99+" : noticeCount}
className="absolute top-0 right-0 z-10"
className="absolute top-0 right-0 z-10 min-w-[14px] flex justify-center items-center"
/>
)}
</div>
@ -85,7 +85,7 @@ function BottomNav({ changeNoticeCount, changeInviter, noticeCount }) {
{!!noticeCount && (
<Badge
content={noticeCount > 99 ? "99+" : noticeCount}
className="absolute top-0 right-0 z-10"
className="absolute top-0 right-0 z-10 min-w-[14px] flex justify-center items-center"
/>
)}
</div>

View File

@ -1,11 +1,15 @@
"use client";
import React from "react";
import { DotLoading } from "antd-mobile";
import Empty from "@/components/Empty";
import { useRouter } from "next/navigation";
export default function InfiniteScrollContent({
hasMore=0,
hasMore = 0,
isEmpty,
showNoMore = true,
}) {
const router = useRouter();
return (
<>
{hasMore ? (
@ -21,6 +25,20 @@ export default function InfiniteScrollContent({
// style={{ height: `${scrollHeight}px` }}
>
<Empty type="nodata" />
<div className="text-white">
<p
onClick={() => router.push("/search")}
className="text-base font-medium flex items-center justify-center bg-[#FFFFFF1A] mt-2 rounded-full w-[190px] h-[46px]"
>
搜索空间
</p>
<p
onClick={() => router.push("/found")}
className="text-base font-medium flex items-center justify-center bg-[#FFFFFF1A] mt-2 rounded-full w-[190px] h-[46px]"
>
查看推荐
</p>
</div>
</div>
)}
</>

BIN
public/icons/newM_pay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 B

BIN
public/images/newM.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB