完善客服聊天功能
This commit is contained in:
parent
cf2d08373f
commit
fc2253f59b
|
@ -123,7 +123,11 @@ body{
|
|||
background-color: #07050A;
|
||||
color: #ffffff88;
|
||||
}
|
||||
.adm-jumbo-tabs-header .adm-jumbo-tabs-tab-list{
|
||||
.spaceBoxTwo .adm-jumbo-tabs-header .adm-jumbo-tabs-tab-list{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
.spaceBoxThree .adm-jumbo-tabs-header .adm-jumbo-tabs-tab-list{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
"use client";
|
||||
|
||||
import React, { useState, useCallback, useEffect } from "react";
|
||||
import React, { useState, useRef, useEffect, useCallback } from "react";
|
||||
|
||||
import baseRequest from "@/utils/baseRequest";
|
||||
import { generateSignature } from "@/utils/crypto";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleLeft } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
Input,
|
||||
Button,
|
||||
PullToRefresh,
|
||||
List,
|
||||
InfiniteScroll,
|
||||
Toast
|
||||
} from "antd-mobile";
|
||||
import { Input, Button, Toast, Avatar } from "antd-mobile";
|
||||
import { useRouter } from "next/navigation";
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
|
||||
import { get } from "@/utils/storeInfo";
|
||||
import require from "@/utils/require";
|
||||
import { formatDeadline } from "@/utils/tools";
|
||||
/*
|
||||
params格式:
|
||||
{
|
||||
|
@ -25,32 +20,117 @@ params格式:
|
|||
*/
|
||||
|
||||
export default function MessageDetail({}) {
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
// const [hasMore, setHasMore] = useState(true);
|
||||
const router = useRouter();
|
||||
const getSession = async () => {
|
||||
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
||||
try {
|
||||
const base = baseRequest();
|
||||
const account = await get("account");
|
||||
const signature = generateSignature({
|
||||
mid: account.mid,
|
||||
...base,
|
||||
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("");
|
||||
|
||||
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);
|
||||
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (toScrollBottom.current) {
|
||||
scrollBox.current?.scrollTo(0, scrollBox.current.scrollHeight);
|
||||
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;
|
||||
});
|
||||
});
|
||||
const detailResponse = await fetch(
|
||||
`${apiUrl}/api/contact_customer_service_session/list_by_mid?signature=${signature}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
const intervalId = setInterval(() => {
|
||||
updateMessages();
|
||||
}, 3000); // 间隔时间为3秒
|
||||
|
||||
// 在组件卸载时清除定时器
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
};
|
||||
}, [sessionId]);
|
||||
//查询session
|
||||
const getSession = async (mid) => {
|
||||
try {
|
||||
const data =
|
||||
await require("POST", "/api/contact_customer_service_session/list_by_mid", {
|
||||
body: {
|
||||
mid: Number(mid),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mid: account.mid,
|
||||
...base,
|
||||
}),
|
||||
}
|
||||
);
|
||||
const detailData = await detailResponse.json();
|
||||
if (detailData.ret === -1) {
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
}
|
||||
if (data.data.session) {
|
||||
setSessionId(data.data.session.id);
|
||||
return;
|
||||
}
|
||||
} 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 {
|
||||
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,
|
||||
|
@ -58,29 +138,198 @@ export default function MessageDetail({}) {
|
|||
});
|
||||
return;
|
||||
}
|
||||
if (detailData.data.session) {
|
||||
setSessionId(detailData.data.session.id);
|
||||
return;
|
||||
}
|
||||
setOffset(data.data.offset);
|
||||
setMore(data.data.more);
|
||||
let mathNewMessages = handleData(data.data.list);
|
||||
// setMessages((prev) => [...prev, ...temMessages]);
|
||||
return mathNewMessages;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
async function doRefresh() {
|
||||
await sleep(1000);
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: "刷新失败",
|
||||
});
|
||||
throw new Error("刷新失败");
|
||||
}
|
||||
//发送私信功能
|
||||
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();
|
||||
console.log("oldArr", oldArr);
|
||||
updateMessages(lastId, 0, oldArr);
|
||||
} 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("刷新失败");
|
||||
// }
|
||||
async function loadMore() {
|
||||
const append = await mockRequest();
|
||||
setData((val) => [...val, ...append]);
|
||||
setHasMore(append.length > 0);
|
||||
if (sessionId && userInfo.mid && offset && more) {
|
||||
const append = await loadEarlierHistory();
|
||||
if (append) {
|
||||
// setMessages((val) => [...val, ...append]);
|
||||
setMessages(append);
|
||||
// setHasMore(append.length > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
// console.log("[...messages, ...temMessages]", [
|
||||
// ...handledmessages,
|
||||
// ...temMessages,
|
||||
// ]);
|
||||
setHandledmessages([...handledmessages, ...temMessages]);
|
||||
setOldMessages([...oldMessages, ...list]);
|
||||
let newMessages = [...handledmessages, ...temMessages].reverse();
|
||||
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) => {
|
||||
console.log("lastId", lastId);
|
||||
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;
|
||||
});
|
||||
console.log("[...messages,...newData]", [...newData, ...oldArr]);
|
||||
let mathNewMessages = handleData([...newData, ...oldArr]);
|
||||
setMessages((old) => {
|
||||
toScrollBottom.current = 1;
|
||||
setNewMessage("");
|
||||
return mathNewMessages;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="bg-[#13121F] h-screen">
|
||||
<div className="bg-[#13121F] h-screen overflow-y-auto" ref={scrollBox}>
|
||||
<div className="p-4 fixed top-0 z-10 w-full bg-black">
|
||||
<div className="flex items-center justify-center absolute">
|
||||
<FontAwesomeIcon
|
||||
|
@ -94,24 +343,81 @@ export default function MessageDetail({}) {
|
|||
<p className="text-base text-center">在线服务</p>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<PullToRefresh onRefresh={doRefresh}>
|
||||
<List className="px-4 overflow-y-auto scrollbarBox_hidden">
|
||||
<List.Item className="!p-0"></List.Item>
|
||||
<List.Item className="!p-0"></List.Item>
|
||||
<List.Item className="!p-0"></List.Item>
|
||||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} />
|
||||
</List>
|
||||
</PullToRefresh>
|
||||
<div className="my-[57px]">
|
||||
<div className="flex justify-center py-2">
|
||||
<p
|
||||
className="px-3 py-2 rounded-full bg-[#FFFFFF1A]"
|
||||
onClick={loadMore}
|
||||
>
|
||||
{more ? "查看更早" : "无更早消息"}
|
||||
</p>
|
||||
</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>
|
||||
</div>
|
||||
<div className="w-full h-16 fixed bottom-0 grid grid-cols-[1fr_68px] items-center p-2 border-t-2 border-[#ffffff2a]">
|
||||
<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">
|
||||
<Input placeholder="输入新消息" className="" />
|
||||
<Input
|
||||
placeholder="输入新消息"
|
||||
className=""
|
||||
value={newMessage}
|
||||
onChange={setNewMessage}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
size="middle"
|
||||
block
|
||||
// onClick={handleSubmit}
|
||||
onClick={() => onSend(newMessage, oldMessages[0].id, oldMessages)}
|
||||
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
|
||||
>
|
||||
发送
|
||||
|
|
|
@ -112,11 +112,11 @@ export default function PersonSpace() {
|
|||
/>
|
||||
</div>
|
||||
<Popover
|
||||
style={{ "--background": "#1E1C29"}}
|
||||
content={
|
||||
<div
|
||||
className="text-black"
|
||||
onClick={() => {
|
||||
router.push("messageDetail");
|
||||
router.push("/messageDetail");
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
|
|
|
@ -85,9 +85,8 @@ export default function ShareSpace({ data }) {
|
|||
<Divider />
|
||||
<div
|
||||
onClick={() => {
|
||||
router.push("WebWithoutHeader", {
|
||||
uri: webUrl + "/zone/share/" + data?.streamer_ext?.user_id,
|
||||
})
|
||||
console.log(webUrl + "/zone/share/" + streamerInfo?.streamer_ext?.user_id)
|
||||
router.push(webUrl + "/zone/share/" + streamerInfo?.streamer_ext?.user_id)
|
||||
}}
|
||||
className="flex justify-between pt-4 pb-2"
|
||||
>
|
||||
|
|
|
@ -160,7 +160,7 @@ export default function PersonSpace() {
|
|||
}
|
||||
};
|
||||
return (
|
||||
<div className="">
|
||||
<div className={`${!!streamerInfo?.is_superfanship_enabled ? "spaceBoxThree":"spaceBoxTwo"}`}>
|
||||
<div className="flex justify-between items-center p-4 fixed top-0 z-10 w-full">
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full">
|
||||
<FontAwesomeIcon
|
||||
|
@ -176,7 +176,7 @@ export default function PersonSpace() {
|
|||
height={42}
|
||||
src="/icons/setting.png"
|
||||
placeholder=""
|
||||
onClick={() => router.push("setting")}
|
||||
onClick={() => router.push("setting?data="+encodeURIComponent(JSON.stringify(streamerInfo?.streamer_ext)))}
|
||||
/>
|
||||
</div>
|
||||
{/* 内容 */}
|
||||
|
@ -277,7 +277,7 @@ export default function PersonSpace() {
|
|||
10
|
||||
)}/${parseInt(streamerInfo?.ironfanship_price / 100, 10)}`}</p>
|
||||
</li>
|
||||
{streamerInfo?.is_superfanship_enabled && (
|
||||
{!!streamerInfo?.is_superfanship_enabled && (
|
||||
<li
|
||||
className="flex flex-col items-center mr-6"
|
||||
onClick={() => {
|
||||
|
@ -304,7 +304,9 @@ export default function PersonSpace() {
|
|||
)}
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
// onClick={() => setMaskVisible(true)}
|
||||
onClick={() => {
|
||||
router.push("/messageDetail");
|
||||
}}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
|
@ -398,7 +400,7 @@ export default function PersonSpace() {
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
<ul className="grid grid-cols-3 mt-8 px-4 py-2 fixed bottom-0 z-[999] bg-deepBg w-full border-t-2 border-[#FFFFFF1A]">
|
||||
<ul className="flex justify-around mt-8 px-4 py-2 fixed bottom-0 z-[999] bg-deepBg w-full border-t-2 border-[#FFFFFF1A]">
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => setMaskVisible({ visible: true, type: "weChat" })}
|
||||
|
@ -434,7 +436,7 @@ export default function PersonSpace() {
|
|||
</p>
|
||||
{/* <p className="text-[#ffffff54] text-[10px]">0/299</p> */}
|
||||
</li>
|
||||
{streamerInfo?.is_superfanship_enabled && (
|
||||
{!!streamerInfo?.is_superfanship_enabled && (
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => {
|
||||
|
|
|
@ -1,14 +1,56 @@
|
|||
"use client";
|
||||
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Image, Avatar } from "antd-mobile";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Image, Avatar, Divider, Dialog, Toast } from "antd-mobile";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleLeft, faAngleRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
faAngleLeft,
|
||||
faAngleRight,
|
||||
faCalendar,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
export default function Setting() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const [streamerInfo, setStreamerInfo] = useState(null);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
useEffect(() => {
|
||||
let data = JSON.parse(decodeURIComponent(searchParams.get("data")));
|
||||
setStreamerInfo(data);
|
||||
}, []);
|
||||
const handleShowVideo = () => {
|
||||
Dialog.className = "videoMask";
|
||||
Dialog.show({
|
||||
title: "是否确认退出空间?",
|
||||
content: (
|
||||
<div className="flex flex-col gap-2">
|
||||
一旦退出,您的空间成员身份将会被取消,若当前空间为付费空间,下次加入时,需要再次付费。请确保知晓以上内容后谨慎选择退出。
|
||||
</div>
|
||||
),
|
||||
bodyStyle: {
|
||||
// background: "none",
|
||||
maxHeight: "none",
|
||||
width: "80vw",
|
||||
position: "absolute",
|
||||
top: "calc(50% - 50px)",
|
||||
left: "10vw",
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
key: "submit",
|
||||
text: "确定",
|
||||
onClick: () => {
|
||||
i;
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "cancel",
|
||||
text: "取消",
|
||||
onClick: () => {},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className="">
|
||||
<div className="p-4 fixed top-0 z-10 w-full">
|
||||
|
@ -24,29 +66,93 @@ export default function Setting() {
|
|||
<p className="text-base text-center leading-9">空间设置</p>
|
||||
</div>
|
||||
{/* 内容 */}
|
||||
<div className="flex items-center p-4 pt-16">
|
||||
|
||||
<div className="p-4 pt-20">
|
||||
<div className="flex items-center">
|
||||
<Avatar
|
||||
rounded-full
|
||||
mr-4
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
src={streamerInfo?.cover?.images[0]?.urls[0]}
|
||||
className="mr-4"
|
||||
style={{ "--size": "64px", "--border-radius": "50%" }}
|
||||
style={{ "--size": "52px", "--border-radius": "50%" }}
|
||||
/>
|
||||
<div>
|
||||
<p className="text-xl font-bold">测试账号</p>
|
||||
<div className="h-4 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mt-1 w-max">
|
||||
<Image
|
||||
src="/icons/info/ID.png"
|
||||
width={14}
|
||||
height={14}
|
||||
className="w-4 h-full mr-1"
|
||||
placeholder=""
|
||||
/>
|
||||
<span>213422</span>
|
||||
</div>
|
||||
<p className="text-xl font-bold">{streamerInfo?.name}</p>
|
||||
<ul className="flex">
|
||||
<li className="h-4 mr-1 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mt-1 w-max">
|
||||
<Image
|
||||
src="/icons/info/ID.png"
|
||||
width={14}
|
||||
height={14}
|
||||
className="w-4 h-full mr-1"
|
||||
placeholder=""
|
||||
/>
|
||||
<span>{streamerInfo?.user_id}</span>
|
||||
</li>
|
||||
<li className="h-4 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mt-1 w-max">
|
||||
<FontAwesomeIcon
|
||||
icon={faCalendar}
|
||||
size="sm"
|
||||
className="mr-1"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
<span>{streamerInfo?.user_id}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="mt-6">
|
||||
<li>
|
||||
<div
|
||||
onClick={() => router.push("/share/" + streamerInfo.mid)}
|
||||
className="flex justify-between"
|
||||
>
|
||||
<span className="text-base text-white">分享空间</span>
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="mr-1"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Divider />
|
||||
</li>
|
||||
<li
|
||||
onClick={async () => {
|
||||
const result = await Dialog.confirm({
|
||||
title: "是否确认退出空间?",
|
||||
content: "一旦退出,您的空间成员身份将会被取消,若当前空间为付费空间,下次加入时,需要再次付费。请确保知晓以上内容后谨慎选择退出。",
|
||||
bodyStyle: {
|
||||
maxHeight: "none",
|
||||
width: "80vw",
|
||||
position: "fixed",
|
||||
top: "200px",
|
||||
left: "10vw",
|
||||
},
|
||||
});
|
||||
if (result) {
|
||||
Toast.show({ content: "点击了确认", position: "bottom" });
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-base text-white">退出空间</span>
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="mr-1"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Divider />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -67,7 +67,7 @@ export default function Photos({ media }) {
|
|||
<div
|
||||
className="flex w-12 h-12 justify-center items-center bg-[#33333348] rounded-full"
|
||||
key="closeBtn"
|
||||
onClick={handleSeeAllPhotos}
|
||||
// onClick={handleSeeAllPhotos}
|
||||
>
|
||||
<FontAwesomeIcon icon={faSave} size="2xl"/>
|
||||
</div>
|
||||
|
@ -116,8 +116,8 @@ export default function Photos({ media }) {
|
|||
placeholder={
|
||||
<div className="w-full h-full bg-[#1d1d1d] rounded"></div>
|
||||
}
|
||||
width={currentPhotos.length>1 ? "25vw":"100%"}
|
||||
height={currentPhotos.length>1 ? "25vw":"100%"}
|
||||
width={currentPhotos.length>1 ? "24vw":"100%"}
|
||||
height={currentPhotos.length>1 ? "24vw":"100%"}
|
||||
className={`rounded max-w-full`}
|
||||
fit="cover"
|
||||
src={item.url}
|
||||
|
|
|
@ -4,11 +4,11 @@ import React, { useEffect, useState, useMemo } from "react";
|
|||
import Photos from "../Photos";
|
||||
import { useRouter } from "next/navigation";
|
||||
import PaySpacePost from "../PaySpacePost";
|
||||
import { Image } from "antd-mobile";
|
||||
import { Image, Popover, Divider } from "antd-mobile";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { handleFollow, thumbsUp } from "@/api/public";
|
||||
import {get} from "@/utils/storeInfo"
|
||||
import { get } from "@/utils/storeInfo";
|
||||
export default function PostItem({
|
||||
type,
|
||||
follow,
|
||||
|
@ -18,14 +18,16 @@ export default function PostItem({
|
|||
const router = useRouter();
|
||||
const [isOpenText, setIsOpenText] = useState(false);
|
||||
const [isFollow, setIsFollow] = useState(data.is_followed);
|
||||
const [isThumbsUp, setIsThumbsUp] = useState(data?.is_thumbed_up || data?.is_zone_moment_thumbed_up);
|
||||
const [isThumbsUp, setIsThumbsUp] = useState(
|
||||
data?.is_thumbed_up || data?.is_zone_moment_thumbed_up
|
||||
);
|
||||
//判断是否是发帖人
|
||||
const [isCreator, setIsCreator] = useState(false);
|
||||
useEffect(() => {
|
||||
const account = get("account");
|
||||
if (account.mid === data.mid) setIsCreator(true);
|
||||
if (account.mid === data.mid) setIsCreator(true);
|
||||
return () => {
|
||||
router.prefetch("/profile/"+data.mid);
|
||||
router.prefetch("/profile/" + data.mid);
|
||||
};
|
||||
}, []);
|
||||
const getDays = useMemo(() => {
|
||||
|
@ -35,7 +37,7 @@ export default function PostItem({
|
|||
}, []);
|
||||
return (
|
||||
<div>
|
||||
{type == "space" && data?.is_headed === 1 && (
|
||||
{type == "space" && data?.is_headed === 1 && (
|
||||
<Image src="/images/top_post.png" width={76} className="mb-2" />
|
||||
)}
|
||||
<div className="flex">
|
||||
|
@ -43,7 +45,7 @@ export default function PostItem({
|
|||
className="flex-none w-8 h-8 rounded-full mr-2"
|
||||
src={data.streamer_ext?.avatar.images[0].urls[0]}
|
||||
alt=""
|
||||
onClick={() => router.push("/profile/"+data.mid)}
|
||||
onClick={() => router.push("/profile/" + data.mid)}
|
||||
/>
|
||||
|
||||
<div className="flex-1">
|
||||
|
@ -72,23 +74,23 @@ export default function PostItem({
|
|||
)}
|
||||
</div>
|
||||
<div className="mr-8">
|
||||
{data.media_component && <Photos media={data.media_component} />}
|
||||
{type == "space" && !isCreator && data.c_type && (
|
||||
<PaySpacePost
|
||||
type={data.is_ironfan_visible ? "ironFan" : "superFan"}
|
||||
price={data.price / 100}
|
||||
status={data.is_ironfanship_unlocked}
|
||||
ironfanship_price={data.ironfanship_price / 100}
|
||||
is_zone_moment_unlocked={data.is_zone_moment_unlocked}
|
||||
data={data}
|
||||
/>
|
||||
)}
|
||||
{data.media_component && <Photos media={data.media_component} />}
|
||||
{type == "space" && !isCreator && data.c_type && (
|
||||
<PaySpacePost
|
||||
type={data.is_ironfan_visible ? "ironFan" : "superFan"}
|
||||
price={data.price / 100}
|
||||
status={data.is_ironfanship_unlocked}
|
||||
ironfanship_price={data.ironfanship_price / 100}
|
||||
is_zone_moment_unlocked={data.is_zone_moment_unlocked}
|
||||
data={data}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-between items-center mt-2">
|
||||
{type == "post" ? (
|
||||
<div
|
||||
className="flex items-center"
|
||||
onClick={() => router.push("/profile/"+data.mid)}
|
||||
onClick={() => router.push("/profile/" + data.mid)}
|
||||
>
|
||||
{data.is_active_within_a_week ? (
|
||||
<>
|
||||
|
@ -141,7 +143,9 @@ export default function PostItem({
|
|||
<div className="flex items-center">
|
||||
<div
|
||||
className="flex items-center mr-4 h-[32px]"
|
||||
onClick={() => thumbsUp(data.id, isThumbsUp, setIsThumbsUp,type == "space")}
|
||||
onClick={() =>
|
||||
thumbsUp(data.id, isThumbsUp, setIsThumbsUp, type == "space")
|
||||
}
|
||||
>
|
||||
<Image
|
||||
src={
|
||||
|
@ -153,9 +157,33 @@ export default function PostItem({
|
|||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
<span className={`text-xs ${isThumbsUp == 1?"text-[#FF669E]":"text-[#FFFFFF80]"}`}>{isThumbsUp == 1 ? "已赞" : "点赞"}</span>
|
||||
<span
|
||||
className={`text-xs ${
|
||||
isThumbsUp == 1 ? "text-[#FF669E]" : "text-[#FFFFFF80]"
|
||||
}`}
|
||||
>
|
||||
{isThumbsUp == 1 ? "已赞" : "点赞"}
|
||||
</span>
|
||||
</div>
|
||||
<span className="mr-2">···</span>
|
||||
<Popover
|
||||
style={{ "--background": "#1E1C29" }}
|
||||
content={
|
||||
<ul>
|
||||
<li
|
||||
className="py-1 px-4"
|
||||
onClick={() => {
|
||||
router.push("/messageDetail");
|
||||
}}
|
||||
>
|
||||
举报
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
trigger="click"
|
||||
placement="left"
|
||||
>
|
||||
<span className="mr-2">···</span>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="rounded-full h-px bg-gray-200 mt-2"></div> */}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 266 KiB |
Loading…
Reference in New Issue