广场和空间接口调用
This commit is contained in:
parent
2a81f3fe93
commit
41fd2f7a7c
_app.jspackage-lock.jsonpackage.json
api
app
components
AddWeChat
DefaultMask
PaySpacePost
Photos
PostItem
SeeTiefen
public/icons
store
utils
1
_app.js
1
_app.js
|
@ -1 +0,0 @@
|
|||
import '@fortawesome/fontawesome-svg-core/styles.css'; // 引入Font Awesome CSS
|
|
@ -0,0 +1,81 @@
|
|||
import { get } from "@/utils/storeInfo";
|
||||
import require from "@/utils/require";
|
||||
import { Toast } from "antd-mobile";
|
||||
//关注和取关功能
|
||||
export const handleFollow = async (isFollowed, followedID, callback) => {
|
||||
const account = get("account");
|
||||
let body = {
|
||||
[!isFollowed ? "account_relations" : "sentences"]: [
|
||||
{ sub_mid: account.mid, obj_mid: followedID, predicate: 0 },
|
||||
{ sub_mid: followedID, obj_mid: account.mid, predicate: 1 },
|
||||
],
|
||||
};
|
||||
try {
|
||||
const data = await require("POST", `/api/account_relation/${
|
||||
!isFollowed ? "create" : "delete"
|
||||
}`, {
|
||||
body,
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
callback(!isFollowed);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
//点赞和取消点赞功能
|
||||
export const thumbsUp = async (id, times = 1,callback) => {
|
||||
console.log("times", times);
|
||||
try {
|
||||
const body = {
|
||||
moment_id: id,
|
||||
times: times==1?-1:1,
|
||||
};
|
||||
const data = await require("POST", `/api/moment/thumbs_up`, {
|
||||
body,
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}else{
|
||||
callback(times==1?-1:1);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
export async function checkRelation(subMid, objMid, predicate) {
|
||||
try {
|
||||
const data = await require("POST", `/api/account_relation/list_by_sentence`, {
|
||||
body:{
|
||||
sub_mid: subMid,
|
||||
obj_mid: objMid,
|
||||
predicate: predicate,
|
||||
},
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: data.msg,
|
||||
topOffset: 60,
|
||||
});
|
||||
return;
|
||||
}
|
||||
return data.data.is_account_relation_existed;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
import require from "@/utils/require";
|
||||
|
||||
export const getStreamerInfo = async (mid) => {
|
||||
try {
|
||||
const data = await require("POST", "/api/zone/list_by_mid", {
|
||||
body: {
|
||||
mid,
|
||||
},
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
return {
|
||||
...data.data.list[0],
|
||||
refund_enable: data.data.refund_enable,
|
||||
refund_status: data.data.refund_status,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
//获取空间数据并将该空间标为已读
|
||||
export const getSpaceData = async (mid) => {
|
||||
try {
|
||||
const data = await require("POST", `/api/zone/list_by_mid`, {
|
||||
body: {
|
||||
mid,
|
||||
},
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: data.msg,
|
||||
topOffset: 60,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
//将空间标为已读
|
||||
const data2 = await require("POST", `/api/zone_session/upsert`, {
|
||||
body: {
|
||||
zid: data.data.list[0].id,
|
||||
},
|
||||
});
|
||||
if (data2.ret === -1) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: data2.msg,
|
||||
topOffset: 60,
|
||||
});
|
||||
return;
|
||||
}
|
||||
return {
|
||||
isRefunding: data.data.refund_status === 1,
|
||||
noRole: data.data.list[0].visitor_role === 4,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
|
@ -151,4 +151,9 @@ body{
|
|||
.adm-dialog .adm-dialog-content{
|
||||
max-height: none;
|
||||
height: 100%;
|
||||
}
|
||||
.adm-toast-icon{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
"use client";
|
||||
import { Inter } from "next/font/google";
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect } from "react";
|
||||
import "./globals.css";
|
||||
import BottomNav from "../components/BottomNav";
|
||||
import { Provider } from 'react-redux';
|
||||
import store from '../store';
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
export const metadata = {
|
||||
title: "铁粉空间",
|
||||
|
||||
|
||||
description: "与Ta永不失联",
|
||||
keywords: [
|
||||
"铁粉空间",
|
||||
|
@ -29,18 +32,14 @@ export const viewport = {
|
|||
};
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html
|
||||
lang="zh-CN"
|
||||
className="bg-deepBg"
|
||||
data-prefers-color-scheme="dark"
|
||||
|
||||
>
|
||||
<html lang="zh-CN" className="bg-deepBg" data-prefers-color-scheme="dark">
|
||||
<body className={inter.className}>
|
||||
{children}
|
||||
|
||||
<main
|
||||
className={`fixed bottom-0 left-0 w-full bg-deepBg border-t-[1px] border-[#333333]`}
|
||||
className={`h-screen fixed bottom-0 left-0 w-full bg-deepBg `}
|
||||
>
|
||||
<BottomNav />
|
||||
<Provider store={store}>{children}</Provider>
|
||||
<div className="fixed bottom-0 left-0 w-full bg-black"><BottomNav /></div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -4,7 +4,7 @@ import React from "react";
|
|||
import { SpinLoading } from "antd-mobile";
|
||||
export default function Loading() {
|
||||
return (
|
||||
<section className="fixed top-0 w-full h-screen flex flex-col justify-center items-center bg-deepBg z-50">
|
||||
<section className="w-full h-screen flex flex-col justify-center items-center bg-deepBg z-50">
|
||||
<SpinLoading />
|
||||
</section>
|
||||
);
|
||||
|
|
|
@ -1,15 +1,24 @@
|
|||
"use client";
|
||||
|
||||
import React, { useState, useRef } 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, Swiper, Tabs, Divider, Checkbox } from "antd-mobile";
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import {
|
||||
Input,
|
||||
Button,
|
||||
Swiper,
|
||||
Tabs,
|
||||
Divider,
|
||||
Checkbox,
|
||||
Toast,
|
||||
} from "antd-mobile";
|
||||
import { useRouter } from "next/navigation";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
import { JSEncrypt } from "jsencrypt";
|
||||
import { handleLogin } from "@/store/actions";
|
||||
import { saveUserInfo,removeUserInfo } from "@/utils/storeInfo";
|
||||
import { connect } from "react-redux";
|
||||
import { cryptoPassword } from "@/utils/crypto";
|
||||
import require from "@/utils/require";
|
||||
import {signOut,signIn} from "@/utils/auth";
|
||||
/*
|
||||
params格式:
|
||||
{
|
||||
|
@ -20,15 +29,171 @@ const tabItems = [
|
|||
{ key: "code", title: "验证码登录" },
|
||||
{ key: "password", title: "帐号密码登录" },
|
||||
];
|
||||
export default function Login({}) {
|
||||
function Login({ handleLogin }) {
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const [regionCode, setRegionCode] = useState("");
|
||||
const [mobilePhone, setMobilePhone] = useState("");
|
||||
const [veriCode, setVeriCode] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [isCounting, setIsCounting] = useState(false);
|
||||
const [seconds, setSeconds] = useState(60);
|
||||
const [loginInfo, setLoginInfo] = useState({
|
||||
mobilePhone: "",
|
||||
regionCode: "86",
|
||||
password: "",
|
||||
checked: false,
|
||||
});
|
||||
const router = useRouter();
|
||||
const swiperRef = useRef(null);
|
||||
useEffect(() => {
|
||||
handleLogin({ isSignin: false, userToken: null });
|
||||
signOut()
|
||||
removeUserInfo();
|
||||
},[])
|
||||
useEffect(() => {
|
||||
let interval;
|
||||
if (isCounting && seconds > 0) {
|
||||
interval = setInterval(() => {
|
||||
setSeconds(seconds - 1);
|
||||
}, 1000);
|
||||
} else {
|
||||
setIsCounting(false);
|
||||
setSeconds(60);
|
||||
clearInterval(interval);
|
||||
}
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [isCounting, seconds]);
|
||||
const handleSubmit = async (type) => {
|
||||
const { mobilePhone, password, regionCode, checked } = loginInfo;
|
||||
//验证数据格式
|
||||
if (!checked) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: "请先阅读并同意《用户协议》和《隐私政策》后登录",
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!mobilePhone.match(/^1[3456789]\d{9}$/)) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: "手机号码格式错误",
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (type === "password") {
|
||||
if (password.length < 8) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: "密码不得小于8位",
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (password.length > 15) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: "密码不得大于15位",
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (veriCode.length !== 6) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: "请输入正确的验证码",
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
//对手机号进行RSA加密
|
||||
const encrypt = new JSEncrypt();
|
||||
encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY);
|
||||
const mobile_phone = encrypt.encrypt(mobilePhone);
|
||||
//MD5加密password
|
||||
const encryptedPassword = cryptoPassword(password);
|
||||
//发送登录请求
|
||||
let body = {
|
||||
mobile_phone,
|
||||
region_code: regionCode,
|
||||
};
|
||||
body =
|
||||
type === "password"
|
||||
? {
|
||||
...body,
|
||||
password: encryptedPassword,
|
||||
}
|
||||
: {
|
||||
...body,
|
||||
code: veriCode,
|
||||
};
|
||||
try {
|
||||
const data = await require("POST", `/api/login/${
|
||||
type === "password" ? "login_by_pswd" : "login_by_veri_code"
|
||||
}`, {
|
||||
body,
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
//登录
|
||||
saveUserInfo(data, mobilePhone, regionCode);
|
||||
signIn(data);
|
||||
handleLogin({ isSignin: true, userToken: data.data.token });
|
||||
router.push("/");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
//点击获取验证码
|
||||
const handleVerification = async () => {
|
||||
const { mobilePhone, regionCode, checked } = loginInfo;
|
||||
if (!checked) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: "请先阅读并同意《用户协议》和《隐私政策》后登录",
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
//手机号校验
|
||||
if (!mobilePhone.match(/^1[3456789]\d{9}$/)) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "手机号码格式错误",
|
||||
topOffset: 60,
|
||||
});
|
||||
return;
|
||||
}
|
||||
//开始倒计时
|
||||
setIsCounting(true);
|
||||
//对手机号进行RSA加密
|
||||
const encrypt = new JSEncrypt();
|
||||
encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY);
|
||||
const mobile_phone = encrypt.encrypt(mobilePhone);
|
||||
//发送短信验证码
|
||||
try {
|
||||
await fetch(`/api/veri_code/send`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mobile_phone,
|
||||
region_code: regionCode,
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className={`${styles.loginBox}`}>
|
||||
<div className="mt-32 flex justify-between items-center px-2 text-gray-400 sticky top-0 z-10 bg-deepBg">
|
||||
|
@ -65,14 +230,33 @@ export default function Login({}) {
|
|||
<Swiper.Item className="px-10">
|
||||
<div className="border-2 border-[#2c2b2f] rounded-2xl p-4">
|
||||
<div className="flex flex-row flex-nowrap items-center mb-4">
|
||||
<p className="text-base text-white mr-4">+{regionCode}</p>
|
||||
<p className="text-base text-white mr-4">
|
||||
+{loginInfo.regionCode}
|
||||
</p>
|
||||
<Input
|
||||
clearable
|
||||
placeholder="请输入手机号"
|
||||
// disabled={true}
|
||||
type="number"
|
||||
maxLength={11}
|
||||
onChangeText={(value) => setMobilePhone(value)}
|
||||
value={mobilePhone}
|
||||
onChange={(value) =>
|
||||
setLoginInfo({ ...loginInfo, mobilePhone: value })
|
||||
}
|
||||
value={loginInfo.mobilePhone}
|
||||
style={{ "--color": "#FFFFFF", "--font-size": "16px" }}
|
||||
/>
|
||||
</div>
|
||||
<Divider />
|
||||
<div className="flex flex-row flex-nowrap items-center">
|
||||
<p className="text-base text-white mr-4 whitespace-nowrap">
|
||||
密码
|
||||
</p>
|
||||
<Input
|
||||
clearable
|
||||
placeholder="请输入密码"
|
||||
onChange={(value) => setLoginInfo({ ...loginInfo, password: value})}
|
||||
value={loginInfo.password}
|
||||
type="password"
|
||||
style={{ "--color": "#FFFFFF", "--font-size": "16px" }}
|
||||
/>
|
||||
</div>
|
||||
|
@ -83,7 +267,7 @@ export default function Login({}) {
|
|||
</p>
|
||||
<Input
|
||||
placeholder="请输入验证码"
|
||||
onChangeText={(value) => setVeriCode(value)}
|
||||
onChange={(value) => setVeriCode(value)}
|
||||
value={veriCode}
|
||||
type="number"
|
||||
style={{
|
||||
|
@ -95,7 +279,7 @@ export default function Login({}) {
|
|||
shape="rounded"
|
||||
size="mini"
|
||||
disabled={isCounting}
|
||||
// onClick={handleSubmit}
|
||||
onClick={handleVerification}
|
||||
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
|
||||
className="whitespace-nowrap"
|
||||
>
|
||||
|
@ -104,19 +288,29 @@ export default function Login({}) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<LoginBtn />
|
||||
<LoginBtn
|
||||
loginInfo={loginInfo}
|
||||
setLoginInfo={setLoginInfo}
|
||||
handleSubmit={handleSubmit}
|
||||
type={activeIndex ? "password" : "mobile"}
|
||||
/>
|
||||
</Swiper.Item>
|
||||
<Swiper.Item className="px-10">
|
||||
<div className="border-2 border-[#2c2b2f] rounded-2xl p-4">
|
||||
<div className="flex flex-row flex-nowrap items-center mb-4">
|
||||
<p className="text-base text-white mr-4">+{regionCode}</p>
|
||||
<p className="text-base text-white mr-4">
|
||||
+{loginInfo.regionCode}
|
||||
</p>
|
||||
<Input
|
||||
clearable
|
||||
placeholder="请输入手机号"
|
||||
// disabled={true}
|
||||
type="number"
|
||||
maxLength={11}
|
||||
onChangeText={(value) => setMobilePhone(value)}
|
||||
value={mobilePhone}
|
||||
onChange={(value) =>
|
||||
setLoginInfo({ ...loginInfo, mobilePhone: value })
|
||||
}
|
||||
value={loginInfo.mobilePhone}
|
||||
style={{ "--color": "#FFFFFF", "--font-size": "16px" }}
|
||||
/>
|
||||
</div>
|
||||
|
@ -126,10 +320,13 @@ export default function Login({}) {
|
|||
密码
|
||||
</p>
|
||||
<Input
|
||||
clearable
|
||||
placeholder="请输入密码"
|
||||
onChangeText={(value) => setVeriCode(value)}
|
||||
value={password}
|
||||
type="number"
|
||||
onChange={(value) =>
|
||||
setLoginInfo({ ...loginInfo, password: value })
|
||||
}
|
||||
value={loginInfo.password}
|
||||
type="password"
|
||||
style={{
|
||||
"--placeholder-color": "#FFFFFF80",
|
||||
"--font-size": "16px",
|
||||
|
@ -137,20 +334,29 @@ export default function Login({}) {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<LoginBtn />
|
||||
<LoginBtn
|
||||
loginInfo={loginInfo}
|
||||
setLoginInfo={setLoginInfo}
|
||||
handleSubmit={handleSubmit}
|
||||
type={activeIndex ? "password" : "mobile"}
|
||||
/>
|
||||
</Swiper.Item>
|
||||
</Swiper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const LoginBtn = () => {
|
||||
|
||||
const LoginBtn = ({ loginInfo, setLoginInfo, type, handleSubmit }) => {
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
console.log("loginInfo", loginInfo);
|
||||
}, []);
|
||||
return (
|
||||
<div className="mt-16">
|
||||
<div className="flex items-center">
|
||||
<Checkbox
|
||||
value={loginInfo?.checked}
|
||||
onChange={(value) => setLoginInfo({ ...loginInfo, checked: value })}
|
||||
style={{
|
||||
"--icon-size": "14px",
|
||||
"--font-size": "14px",
|
||||
|
@ -186,7 +392,7 @@ const LoginBtn = () => {
|
|||
shape="rounded"
|
||||
size="middle"
|
||||
block
|
||||
// onClick={handleSubmit}
|
||||
onClick={() => handleSubmit(type)}
|
||||
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
|
||||
className="mt-2"
|
||||
>
|
||||
|
@ -195,3 +401,8 @@ const LoginBtn = () => {
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
handleLogin,
|
||||
};
|
||||
export default connect(null, mapDispatchToProps)(Login);
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
PullToRefresh,
|
||||
List,
|
||||
InfiniteScroll,
|
||||
Toast
|
||||
} from "antd-mobile";
|
||||
import { useRouter } from "next/navigation";
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
|
@ -29,9 +30,9 @@ export default function MessageDetail({}) {
|
|||
const getSession = async () => {
|
||||
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
||||
try {
|
||||
const base = baseRequest();
|
||||
const base = baseRequest();
|
||||
const account = await get("account");
|
||||
const signature = generateSignature({
|
||||
const signature = generateSignature({
|
||||
mid: account.mid,
|
||||
...base,
|
||||
});
|
||||
|
@ -51,9 +52,9 @@ export default function MessageDetail({}) {
|
|||
const detailData = await detailResponse.json();
|
||||
if (detailData.ret === -1) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: detailData.msg,
|
||||
topOffset: 60,
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -96,9 +97,7 @@ export default function MessageDetail({}) {
|
|||
<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>
|
||||
<List.Item className="!p-0"></List.Item>
|
||||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} />
|
||||
|
|
|
@ -1,16 +1,24 @@
|
|||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import React,{useEffect,useState} from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Avatar, Image } from "antd-mobile";
|
||||
import { useRouter,useSearchParams } from "next/navigation";
|
||||
import withAuth from "@/components/WithAuth";
|
||||
import {get} from "@/utils/storeInfo";
|
||||
const My = () => {
|
||||
const [userInfo, setUserInfo] = useState({});
|
||||
const searchParams = useSearchParams();
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
const userInfo = get("account");
|
||||
if (userInfo) {
|
||||
setUserInfo(userInfo);
|
||||
}
|
||||
},[])
|
||||
return (
|
||||
<div className="p-4 pb-20 bg-no-repeat bg-contain bg-top bg-[url(/images/profilebackground.png)]">
|
||||
<div className="h-screen p-4 pb-20 bg-no-repeat bg-contain bg-top bg-[url(/images/profilebackground.png)]">
|
||||
<div className="flex justify-end items-center z-10 w-full mb-4">
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full mr-2" onClick={()=>router.push("my/editUserProfile/selectUserProfileItem")}>
|
||||
<Image
|
||||
|
@ -29,25 +37,26 @@ const My = () => {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mb-4" onClick={()=>router.push("profile")}>
|
||||
<div className="flex items-center justify-between mb-4" onClick={()=>router.push("profile/"+userInfo.mid)}>
|
||||
<div className="flex items-center">
|
||||
<Avatar
|
||||
rounded-full
|
||||
mr-4
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
src={userInfo.avatar?.images[0].urls[0]}
|
||||
className="mr-4"
|
||||
style={{ "--size": "76px", "--border-radius": "50%" }}
|
||||
/>
|
||||
<div>
|
||||
<p className="text-2xl font-bold">测试账号</p>
|
||||
<p className="text-2xl font-bold">{userInfo.name}</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>
|
||||
<span>{userInfo.user_id}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -71,11 +80,11 @@ const My = () => {
|
|||
<p className="text-[#ffffff88]">粉丝</p>
|
||||
</li>
|
||||
<li className="text-center" onClick={()=>router.push("my/wallet")}>
|
||||
<p className="text-2xl">540</p>
|
||||
<p className="text-2xl">{userInfo.gold_num}</p>
|
||||
<p className="text-[#ffffff88]">金币</p>
|
||||
</li>
|
||||
<li className="text-center" onClick={()=>router.push("my/wallet")}>
|
||||
<p className="text-2xl">0</p>
|
||||
<p className="text-2xl">{userInfo.diamond_num}</p>
|
||||
<p className="text-[#ffffff88]">钻石</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
@ -71,6 +71,7 @@ export default function SwitchAccount() {
|
|||
<Image
|
||||
src="/icons/info/ID.png"
|
||||
width={14}
|
||||
height={14}
|
||||
className="w-4 h-full mr-1"
|
||||
/>
|
||||
<span>213422</span>
|
||||
|
|
263
app/page.js
263
app/page.js
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import React, { useEffect, useRef, useState, Suspense } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Tabs,
|
||||
Swiper,
|
||||
|
@ -10,15 +10,15 @@ import {
|
|||
List,
|
||||
Image,
|
||||
} from "antd-mobile";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faRefresh } from "@fortawesome/free-solid-svg-icons";
|
||||
import PostItem from "../components/PostItem";
|
||||
import { sleep } from "antd-mobile/es/utils/sleep";
|
||||
import "./index.css";
|
||||
import PostItemSkeleton from "@/components/skeletons/PostItemSkeleton";
|
||||
import Link from "next/link";
|
||||
import requre from "@/utils/require";
|
||||
import baseRequest from "@/utils/baseRequest";
|
||||
import { generateSignature } from "@/utils/crypto";
|
||||
import require from "@/utils/require";
|
||||
import Empty from "@/components/Empty";
|
||||
const variables = {
|
||||
"@active-line-color": "#f00", // 将主题色改为红色
|
||||
};
|
||||
|
@ -34,46 +34,14 @@ export default function Home() {
|
|||
const swiperRef = useRef(null);
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const [data, setData] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
|
||||
const [scrollHeight, setScrollHeight] = useState(0);
|
||||
const [commenPostList,setCommenPostList] = useState([])
|
||||
// 获取屏幕高度
|
||||
// const scrollHeight = 600;
|
||||
useEffect(() => {
|
||||
setScrollHeight(window.innerHeight - 126);
|
||||
getPostList(2);
|
||||
setScrollHeight(window.innerHeight - 112);
|
||||
// getData(0)
|
||||
}, []);
|
||||
async function doRefresh() {
|
||||
// await sleep(1000);
|
||||
// Toast.show({
|
||||
// icon: "fail",
|
||||
// content: "刷新失败",
|
||||
// });
|
||||
// throw new Error("刷新失败");
|
||||
getPostList(1);
|
||||
}
|
||||
async function loadMore() {
|
||||
// const append = await getPostList(0);
|
||||
// setData((val) => [...val, ...append]);
|
||||
// setHasMore(append.length > 0);
|
||||
}
|
||||
const getPostList = async (type = 0) => {
|
||||
const data = await requre("POST", "/api/moment/recomm_list", {
|
||||
body: { op_type: type },
|
||||
});
|
||||
setLoading(false)
|
||||
if (data.ret == -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: "加载失败",
|
||||
});
|
||||
}else{
|
||||
setCommenPostList(data.data.recomm_list)
|
||||
}
|
||||
console.log("res", data);
|
||||
};
|
||||
return (
|
||||
<div className="h-screen">
|
||||
<div className="flex justify-between items-center px-2 custom-tabs text-gray-400 sticky top-0 z-10 bg-deepBg">
|
||||
|
@ -87,6 +55,7 @@ export default function Home() {
|
|||
>
|
||||
{tabItems.map((item) => (
|
||||
<Tabs.Tab
|
||||
destroyOnClose={true}
|
||||
forceRender={false}
|
||||
title={item.title}
|
||||
key={item.key}
|
||||
|
@ -102,9 +71,9 @@ export default function Home() {
|
|||
</Link>
|
||||
</div>
|
||||
<Swiper
|
||||
className="overflow-visible"
|
||||
className="overflow-visible h-full"
|
||||
direction="horizontal"
|
||||
loop
|
||||
loop={false}
|
||||
indicator={() => null}
|
||||
ref={swiperRef}
|
||||
defaultIndex={activeIndex}
|
||||
|
@ -113,33 +82,199 @@ export default function Home() {
|
|||
}}
|
||||
>
|
||||
<Swiper.Item>
|
||||
<PullToRefresh onRefresh={doRefresh}>
|
||||
<List className="px-4 overflow-y-auto scrollbarBox_hidden">
|
||||
{loading && <div><PostItemSkeleton /><PostItemSkeleton /><PostItemSkeleton /></div>}
|
||||
{commenPostList.map(item=><List.Item key={item.id} className="!p-0">
|
||||
<PostItem
|
||||
type="post"
|
||||
data={item}
|
||||
/>
|
||||
</List.Item>)}
|
||||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} />
|
||||
</List>
|
||||
</PullToRefresh>
|
||||
<RecommPostList scrollHeight={scrollHeight} />
|
||||
</Swiper.Item>
|
||||
<Swiper.Item>
|
||||
<PullToRefresh onRefresh={doRefresh}>
|
||||
<List
|
||||
className="p-2 overflow-y-auto scrollbarBox_hidden"
|
||||
style={{ maxHeight: `${scrollHeight}px` }}
|
||||
>
|
||||
<List.Item className="!p-0">
|
||||
<PostItem follow={true} type="post" />
|
||||
</List.Item>
|
||||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} />
|
||||
</List>
|
||||
</PullToRefresh>
|
||||
<FollowPostList scrollHeight={scrollHeight} />
|
||||
</Swiper.Item>
|
||||
</Swiper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const RecommPostList = ({ scrollHeight }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const [commenPostList, setCommenPostList] = useState([]);
|
||||
const [currentTime, setCurrentTime] = useState();
|
||||
useEffect(() => {
|
||||
getRecommPostList(2).then((res) => {
|
||||
setCommenPostList(res);
|
||||
});
|
||||
}, []);
|
||||
async function doRefresh() {
|
||||
// await sleep(1000);
|
||||
// Toast.show({
|
||||
// icon: "fail",
|
||||
// content: "刷新失败",
|
||||
// });
|
||||
// throw new Error("刷新失败");
|
||||
const list = await getRecommPostList(1);
|
||||
setCommenPostList(list);
|
||||
}
|
||||
async function loadMore() {
|
||||
const list = await getRecommPostList(0);
|
||||
if (list.length == 0) {
|
||||
setHasMore(false);
|
||||
}
|
||||
setCommenPostList([...commenPostList, ...list]);
|
||||
}
|
||||
const getRecommPostList = async (type = 2) => {
|
||||
setLoading(true);
|
||||
const data = await require("POST", "/api/moment/recomm_list", {
|
||||
body: { op_type: type },
|
||||
});
|
||||
setLoading(false);
|
||||
if (data.ret == -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
} else {
|
||||
return data.data.recomm_list;
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div
|
||||
style={{ maxHeight: `${scrollHeight}px` }}
|
||||
className="px-4 overflow-y-auto"
|
||||
>
|
||||
<List>
|
||||
{loading && (
|
||||
<div>
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
</div>
|
||||
)}
|
||||
{commenPostList.map((item) => (
|
||||
<List.Item key={item.id} className="!p-0">
|
||||
<PostItem type="post" data={item} />
|
||||
</List.Item>
|
||||
))}
|
||||
{commenPostList.length == 0 && (
|
||||
<div
|
||||
className={`flex flex-col items-center justify-center`}
|
||||
style={{ height: `${scrollHeight}px` }}
|
||||
>
|
||||
<Empty type="nodata" />
|
||||
</div>
|
||||
)}
|
||||
</List>
|
||||
{!!commenPostList.length && (
|
||||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} />
|
||||
)}
|
||||
<div
|
||||
className={`fixed bottom-[126px] right-4 z-[999] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white ${
|
||||
loading ? "animate-spin" : ""
|
||||
}`}
|
||||
>
|
||||
<FontAwesomeIcon icon={faRefresh} size="xl" onClick={doRefresh} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const FollowPostList = ({ scrollHeight }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [hasMore, setHasMore] = useState(false);
|
||||
const [followPostList, setFollowPostList] = useState([]);
|
||||
const [currentTime, setCurrentTime] = useState();
|
||||
const [offset, setOffset] = useState(0);
|
||||
useEffect(() => {
|
||||
getFollowPostList().then((res) => {
|
||||
setFollowPostList(res);
|
||||
});
|
||||
}, []);
|
||||
async function doRefresh() {
|
||||
// await sleep(1000);
|
||||
// Toast.show({
|
||||
// icon: "fail",
|
||||
// content: "刷新失败",
|
||||
// });
|
||||
// throw new Error("刷新失败");
|
||||
// getRecommPostList(1);
|
||||
}
|
||||
async function loadMore() {
|
||||
const list = await getFollowPostList();
|
||||
const newList = [...followPostList, ...list];
|
||||
setOffset(newList.length / 4);
|
||||
setFollowPostList(newList);
|
||||
}
|
||||
const getFollowPostList = async () => {
|
||||
setLoading(true);
|
||||
setCurrentTime(Math.floor(new Date().getTime() / 1000));
|
||||
const data = await require("POST", "/api/account_relation/list_follow", {
|
||||
body: { offset, limit: 4 },
|
||||
}, true);
|
||||
setHasMore(data.data.list.length > 0);
|
||||
if (data.data.list.length > 0) {
|
||||
//查关注主播展示资料
|
||||
const followsResponse =
|
||||
await require("POST", "/api/moment/list_by_mids", {
|
||||
body: {
|
||||
offset,
|
||||
limit: 4,
|
||||
ct_upper_bound: currentTime,
|
||||
mids: data.data.list.map((item) => item.obj_mid),
|
||||
},
|
||||
});
|
||||
setLoading(false);
|
||||
if (data.ret == -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
} else {
|
||||
return followsResponse.data.list;
|
||||
}
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div
|
||||
style={{ maxHeight: `${scrollHeight}px` }}
|
||||
className="px-4 overflow-y-auto"
|
||||
>
|
||||
{/* <PullToRefresh onRefresh={doRefresh}> */}
|
||||
<List>
|
||||
{loading && (
|
||||
<div className="my-[31px]">
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
</div>
|
||||
)}
|
||||
{followPostList.map((item, index) => (
|
||||
<List.Item key={item.id + "_" + index} className="!p-0">
|
||||
<PostItem type="post" data={item} />
|
||||
</List.Item>
|
||||
))}
|
||||
{followPostList.length == 0 && (
|
||||
<div
|
||||
className={`flex flex-col items-center justify-center`}
|
||||
style={{ height: `${scrollHeight}px` }}
|
||||
>
|
||||
<Empty type="nodata" />
|
||||
</div>
|
||||
)}
|
||||
</List>
|
||||
{!!followPostList.length && (
|
||||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} />
|
||||
)}
|
||||
{/* <div
|
||||
className={`fixed bottom-[126px] right-4 z-[999] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white ${
|
||||
loading ? "animate-spin" : ""
|
||||
}`}
|
||||
>
|
||||
<FontAwesomeIcon icon={faRefresh} size="xl" onClick={doRefresh} />
|
||||
</div> */}
|
||||
{/* </PullToRefresh> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,360 @@
|
|||
"use client";
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Image,
|
||||
Swiper,
|
||||
Divider,
|
||||
ImageViewer,
|
||||
Popover,
|
||||
Toast,
|
||||
} from "antd-mobile";
|
||||
import { useRouter, useParams } from "next/navigation";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faAngleLeft,
|
||||
faAngleRight,
|
||||
faEllipsisVertical,
|
||||
faCopy,
|
||||
faWarning,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import require from "@/utils/require";
|
||||
import AddWeChat from "@/components/AddWeChat";
|
||||
import { handleFollow, checkRelation } from "@/api/public";
|
||||
import { get } from "@/utils/storeInfo";
|
||||
// import * as Clipboard from "expo-clipboard";
|
||||
export default function PersonSpace() {
|
||||
const { mid } = useParams();
|
||||
const router = useRouter();
|
||||
const [streamerInfo, setStreamerInfo] = useState(null);
|
||||
const [spaceData, setSpaceData] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [isFollow, setIsFollow] = useState(false);
|
||||
// 获取屏幕高度
|
||||
// const scrollHeight = 600;
|
||||
const photos = [
|
||||
{ url: "https://picsum.photos/seed/picsum/200/300", type: "video" },
|
||||
{ url: "https://picsum.photos/seed/picsum/200/300", type: "img" },
|
||||
];
|
||||
useEffect(() => {
|
||||
getStreamerInfo();
|
||||
getSpaceData();
|
||||
getRelationData();
|
||||
}, []);
|
||||
const showPhotos = (photos, index) => {
|
||||
ImageViewer.Multi.show({
|
||||
images: photos.map((item) => item.url),
|
||||
defaultIndex: index,
|
||||
});
|
||||
};
|
||||
const getStreamerInfo = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await require("POST", "/api/streamer/list_ext_by_mid", {
|
||||
body: {
|
||||
mid: Number(mid),
|
||||
},
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
setStreamerInfo({
|
||||
...data.data,
|
||||
});
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
const getSpaceData = async () => {
|
||||
try {
|
||||
const data = await require("POST", "/api/zone/list_by_mid", {
|
||||
body: {
|
||||
mid: Number(mid),
|
||||
},
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
setSpaceData(data.data.list[0]);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
const getRelationData = async () => {
|
||||
const account = get("account");
|
||||
const subMid = account.mid;
|
||||
const objMid = Number(mid);
|
||||
const temIsFollowed = await checkRelation(subMid, objMid, 0);
|
||||
setIsFollow(temIsFollowed);
|
||||
};
|
||||
return (
|
||||
<div className="">
|
||||
<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
|
||||
icon={faAngleLeft}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Popover
|
||||
content={
|
||||
<div
|
||||
className="text-black"
|
||||
onClick={() => {
|
||||
router.push("messageDetail");
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faWarning}
|
||||
// size="xl"
|
||||
|
||||
color="#3B69B8"
|
||||
className="mr-2"
|
||||
/>
|
||||
<span>举报</span>
|
||||
</div>
|
||||
}
|
||||
trigger="click"
|
||||
placement="left"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faEllipsisVertical}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
// router.back();
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
{/* 内容 */}
|
||||
<div>
|
||||
<div>
|
||||
<Swiper
|
||||
autoplay
|
||||
loop
|
||||
indicatorProps={{
|
||||
style: {
|
||||
"--dot-color": "#FF669E30",
|
||||
"--active-dot-color": "#FF669E",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{photos.map((photo, index) => (
|
||||
<Swiper.Item key={index}>
|
||||
<div
|
||||
className="relative min-w-max"
|
||||
key={index}
|
||||
onClick={() => {
|
||||
showPhotos(photos, index);
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
className="h-12 w-full"
|
||||
fit="cover"
|
||||
height={320}
|
||||
src={photo.url}
|
||||
// onClick={() => {
|
||||
// Toast.show(`你点击了卡片 ${index + 1}`);
|
||||
// }}
|
||||
/>
|
||||
{photo.type == "video" && (
|
||||
<div className="absolute top-0 w-full h-full flex justify-center items-center bg-[#33333348]">
|
||||
<Image
|
||||
className=""
|
||||
width={98}
|
||||
height={98}
|
||||
src="/icons/play.png"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Swiper.Item>
|
||||
))}
|
||||
</Swiper>
|
||||
</div>
|
||||
<div className="p-4 pb-24">
|
||||
<div>
|
||||
<div className="mb-2">
|
||||
<div className="flex items-center mb-2">
|
||||
<p className="text-2xl mr-2">
|
||||
{streamerInfo?.streamer_ext?.name}
|
||||
</p>
|
||||
<div className="w-5 h-5">
|
||||
<Image src="/icons/verification.png" />
|
||||
</div>
|
||||
</div>
|
||||
<ul className="flex">
|
||||
{streamerInfo?.streamer_ext?.tag.map((item, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className="rounded-md bg-primary mr-2 px-2 py-1 text-xs mb-1"
|
||||
>
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="flex mb-1">
|
||||
<li className="h-4 flex items-center text-xs bg-[#FFFFFF1A] rounded-full px-2 py-2.5 mb-1">
|
||||
<Image
|
||||
src="/icons/info/ID.png"
|
||||
width={14}
|
||||
height={14}
|
||||
className="w-4 h-full mr-1"
|
||||
/>
|
||||
<span>{streamerInfo?.streamer_ext?.user_id}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
<span className="text-[#ffffff88]">个性签名|</span>
|
||||
{streamerInfo?.streamer_ext?.bio}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
<div>
|
||||
<div onClick={() => router.push("/space/"+mid)}>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="font-bold text-base">空间动态</span>
|
||||
<div className="h-4 text-xs text-[#ffffff88]">
|
||||
<span className="mr-2">
|
||||
查看{spaceData?.zone_moment_count}条
|
||||
</span>
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="h-4"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex ">
|
||||
{spaceData?.previews?.images.map((item, index) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="w-20 h-20 overflow-hidden rounded"
|
||||
>
|
||||
<Image
|
||||
width="20vw"
|
||||
height="20vw"
|
||||
className={`rounded mr-2 ${!!index && "imageBlur"}`}
|
||||
fit="cover"
|
||||
src={item.urls[0]}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{streamerInfo?.streamer_ext?.platforms && (
|
||||
<>
|
||||
<Divider />
|
||||
<div>
|
||||
<p className="font-bold mb-2 text-base">来这找我玩</p>
|
||||
|
||||
<ul>
|
||||
<li className="flex justify-between border-[1.5px] border-[#ffffff43] rounded-xl p-2 mb-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<Image
|
||||
height={32}
|
||||
width={32}
|
||||
className="mr-2"
|
||||
src="/images/platform_wechat.png"
|
||||
/>
|
||||
<div className="text-base">
|
||||
<span>微信:</span>
|
||||
<span>点击查看</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{streamerInfo?.streamer_ext?.platforms?.map((item) => (
|
||||
<li
|
||||
key={item.id}
|
||||
className="flex justify-between border-[1.5px] border-[#ffffff43] rounded-xl p-2"
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<Image
|
||||
height={32}
|
||||
width={32}
|
||||
className="mr-2"
|
||||
src="/images/platform_douyin.png"
|
||||
/>
|
||||
<div className="text-base">
|
||||
<span>{item?.link_name}:</span>
|
||||
<span>{item?.nickname}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex text-sm">
|
||||
<div
|
||||
className="flex items-center mr-6"
|
||||
// onClick={() => {
|
||||
// Clipboard.setStringAsync(item.url);
|
||||
// }}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faCopy}
|
||||
size="xl"
|
||||
className="h-3 mr-1"
|
||||
/>
|
||||
<span>复制</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="h-3 mr-1"
|
||||
/>
|
||||
<span>前往</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-between items-center px-4 py-4 fixed bottom-0 bg-deepBg w-full border-t-2 border-[#FFFFFF1A]">
|
||||
<div
|
||||
className="text-base bg-[#FFFFFF1A] py-1 px-6 rounded-full"
|
||||
onClick={() => handleFollow(isFollow, Number(mid), setIsFollow)}
|
||||
>
|
||||
{isFollow ? "已关注" : "关注"}
|
||||
</div>
|
||||
<div
|
||||
className="bg-primary px-10 py-1 text-base rounded-full"
|
||||
onClick={() => setVisible(true)}
|
||||
>
|
||||
添加微信
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AddWeChat
|
||||
visible={visible}
|
||||
closeMask={setVisible}
|
||||
price={streamerInfo?.streamer_ext?.wechat_coin_price}
|
||||
name={streamerInfo?.streamer_ext?.name}
|
||||
streamerMid={streamerInfo?.streamer_ext?.mid}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
"use client";
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Image, Swiper, Divider, ImageViewer, Popover } from "antd-mobile";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faAngleLeft,
|
||||
faAngleRight,
|
||||
faEllipsisVertical,
|
||||
faCopy,
|
||||
faWarning,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
export default function PersonSpace() {
|
||||
const router = useRouter();
|
||||
// 获取屏幕高度
|
||||
// const scrollHeight = 600;
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const photos = [
|
||||
{ url: "https://picsum.photos/seed/picsum/200/300", type: "video" },
|
||||
{ url: "https://picsum.photos/seed/picsum/200/300", type: "img" },
|
||||
];
|
||||
useEffect(() => {}, []);
|
||||
const showPhotos = (photos, index) => {
|
||||
ImageViewer.Multi.show({
|
||||
images: photos.map((item) => item.url),
|
||||
defaultIndex: index,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className="">
|
||||
<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
|
||||
icon={faAngleLeft}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Popover
|
||||
content={
|
||||
<div
|
||||
className="text-black"
|
||||
onClick={() => {
|
||||
router.push("messageDetail");
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faWarning}
|
||||
// size="xl"
|
||||
|
||||
color="#3B69B8"
|
||||
className="mr-2"
|
||||
/>
|
||||
<span>举报</span>
|
||||
</div>
|
||||
}
|
||||
trigger="click"
|
||||
placement="left"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faEllipsisVertical}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
// router.back();
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
{/* 内容 */}
|
||||
<div>
|
||||
<div>
|
||||
<Swiper
|
||||
autoplay
|
||||
loop
|
||||
indicatorProps={{
|
||||
style: {
|
||||
"--dot-color": "#FF669E30",
|
||||
"--active-dot-color": "#FF669E",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{photos.map((photo, index) => (
|
||||
<Swiper.Item key={index}>
|
||||
<div
|
||||
className="relative min-w-max"
|
||||
key={index}
|
||||
onClick={() => {
|
||||
showPhotos(photos, index);
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
className="h-12 w-full"
|
||||
fit="cover"
|
||||
height={320}
|
||||
src={photo.url}
|
||||
// onClick={() => {
|
||||
// Toast.show(`你点击了卡片 ${index + 1}`);
|
||||
// }}
|
||||
/>
|
||||
{photo.type == "video" && (
|
||||
<div className="absolute top-0 w-full h-full flex justify-center items-center bg-[#33333348]">
|
||||
<Image
|
||||
className=""
|
||||
width={98}
|
||||
height={98}
|
||||
src="/icons/play.png"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Swiper.Item>
|
||||
))}
|
||||
</Swiper>
|
||||
</div>
|
||||
<div className="p-4 pb-24">
|
||||
<div>
|
||||
<div className="mb-2">
|
||||
<div className="flex items-center mb-2">
|
||||
<p className="text-2xl mr-2">PUPIHAN</p>
|
||||
<div className="w-5 h-5">
|
||||
<Image src="/icons/verification.png" />
|
||||
</div>
|
||||
</div>
|
||||
<ul className="flex">
|
||||
<li className="rounded-md bg-primary mr-2 px-2 py-1 text-xs mb-1">
|
||||
颜值高
|
||||
</li>
|
||||
<li className="rounded-md bg-primary mr-2 px-2 py-1 text-xs mb-1">
|
||||
身材好
|
||||
</li>
|
||||
<li className="rounded-md bg-primary mr-2 px-2 py-1 text-xs mb-1">
|
||||
女王范
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="flex mb-1">
|
||||
<li className="h-4 flex items-center text-xs bg-[#FFFFFF1A] rounded-full px-2 py-2.5 mb-1">
|
||||
<Image
|
||||
src="/icons/info/ID.png"
|
||||
width={14}
|
||||
className="w-4 h-full mr-1"
|
||||
/>
|
||||
<span>213422</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
<span className="text-[#ffffff88]">个性签名|</span>
|
||||
专属圈内容都在空间里,永久更新外面看不到哟
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
<div>
|
||||
<div onClick={() => router.push("/space/person_space")}>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="font-bold text-base">空间动态</span>
|
||||
<div className="h-4 text-xs text-[#ffffff88]">
|
||||
<span className="mr-2">查看60条</span>
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="h-4"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex ">
|
||||
<Image
|
||||
width="20vw"
|
||||
height="20vw"
|
||||
className="rounded mr-2"
|
||||
fit="cover"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
/>
|
||||
<div className="w-20 h-20 overflow-hidden rounded">
|
||||
<Image
|
||||
width="20vw"
|
||||
height="20vw"
|
||||
className="rounded mr-2 imageBlur"
|
||||
fit="cover"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
<div>
|
||||
<p className="font-bold mb-2 text-base">来这找我玩</p>
|
||||
<ul>
|
||||
<li className="flex justify-between border-[1.5px] border-[#ffffff43] rounded-xl p-2 mb-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<Image
|
||||
height={32}
|
||||
width={32}
|
||||
className="mr-2"
|
||||
src="/images/platform_wechat.png"
|
||||
/>
|
||||
<div className="text-base">
|
||||
<span>微信:</span>
|
||||
<span>点击查看</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li className="flex justify-between border-[1.5px] border-[#ffffff43] rounded-xl p-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<Image
|
||||
height={32}
|
||||
width={32}
|
||||
className="mr-2"
|
||||
src="/images/platform_douyin.png"
|
||||
/>
|
||||
<div className="text-base">
|
||||
<span>抖音:</span>
|
||||
<span>PUPIHAN</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex text-sm">
|
||||
<div className="flex items-center mr-6">
|
||||
<FontAwesomeIcon
|
||||
icon={faCopy}
|
||||
size="xl"
|
||||
className="h-3 mr-1"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
<span>复制</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="h-3 mr-1"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
<span>前往</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between items-center px-4 py-4 fixed bottom-0 bg-deepBg w-full border-t-2 border-[#FFFFFF1A]">
|
||||
<div className="text-base bg-[#FFFFFF1A] py-1 px-6 rounded-full">
|
||||
关注
|
||||
</div>
|
||||
<div className="bg-primary px-10 py-1 text-base rounded-full">
|
||||
添加微信
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,31 +1,102 @@
|
|||
"use client";
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Input, List } from "antd-mobile";
|
||||
import { Input, List, DotLoading, Toast } from "antd-mobile";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faAngleLeft } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleLeft } from "@fortawesome/free-solid-svg-icons";
|
||||
import require from "@/utils/require";
|
||||
import { debounce } from "@/utils/tools";
|
||||
import Empty from "@/components/Empty";
|
||||
const newDebounce = debounce(function (fn) {
|
||||
fn && fn();
|
||||
}, 500);
|
||||
export default function Search() {
|
||||
const router = useRouter();
|
||||
// 获取屏幕高度
|
||||
// const scrollHeight = 600;
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [streamers, setStreamers] = useState([]);
|
||||
const [zones, setZones] = useState([]);
|
||||
useEffect(() => {}, []);
|
||||
|
||||
const isNumeric = (str) => {
|
||||
return /^\d+$/.test(str);
|
||||
};
|
||||
const getResult = async (value) => {
|
||||
console.log("searchValue", value);
|
||||
const isSearchInt = isNumeric(value);
|
||||
let api = "";
|
||||
let querryParams = "";
|
||||
if (isSearchInt) {
|
||||
api = "/api/streamer/list_ext_fuzzily_by_user_id";
|
||||
querryParams = { user_id: parseInt(value, 10) };
|
||||
} else {
|
||||
api = "/api/streamer/list_ext_fuzzily_by_name";
|
||||
querryParams = { name: value };
|
||||
}
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await require("POST", api, {
|
||||
body: {
|
||||
...querryParams,
|
||||
offset: 0,
|
||||
limit: 20,
|
||||
},
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
// if (!ignore) {
|
||||
const zonesData = data.data.list.filter((item) => item.zones.length > 0);
|
||||
setStreamers(data.data.list);
|
||||
setZones(zonesData);
|
||||
// }
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex items-center p-4">
|
||||
<FontAwesomeIcon icon={faAngleLeft} size="xl" className="mr-3"onClick={() => {
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleLeft}
|
||||
size="xl"
|
||||
className="mr-3"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}/>
|
||||
}}
|
||||
/>
|
||||
<div className="flex items-center w-full">
|
||||
<div className="bg-[#FFFFFF1A] rounded-lg px-4 py-1 w-full">
|
||||
<div className="relative bg-[#FFFFFF1A] rounded-lg px-4 py-1 w-full">
|
||||
<Input
|
||||
placeholder="搜索Ta的昵称或id"
|
||||
value={searchValue}
|
||||
onChange={(val) => {
|
||||
setSearchValue(val);
|
||||
setSearchValue((old) => {
|
||||
let test = (e) => {
|
||||
if (val == "") {
|
||||
setStreamers([]);
|
||||
setZones([]);
|
||||
return;
|
||||
}
|
||||
getResult(val);
|
||||
};
|
||||
newDebounce(test);
|
||||
return val;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<div className="absolute top-1/2 -translate-y-1/2 right-2">
|
||||
{loading && <DotLoading />}
|
||||
</div>
|
||||
</div>
|
||||
{searchValue && (
|
||||
<p
|
||||
|
@ -40,42 +111,39 @@ export default function Search() {
|
|||
</div>
|
||||
</div>
|
||||
<List className="px-4 overflow-y-auto scrollbarBox_hidden">
|
||||
<List.Item className="!p-0">
|
||||
<div className="flex items-center">
|
||||
<img
|
||||
className="flex-none w-10 h-10 rounded-full mr-2"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
alt=""
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center">
|
||||
<span className="text-md mr-2 text-base text-white font-medium">用户名</span>
|
||||
<span className="py-0.5 px-2 ml-1 bg-[#FFFFFF1A] rounded-full text-white text-xs font-medium">
|
||||
ID 845457
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-[#FFFFFF80]">御姐风细跟高跟鞋太绝了</p>
|
||||
</div>
|
||||
{!streamers.length && (
|
||||
<div
|
||||
className={`h-screen -mt-[57px] flex flex-col items-center justify-center`}
|
||||
>
|
||||
<Empty type="nodata" />
|
||||
</div>
|
||||
</List.Item>
|
||||
<List.Item className="!p-0">
|
||||
<div className="flex items-center">
|
||||
<img
|
||||
className="flex-none w-10 h-10 rounded-full mr-2"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
alt=""
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center">
|
||||
<span className="text-md mr-2 text-base text-white font-medium">用户名</span>
|
||||
<span className="py-0.5 px-2 ml-1 bg-[#FFFFFF1A] rounded-full text-white text-xs font-medium">
|
||||
ID 845457
|
||||
</span>
|
||||
)}
|
||||
{streamers.map((item) => (
|
||||
<List.Item
|
||||
className="!p-0"
|
||||
onClick={() => router.push(`/space/${item.mid}`)}
|
||||
key={item.id}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<img
|
||||
className="flex-none w-10 h-10 rounded-full mr-2"
|
||||
src={item?.avatar?.images[0]?.urls[0]}
|
||||
alt=""
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center">
|
||||
<span className="text-md mr-2 text-base text-white font-medium">
|
||||
{item?.name}
|
||||
</span>
|
||||
<span className="py-0.5 px-2 ml-1 bg-[#FFFFFF1A] rounded-full text-white text-xs font-medium">
|
||||
ID {item.user_id}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-[#FFFFFF80]">{item?.bio}</p>
|
||||
</div>
|
||||
<p className="text-sm text-[#FFFFFF80]">御姐风细跟高跟鞋太绝了</p>
|
||||
</div>
|
||||
</div>
|
||||
</List.Item>
|
||||
</List.Item>
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,474 @@
|
|||
"use client";
|
||||
|
||||
import React, { useEffect, useState, useRef,useMemo } from "react";
|
||||
import {
|
||||
Image,
|
||||
Mask,
|
||||
FloatingPanel,
|
||||
JumboTabs,
|
||||
List,
|
||||
InfiniteScroll,
|
||||
ProgressBar,
|
||||
Toast,
|
||||
} from "antd-mobile";
|
||||
import { useRouter, useParams } from "next/navigation";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleLeft, faRefresh } from "@fortawesome/free-solid-svg-icons";
|
||||
import PostItem from "@/components/PostItem";
|
||||
import PostItemSkeleton from "@/components/skeletons/PostItemSkeleton";
|
||||
import Empty from "@/components/Empty";
|
||||
import require from "@/utils/require";
|
||||
import AddWeChat from "@/components/AddWeChat";
|
||||
import SeeTiefen from "@/components/SeeTiefen";
|
||||
import DefaultMask from "@/components/DefaultMask";
|
||||
import {getSpaceData,getStreamerInfo} from '@/api/space'
|
||||
const anchors = [
|
||||
window.innerHeight - 280,
|
||||
window.innerHeight - 280,
|
||||
window.innerHeight - 60,
|
||||
];
|
||||
const tabItems = [
|
||||
{ label: "全部", key: "all" },
|
||||
{ label: "铁粉专享", key: "ironFan" },
|
||||
{ label: "超粉专享", key: "chaofen" },
|
||||
];
|
||||
export default function PersonSpace() {
|
||||
const router = useRouter();
|
||||
const { id } = useParams();
|
||||
const contentBox = useRef();
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const [scrollHeight, setScrollHeight] = useState(0);
|
||||
const [postList, setPostList] = useState([]);
|
||||
const [offset, setOffset] = useState(0);
|
||||
const [maskVisible, setMaskVisible] = useState({ visible: false, type: "" });
|
||||
const [currentKey, setCurrentKey] = useState("all");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [streamerInfo, setStreamerInfo] = useState(null);
|
||||
const [currentTime, setCurrentTime] = useState();
|
||||
//退款中Modal是否展示
|
||||
const [isRefundingModalVisible, setIsRefundingModalVisible] = useState(false);
|
||||
const ironFanProgress = useMemo(
|
||||
() => Math.floor((streamerInfo?.expenditure / streamerInfo?.ironfanship_price) * 100),
|
||||
[streamerInfo]
|
||||
);
|
||||
useEffect(() => {
|
||||
setScrollHeight(window.innerHeight - 126);
|
||||
if (contentBox.current) {
|
||||
contentBox.current.style.transform = "translateY(-12px)";
|
||||
// debugger
|
||||
}
|
||||
getStreamerInfo(Number(id));
|
||||
getCurrentTime();
|
||||
getSpaceData(Number(id)).then(res=>{
|
||||
const {isRefunding,noRole}=res;
|
||||
isRefunding && router.push("/");
|
||||
noRole && router.push("/person_space_introduce/"+id);
|
||||
})
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
setOffset(0);
|
||||
if (streamerInfo) {
|
||||
getPostList(streamerInfo.id, currentKey, true).then((res) => {
|
||||
setPostList(res);
|
||||
});
|
||||
}
|
||||
}, [currentKey, streamerInfo]);
|
||||
const getCurrentTime = async () => {
|
||||
setCurrentTime(Math.floor(new Date().getTime() / 1000));
|
||||
};
|
||||
async function loadMore() {
|
||||
const append = await getPostList(streamerInfo.id, currentKey, false);
|
||||
if (append) {
|
||||
setPostList((val) => [...val, ...append]);
|
||||
setOffset((val) => val + 1);
|
||||
setHasMore(append.length > 0);
|
||||
}
|
||||
}
|
||||
const getPostList = async (zid, activeKey, first) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
let body = {
|
||||
zid: zid,
|
||||
ct_upper_bound: Math.floor(new Date().getTime() / 1000),
|
||||
offset: first ? 0 : offset,
|
||||
limit: 4,
|
||||
};
|
||||
switch (activeKey) {
|
||||
case "all":
|
||||
body = body;
|
||||
break;
|
||||
case "ironFan":
|
||||
body = {
|
||||
...body,
|
||||
c_type: 1,
|
||||
is_ironfan_visible: 1,
|
||||
};
|
||||
break;
|
||||
case "chaofen":
|
||||
body = {
|
||||
...body,
|
||||
c_type: 1,
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const data = await require("POST", "/api/zone_moment/list_by_zid", {
|
||||
body,
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
return data.data.list;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="">
|
||||
<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
|
||||
icon={faAngleLeft}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Image
|
||||
width={42}
|
||||
height={42}
|
||||
src="/icons/setting.png"
|
||||
placeholder=""
|
||||
onClick={() => router.push("setting")}
|
||||
/>
|
||||
</div>
|
||||
{/* 内容 */}
|
||||
<div>
|
||||
<div
|
||||
className="bg-no-repeat bg-cover bg-fixed "
|
||||
style={{
|
||||
backgroundImage:
|
||||
streamerInfo?.streamer_ext?.cover?.images[0]?.urls[0],
|
||||
}}
|
||||
>
|
||||
<div className="px-4 pt-24 pb-8 bg-[#181818a9]">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<Image
|
||||
width="64px"
|
||||
height="64px"
|
||||
className="rounded-full mr-2 border-2 border-white"
|
||||
fit="cover"
|
||||
src={streamerInfo?.streamer_ext?.avatar?.images[0]?.urls[0]}
|
||||
/>
|
||||
<div>
|
||||
<p className="text-2xl mb-1 font-bold">
|
||||
{streamerInfo?.streamer_ext?.name}
|
||||
</p>
|
||||
<div className="flex">
|
||||
<div className="h-4 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mb-1 w-max mr-1">
|
||||
<Image
|
||||
src="/icons/info/ID.png"
|
||||
width={14}
|
||||
height={14}
|
||||
className="w-4 h-full mr-1"
|
||||
placeholder=""
|
||||
/>
|
||||
<span>{streamerInfo?.streamer_ext?.user_id}</span>
|
||||
</div>
|
||||
<div className="h-4 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mb-1 w-max">
|
||||
<Image
|
||||
src="/icons/edit.png"
|
||||
width={14}
|
||||
height={14}
|
||||
className="w-4 h-full mr-1"
|
||||
placeholder=""
|
||||
/>
|
||||
<span>{streamerInfo?.zone_moment_count}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="flex flex-col items-center"
|
||||
// onClick={() => setMaskVisible(true)}
|
||||
>
|
||||
<p className="text-base px-3 py-1 rounded-full bg-primary">
|
||||
分享
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="flex mt-8">
|
||||
<li
|
||||
className="flex flex-col items-center mr-6"
|
||||
onClick={() =>
|
||||
setMaskVisible({ visible: true, type: "weChat" })
|
||||
}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/images/wechat.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">查看微信</p>
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center mr-6"
|
||||
onClick={() =>
|
||||
setMaskVisible({ visible: true, type: "ironFan" })
|
||||
}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/tiefen.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">
|
||||
{streamerInfo?.is_ironfanship_unlocked === 1
|
||||
? "已是铁粉"
|
||||
: "成为铁粉"}
|
||||
</p>
|
||||
<p className="text-[#ffffff54] text-[10px]">{`${parseInt(
|
||||
streamerInfo?.expenditure / 100,
|
||||
10
|
||||
)}/${parseInt(streamerInfo?.ironfanship_price / 100, 10)}`}</p>
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center mr-6"
|
||||
onClick={() => {
|
||||
streamerInfo?.is_superfanship_unlocked === 1 ? setCurrentKey("chaofen")
|
||||
: router.push("/pay");
|
||||
}}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/chaofen.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">
|
||||
{streamerInfo?.is_superfanship_unlocked === 1
|
||||
? "尊贵超粉"
|
||||
: "成为超粉"}
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
// onClick={() => setMaskVisible(true)}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/report.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">举报</p>
|
||||
</li>
|
||||
{streamerInfo?.visitor_role === 3 && (
|
||||
<li
|
||||
onClick={() =>
|
||||
router.push("VisibleToOneselfSpacePosts")
|
||||
}
|
||||
className="flex flex-col items-center"
|
||||
>
|
||||
<Image
|
||||
src="/icons/review_fail_bg.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
<p className="text-xs">审核未通过</p>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<FloatingPanel anchors={anchors}>
|
||||
<JumboTabs
|
||||
onChange={(key) => setCurrentKey(key)}
|
||||
activeKey={currentKey}
|
||||
className="bg-deepBg"
|
||||
>
|
||||
{tabItems.map((it) => (
|
||||
<JumboTabs.Tab
|
||||
title={it.label}
|
||||
key={it.key}
|
||||
description={
|
||||
currentKey == it.key && (
|
||||
<div className="titlePinkLine relative w-full"></div>
|
||||
)
|
||||
}
|
||||
destroyOnClose={true}
|
||||
>
|
||||
<List className="overflow-y-auto scrollbarBox_hidden px-1">
|
||||
{loading && (
|
||||
<>
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
<PostItemSkeleton />
|
||||
</>
|
||||
)}
|
||||
{!postList.length && (
|
||||
<div
|
||||
className={`flex flex-col items-center mt-20`}
|
||||
style={{ height: `${scrollHeight}px` }}
|
||||
>
|
||||
<Empty type="nodata" />
|
||||
</div>
|
||||
)}
|
||||
{postList.map((item, index) => (
|
||||
<List.Item key={item.id + "_" + index} className="!p-0">
|
||||
<PostItem type="space" data={item} />
|
||||
</List.Item>
|
||||
))}
|
||||
{/* <InfiniteScroll loadMore={loadMore} hasMore={hasMore} /> */}
|
||||
{!!postList.length && streamerInfo && (
|
||||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} />
|
||||
)}
|
||||
</List>
|
||||
</JumboTabs.Tab>
|
||||
))}
|
||||
</JumboTabs>
|
||||
</FloatingPanel>
|
||||
<div
|
||||
className={`fixed bottom-[96px] right-4 z-[999] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white ${
|
||||
loading ? "animate-spin" : ""
|
||||
}`}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faRefresh}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
router.refresh();
|
||||
}}
|
||||
/>
|
||||
</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]">
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => setMaskVisible({ visible: true, type: "weChat" })}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/images/wechat.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">查看微信</p>
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => setMaskVisible({ visible: true, type: "ironFan" })}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/tiefen.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">已是铁粉</p>
|
||||
{/* <p className="text-[#ffffff54] text-[10px]">0/299</p> */}
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => {
|
||||
setCurrentKey("chaofen");
|
||||
}}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/chaofen.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">尊贵超粉</p>
|
||||
</li>
|
||||
</ul>
|
||||
{maskVisible.type=="weChat" && <AddWeChat
|
||||
visible={maskVisible.visible}
|
||||
closeMask={(close) => setMaskVisible({ visible: false, type: "" })}
|
||||
price={streamerInfo?.streamer_ext?.wechat_coin_price}
|
||||
name={streamerInfo?.streamer_ext?.name}
|
||||
streamerMid={streamerInfo?.streamer_ext?.mid}
|
||||
avatar={streamerInfo?.streamer_ext?.avatar?.images[0]?.urls[0]}
|
||||
/>}
|
||||
{maskVisible.type=="ironFan" && <SeeTiefen
|
||||
visible={maskVisible.visible}
|
||||
ironFanProgress={ironFanProgress}
|
||||
expenditure={streamerInfo.expenditure}
|
||||
ironfanship_price={streamerInfo.ironfanship_price}
|
||||
closeMask={() => {
|
||||
setMaskVisible({ visible: false, type: "" });
|
||||
}}
|
||||
handleClick={()=>{
|
||||
setCurrentKey("ironFan");
|
||||
setMaskVisible({ visible: false, type: "" });
|
||||
}}
|
||||
/>}
|
||||
<DefaultMask title="当前空间正在退款中" content="退款中空间不支持查看,请关注原支付渠道退款进度,退款后无法再次进入当前空间。" visible={isRefundingModalVisible} closeMask={() => {
|
||||
setIsRefundingModalVisible(false);
|
||||
// setTimeout(() => navigation.replace("HomeTab"), 500);
|
||||
}}/>
|
||||
{/* <div className="flex justify-center items-center px-4 py-4 fixed bottom-0 bg-deepBg w-full border-t-2 border-[#FFFFFF1A]">
|
||||
<div className="bg-primary px-10 py-1 text-base rounded-full">
|
||||
<div
|
||||
className="flex items-center py-2 text-base"
|
||||
onClick={() => {
|
||||
router.push("/pay");
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
width={18}
|
||||
height={18}
|
||||
placeholder=""
|
||||
className="mr-2"
|
||||
src="/icons/money_pink.png"
|
||||
/>
|
||||
<span>39.9元立即加入</span>
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="h-4 ml-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -79,7 +79,7 @@ export default function Space() {
|
|||
setHasMore(append.length > 0);
|
||||
}
|
||||
return (
|
||||
<main className="h-screen">
|
||||
<div className="h-screen">
|
||||
<div className="flex justify-between items-center p-2 custom-tabs text-gray-400 sticky top-0 z-10 bg-deepBg">
|
||||
<Tabs
|
||||
activeKey={tabItems[activeIndex].key}
|
||||
|
@ -209,7 +209,7 @@ export default function Space() {
|
|||
</div>
|
||||
</Swiper.Item>
|
||||
</Swiper>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,537 +0,0 @@
|
|||
"use client";
|
||||
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import {
|
||||
Image,
|
||||
Mask,
|
||||
FloatingPanel,
|
||||
JumboTabs,
|
||||
List,
|
||||
InfiniteScroll,
|
||||
ProgressBar,
|
||||
} from "antd-mobile";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faAngleLeft,
|
||||
faRefresh,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import PostItem from "@/components/PostItem";
|
||||
import PostItemSkeleton from "@/components/skeletons/PostItemSkeleton";
|
||||
import Empty from "@/components/Empty";
|
||||
const anchors = [
|
||||
window.innerHeight - 280,
|
||||
window.innerHeight - 280,
|
||||
window.innerHeight - 60,
|
||||
];
|
||||
export default function PersonSpace() {
|
||||
const router = useRouter();
|
||||
const contentBox = useRef();
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const [scrollHeight, setScrollHeight] = useState(0);
|
||||
// 获取屏幕高度
|
||||
// const scrollHeight = 600;
|
||||
const photos = [
|
||||
"https://picsum.photos/seed/picsum/200/300",
|
||||
"https://picsum.photos/seed/picsum/200/300",
|
||||
];
|
||||
const [maskVisible, setMaskVisible] = useState({ visible: false, type: "" });
|
||||
const [currentKey, setCurrentKey] = useState("all");
|
||||
useEffect(() => {
|
||||
setScrollHeight(window.innerHeight - 126);
|
||||
if (contentBox.current) {
|
||||
contentBox.current.style.transform = "translateY(-12px)";
|
||||
// debugger
|
||||
}
|
||||
}, []);
|
||||
async function loadMore() {
|
||||
const append = await mockRequest();
|
||||
setData((val) => [...val, ...append]);
|
||||
setHasMore(append.length > 0);
|
||||
}
|
||||
return (
|
||||
<div className="">
|
||||
<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
|
||||
icon={faAngleLeft}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Image width={42} height={42} src="/icons/setting.png" placeholder="" onClick={()=>router.push("setting")}/>
|
||||
</div>
|
||||
{/* 内容 */}
|
||||
<div>
|
||||
<div
|
||||
className="bg-no-repeat bg-cover bg-fixed "
|
||||
style={{
|
||||
backgroundImage: "url('https://picsum.photos/seed/picsum/200/300')",
|
||||
}}
|
||||
>
|
||||
<div className="px-4 pt-24 pb-8 bg-[#181818a9]">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<Image
|
||||
width="64px"
|
||||
height="64px"
|
||||
className="rounded-full mr-2 border-2 border-white"
|
||||
fit="cover"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
/>
|
||||
<div>
|
||||
<p className="text-2xl mb-1 font-bold">草莓不可爱</p>
|
||||
<div className="h-4 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mb-1 w-max">
|
||||
<Image
|
||||
src="/icons/info/ID.png"
|
||||
width={14}
|
||||
className="w-4 h-full mr-1"
|
||||
placeholder=""
|
||||
/>
|
||||
<span>213422</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="flex flex-col items-center"
|
||||
// onClick={() => setMaskVisible(true)}
|
||||
>
|
||||
<p className="text-base px-3 py-1 rounded-full bg-primary">
|
||||
分享
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="flex mt-8">
|
||||
<li
|
||||
className="flex flex-col items-center mr-6"
|
||||
onClick={() =>
|
||||
setMaskVisible({ visible: true, type: "weChat" })
|
||||
}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/images/wechat.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">查看微信</p>
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center mr-6"
|
||||
onClick={() =>
|
||||
setMaskVisible({ visible: true, type: "ironFan" })
|
||||
}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/tiefen.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">已是铁粉</p>
|
||||
<p className="text-[#ffffff54] text-[10px]">0/299</p>
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center mr-6"
|
||||
onClick={() => setCurrentKey("chaofen")}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/chaofen.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">尊贵超粉</p>
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
// onClick={() => setMaskVisible(true)}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/report.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">举报</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<FloatingPanel anchors={anchors}>
|
||||
<JumboTabs
|
||||
onChange={(key) => setCurrentKey(key)}
|
||||
activeKey={currentKey}
|
||||
className="bg-deepBg"
|
||||
>
|
||||
<JumboTabs.Tab
|
||||
title="全部"
|
||||
key="all"
|
||||
description={
|
||||
currentKey == "all" && (
|
||||
<div className="titlePinkLine relative w-full"></div>
|
||||
)
|
||||
}
|
||||
destroyOnClose={true}
|
||||
>
|
||||
<List className="overflow-y-auto scrollbarBox_hidden">
|
||||
<PostItemSkeleton />
|
||||
<List.Item className="!p-0">
|
||||
<PostItem
|
||||
type="space"
|
||||
photos={[
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "video",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</List.Item>
|
||||
<List.Item className="!p-0">
|
||||
<PostItem
|
||||
type="space"
|
||||
photos={[
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</List.Item>
|
||||
<List.Item className="!p-0">
|
||||
<PostItem
|
||||
type="space"
|
||||
photos={[
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</List.Item>
|
||||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} />
|
||||
</List>
|
||||
</JumboTabs.Tab>
|
||||
<JumboTabs.Tab
|
||||
title="铁粉专享"
|
||||
key="ironFan"
|
||||
description={
|
||||
currentKey == "ironFan" && (
|
||||
<div className="titlePinkLine relative w-full"></div>
|
||||
)
|
||||
}
|
||||
destroyOnClose={true}
|
||||
>
|
||||
<div
|
||||
className={`flex flex-col items-center mt-20`}
|
||||
style={{ height: `${scrollHeight}px` }}
|
||||
>
|
||||
<Empty type="nodata" />
|
||||
</div>
|
||||
</JumboTabs.Tab>
|
||||
<JumboTabs.Tab
|
||||
title="超粉专享"
|
||||
key="chaofen"
|
||||
description={
|
||||
currentKey == "chaofen" && (
|
||||
<div className="titlePinkLine relative w-full"></div>
|
||||
)
|
||||
}
|
||||
destroyOnClose={true}
|
||||
>
|
||||
<List className="overflow-y-auto scrollbarBox_hidden">
|
||||
<PostItemSkeleton />
|
||||
<List.Item className="!p-0">
|
||||
<PostItem
|
||||
type="space"
|
||||
photos={[
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "video",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "video",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "video",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</List.Item>
|
||||
<List.Item className="!p-0">
|
||||
<PostItem
|
||||
type="space"
|
||||
photos={[
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</List.Item>
|
||||
<List.Item className="!p-0">
|
||||
<PostItem
|
||||
type="space"
|
||||
photos={[
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
{
|
||||
url: "https://picsum.photos/seed/picsum/200/300",
|
||||
type: "img",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</List.Item>
|
||||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} />
|
||||
</List>
|
||||
</JumboTabs.Tab>
|
||||
</JumboTabs>
|
||||
</FloatingPanel>
|
||||
<div className="fixed bottom-[96px] right-4 z-[999] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white animate-spin">
|
||||
<FontAwesomeIcon
|
||||
icon={faRefresh}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
router.refresh();
|
||||
}}
|
||||
/>
|
||||
</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]">
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => setMaskVisible({ visible: true, type: "weChat" })}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/images/wechat.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">查看微信</p>
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => setMaskVisible({ visible: true, type: "ironFan" })}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/tiefen.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">已是铁粉</p>
|
||||
{/* <p className="text-[#ffffff54] text-[10px]">0/299</p> */}
|
||||
</li>
|
||||
<li
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => setCurrentKey("chaofen")}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/icons/chaofen.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">尊贵超粉</p>
|
||||
</li>
|
||||
</ul>
|
||||
<Mask visible={maskVisible.visible}>
|
||||
<div>
|
||||
<div
|
||||
className="w-full h-screen flex justify-center items-center"
|
||||
onClick={() => setMaskVisible({ visible: false, type: "" })}
|
||||
></div>
|
||||
<div className="w-full h-screen flex justify-center items-center absolute top-0 pointer-events-none">
|
||||
<div className="relative w-[70vw] h-max flex flex-col justify-center items-center p-4 bg-[#261e30] rounded-2xl pointer-events-auto">
|
||||
{maskVisible.type === "weChat" && <SeeWechat />}
|
||||
{maskVisible.type === "ironFan" && (
|
||||
<SeeTiefen
|
||||
handleClick={() => {
|
||||
setCurrentKey("ironFan");
|
||||
setMaskVisible({ visible: false, type: "" });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Mask>
|
||||
{/* <div className="flex justify-center items-center px-4 py-4 fixed bottom-0 bg-deepBg w-full border-t-2 border-[#FFFFFF1A]">
|
||||
<div className="bg-primary px-10 py-1 text-base rounded-full">
|
||||
<div
|
||||
className="flex items-center py-2 text-base"
|
||||
onClick={() => {
|
||||
router.push("/pay");
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
width={18}
|
||||
height={18}
|
||||
placeholder=""
|
||||
className="mr-2"
|
||||
src="/icons/money_pink.png"
|
||||
/>
|
||||
<span>39.9元立即加入</span>
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="h-4 ml-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const SeeTiefen = ({ closeMask, handleClick }) => {
|
||||
return (
|
||||
<div className="relative w-[70vw] h-max flex flex-col justify-center items-center p-4 bg-[#261e30] rounded-2xl pointer-events-auto">
|
||||
<p className="text-base text-left w-full">
|
||||
当前铁粉解锁进度:
|
||||
<span className="text-2xl font-bold text-primary">50%</span>
|
||||
</p>
|
||||
<ProgressBar
|
||||
percent={50}
|
||||
style={{
|
||||
"--fill-color": "#FF669E",
|
||||
"--track-color": "#FF669E50",
|
||||
}}
|
||||
className="w-full mt-2 mb-4"
|
||||
/>
|
||||
<p className="text-left my-2 text-sm text-[#FFFFFF40]">
|
||||
空间内累计消费达到¥1280即可成为
|
||||
<span className="text-primary">铁粉</span>
|
||||
,可查看所有铁粉专享内容哟,快来成为我的铁粉吧~
|
||||
</p>
|
||||
<div
|
||||
className="px-8 py-2 rounded-full flex items-center mt-2 bg-gradient-to-r from-[#FF668B] to-[#FF66F0]"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span className="text-base">查看铁粉专享内容</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const SeeWechat = ({ closeMask }) => {
|
||||
return (
|
||||
<div className="relative w-[70vw] h-max flex flex-col justify-center items-center p-4 pt-10 bg-[#261e30] rounded-2xl pointer-events-auto">
|
||||
<Image
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
width={64}
|
||||
height={64}
|
||||
className="rounded-full absolute -top-8"
|
||||
/>
|
||||
<p className="text-2xl font-bold">草莓不可爱</p>
|
||||
<div className="my-2 bg-[#FFFFFF1A] px-4 py-2 rounded-lg text-base">
|
||||
解锁后展示
|
||||
</div>
|
||||
<p className="text-[red] text-center mb-2">
|
||||
添加时请备注自己“铁粉空间”昵称
|
||||
<br />
|
||||
若解锁后72小时为通过好友,请联系客服
|
||||
</p>
|
||||
<div className="bg-primary px-4 py-2 rounded-full flex items-center">
|
||||
<span className="text-[16px]">解锁微信(990金币)</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,280 @@
|
|||
"use client";
|
||||
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Image, ImageViewer,Dialog } from "antd-mobile";
|
||||
import { useRouter, useParams } from "next/navigation";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleLeft, faAngleRight,faClose,faSave } from "@fortawesome/free-solid-svg-icons";
|
||||
import AddWeChat from "@/components/AddWeChat";
|
||||
import { getStreamerInfo } from "@/api/space";
|
||||
export default function PersonSpaceIntroduce() {
|
||||
const router = useRouter();
|
||||
const contentBox = useRef();
|
||||
// 获取屏幕高度
|
||||
// const scrollHeight = 600;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [data, setData] = useState({});
|
||||
const [isLoading, setIsloading] = useState(true);
|
||||
const { mid } = useParams();
|
||||
useEffect(() => {
|
||||
if (contentBox.current) {
|
||||
contentBox.current.style.transform = "translateY(-12px)";
|
||||
// debugger
|
||||
}
|
||||
|
||||
getStreamerInfo(Number(mid)).then((res) => {
|
||||
setData(res);
|
||||
console.log("mid", mid);
|
||||
});
|
||||
}, []);
|
||||
const showPhotos = (photos, index) => {
|
||||
ImageViewer.Multi.show({
|
||||
images: photos.map((item) => item.urls[0]),
|
||||
defaultIndex: index,
|
||||
});
|
||||
};
|
||||
const handleShowVideo = (video) => {
|
||||
Dialog.className = "videoMask";
|
||||
Dialog.show({
|
||||
title: "",
|
||||
content: (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex w-full justify-end">
|
||||
<div
|
||||
className="flex w-12 h-12 justify-center items-center bg-[#33333348] rounded-full"
|
||||
key="closeBtn"
|
||||
onClick={() => Dialog.clear()}
|
||||
>
|
||||
<FontAwesomeIcon icon={faClose} size="2xl" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-4">
|
||||
<video
|
||||
width="100%"
|
||||
height="100%"
|
||||
controls
|
||||
className="w-screen h-[70vh] rounded-lg object-contain"
|
||||
poster={video.url}
|
||||
>
|
||||
<source src={video.mp4} type="video/mp4" />
|
||||
您的浏览器不支持 Video 标签。
|
||||
</video>
|
||||
</div>
|
||||
<div
|
||||
className="flex w-12 h-12 justify-center items-center bg-[#33333348] rounded-full"
|
||||
key="closeBtn"
|
||||
// onClick={handleSeeAllPhotos}
|
||||
>
|
||||
<FontAwesomeIcon icon={faSave} size="2xl" />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
bodyStyle: {
|
||||
background: "none",
|
||||
maxHeight: "none",
|
||||
height: "100%",
|
||||
},
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className="">
|
||||
<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
|
||||
icon={faAngleLeft}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* 内容 */}
|
||||
<div>
|
||||
<div
|
||||
className="bg-no-repeat bg-cover bg-fixed "
|
||||
style={{
|
||||
backgroundImage: "url('https://picsum.photos/seed/picsum/200/300')",
|
||||
}}
|
||||
>
|
||||
<div className="px-4 pt-24 pb-8 bg-[#181818a9]">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<Image
|
||||
width="64px"
|
||||
height="64px"
|
||||
className="rounded-full mr-2 border-2 border-white"
|
||||
fit="cover"
|
||||
src={data?.streamer_ext?.avatar?.images[0]?.urls[0]}
|
||||
/>
|
||||
<div>
|
||||
<p className="text-2xl mb-1 font-bold">
|
||||
{data?.streamer_ext?.name}
|
||||
</p>
|
||||
<div className="h-4 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mb-1 w-max">
|
||||
<Image
|
||||
src="/icons/info/ID.png"
|
||||
width={14}
|
||||
height={14}
|
||||
className="w-4 h-full mr-1"
|
||||
/>
|
||||
<span>{data?.streamer_ext?.user_id}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => setVisible(true)}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/images/wechat.png"
|
||||
width={22}
|
||||
height={22}
|
||||
className="w-4 h-full"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">查看微信</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="flex justify-around items-center mt-8">
|
||||
<li className="text-center">
|
||||
<p className="font-bold text-2xl">{data?.zone_moment_count}</p>
|
||||
<p>动态</p>
|
||||
</li>
|
||||
<li className="text-center">
|
||||
<p className="font-bold text-2xl">{data?.image_count}</p>
|
||||
<p>照片</p>
|
||||
</li>
|
||||
<li className="text-center">
|
||||
<p className="font-bold text-2xl">{data?.video_count}</p>
|
||||
<p>视频</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-2xl bg-deepBg p-4 pb-24" ref={contentBox}>
|
||||
<p className="text-lg font-bold tabPinkLine relative inline-block">
|
||||
空间介绍
|
||||
</p>
|
||||
<p className="my-2 text-base">{data?.profile}</p>
|
||||
<ul className="grid grid-cols-3 gap-1.5">
|
||||
<li
|
||||
className="relative"
|
||||
onClick={() =>
|
||||
handleShowVideo({
|
||||
url: data?.streamer_ext?.shorts?.videos[0]?.cover_urls[0],
|
||||
mp4: data?.streamer_ext?.shorts?.videos[0]?.urls[0],
|
||||
})
|
||||
}
|
||||
>
|
||||
<div className="absolute top-0 w-full h-full rounded flex justify-center items-center bg-[#33333348]">
|
||||
<Image
|
||||
className=""
|
||||
width={98}
|
||||
height={98}
|
||||
src="/icons/play.png"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
<Image
|
||||
height="28vw"
|
||||
className="rounded"
|
||||
fit="cover"
|
||||
src={data?.streamer_ext?.shorts?.videos[0]?.cover_urls[0]}
|
||||
/>
|
||||
</li>
|
||||
{data?.streamer_ext?.album?.images.map((item, index) => (
|
||||
<li
|
||||
key={item.id}
|
||||
onClick={() =>
|
||||
showPhotos(data?.streamer_ext?.album?.images, index)
|
||||
}
|
||||
>
|
||||
<Image
|
||||
height="28vw"
|
||||
className="rounded"
|
||||
fit="cover"
|
||||
src={item.urls[0]}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{data?.admission_price !== 0 && (
|
||||
<div className="mt-6">
|
||||
<p className="text-lg font-bold mb-2 titlePinkLine relative inline-block">
|
||||
付费须知
|
||||
</p>
|
||||
<div>
|
||||
<p className="text-white text-base mb-1">
|
||||
1、加入后,您可以查看空间内相关内容;
|
||||
</p>
|
||||
<p className="text-white text-base mb-1">
|
||||
2、本空间由空间主人自行创建,加入空间前请确认相关风险,本平台不提供相关保证,请避免上当受骗;
|
||||
</p>
|
||||
<p className="text-white text-base mb-1">
|
||||
3、虚拟商品一经售出不予退款,请确认阅读上述条款并无异议后进行购买。
|
||||
</p>
|
||||
<p className="text-white text-base mb-1">
|
||||
4、本平台不提供违法及色情内容,如您发现空间内存在以上内容,请联系人工客服举报处理。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<AddWeChat
|
||||
visible={visible}
|
||||
closeMask={() => setVisible(false)}
|
||||
name={data?.streamer_ext?.name}
|
||||
price={data?.streamer_ext?.wechat_coin_price}
|
||||
streamerMid={data?.streamer_ext?.mid}
|
||||
avatar={data?.streamer_ext?.avatar?.images[0]?.urls[0]}
|
||||
/>
|
||||
{/* <Mask visible={visible} >
|
||||
<div className="w-full h-screen flex justify-center items-center" onClick={() => setVisible(false)}>
|
||||
<div className="relative w-[70vw] h-max flex flex-col justify-center items-center p-4 pt-10 bg-[#261e30] rounded-2xl">
|
||||
<Image src="https://picsum.photos/seed/picsum/200/300" width={64} height={64} className="rounded-full absolute -top-8"/>
|
||||
<p className="text-2xl font-bold">草莓不可爱</p>
|
||||
<div className="my-2 bg-[#FFFFFF1A] px-4 py-2 rounded-lg text-base">
|
||||
解锁后展示
|
||||
</div>
|
||||
<p className="text-[red] text-center mb-2">
|
||||
添加时请备注自己“铁粉空间”昵称
|
||||
<br />
|
||||
若解锁后72小时为通过好友,请联系客服
|
||||
</p>
|
||||
<div className="bg-primary px-4 py-2 rounded-full flex items-center">
|
||||
<span className="text-[16px]">解锁微信(990金币)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Mask> */}
|
||||
<div className="flex justify-center items-center px-4 py-4 fixed bottom-0 bg-deepBg w-full border-t-2 border-[#FFFFFF1A]">
|
||||
<div className="bg-primary px-10 py-1 text-base rounded-full">
|
||||
{/* <Image/> */}
|
||||
<div
|
||||
className="flex items-center py-2 text-base"
|
||||
onClick={() => {
|
||||
router.push("/pay");
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
width={18}
|
||||
height={18}
|
||||
placeholder=""
|
||||
className="mr-2"
|
||||
src="/icons/money_pink.png"
|
||||
/>
|
||||
<span>39.9元立即加入</span>
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="h-4 ml-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
"use client";
|
||||
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Image, Mask } from "antd-mobile";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleLeft, faAngleRight } from "@fortawesome/free-solid-svg-icons";
|
||||
export default function PersonSpaceIntroduce() {
|
||||
const router = useRouter();
|
||||
const contentBox = useRef();
|
||||
// 获取屏幕高度
|
||||
// const scrollHeight = 600;
|
||||
const photos = [
|
||||
"https://picsum.photos/seed/picsum/200/300",
|
||||
"https://picsum.photos/seed/picsum/200/300",
|
||||
];
|
||||
const [visible, setVisible] = useState(false);
|
||||
useEffect(() => {
|
||||
if (contentBox.current) {
|
||||
contentBox.current.style.transform = "translateY(-12px)";
|
||||
// debugger
|
||||
}
|
||||
}, []);
|
||||
return (
|
||||
<div className="">
|
||||
<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
|
||||
icon={faAngleLeft}
|
||||
size="xl"
|
||||
onClick={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* 内容 */}
|
||||
<div>
|
||||
<div
|
||||
className="bg-no-repeat bg-cover bg-fixed "
|
||||
style={{
|
||||
backgroundImage: "url('https://picsum.photos/seed/picsum/200/300')",
|
||||
}}
|
||||
>
|
||||
<div className="px-4 pt-24 pb-8 bg-[#181818a9]">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<Image
|
||||
width="64px"
|
||||
height="64px"
|
||||
className="rounded-full mr-2 border-2 border-white"
|
||||
fit="cover"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
/>
|
||||
<div>
|
||||
<p className="text-2xl mb-1 font-bold">草莓不可爱</p>
|
||||
<div className="h-4 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mb-1 w-max">
|
||||
<Image
|
||||
src="/icons/info/ID.png"
|
||||
width={14}
|
||||
className="w-4 h-full mr-1"
|
||||
/>
|
||||
<span>213422</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="flex flex-col items-center"
|
||||
onClick={() => setVisible(true)}
|
||||
>
|
||||
<div className="w-9 h-9 flex items-center justify-center bg-[#1d1d1d71] rounded-full mb-1">
|
||||
<Image
|
||||
src="/images/wechat.png"
|
||||
width={22}
|
||||
className="w-4 h-full"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs">查看微信</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="flex justify-around items-center mt-8">
|
||||
<li className="text-center">
|
||||
<p className="font-bold text-2xl">38</p>
|
||||
<p>动态</p>
|
||||
</li>
|
||||
<li className="text-center">
|
||||
<p className="font-bold text-2xl">38</p>
|
||||
<p>照片</p>
|
||||
</li>
|
||||
<li className="text-center">
|
||||
<p className="font-bold text-2xl">38</p>
|
||||
<p>视频</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-2xl bg-deepBg p-4 pb-24" ref={contentBox}>
|
||||
<p className="text-lg font-bold tabPinkLine relative inline-block">空间介绍</p>
|
||||
<p className="my-2 text-base">
|
||||
草莓秘密基地,一次进入永久权限。都是你想看到的哟。
|
||||
</p>
|
||||
<ul className="grid grid-cols-3 gap-1.5">
|
||||
<li>
|
||||
<Image
|
||||
height="28vw"
|
||||
className="rounded"
|
||||
fit="cover"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Image
|
||||
height="28vw"
|
||||
className="rounded"
|
||||
fit="cover"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Image
|
||||
height="28vw"
|
||||
className="rounded"
|
||||
fit="cover"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Image
|
||||
height="28vw"
|
||||
className="rounded"
|
||||
fit="cover"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Image
|
||||
height="28vw"
|
||||
className="rounded"
|
||||
fit="cover"
|
||||
src="https://picsum.photos/seed/picsum/200/300"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="mt-6">
|
||||
<p className="text-lg font-bold mb-2 titlePinkLine relative inline-block">付费须知</p>
|
||||
<div>
|
||||
<p className="text-white text-base mb-1">
|
||||
1、加入后,您可以查看空间内相关内容;
|
||||
</p>
|
||||
<p className="text-white text-base mb-1">
|
||||
2、本空间由空间主人自行创建,加入空间前请确认相关风险,本平台不提供相关保证,请避免上当受骗;
|
||||
</p>
|
||||
<p className="text-white text-base mb-1">
|
||||
3、虚拟商品一经售出不予退款,请确认阅读上述条款并无异议后进行购买。
|
||||
</p>
|
||||
<p className="text-white text-base mb-1">
|
||||
4、本平台不提供违法及色情内容,如您发现空间内存在以上内容,请联系人工客服举报处理。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Mask visible={visible} >
|
||||
<div className="w-full h-screen flex justify-center items-center" onClick={() => setVisible(false)}>
|
||||
<div className="relative w-[70vw] h-max flex flex-col justify-center items-center p-4 pt-10 bg-[#261e30] rounded-2xl">
|
||||
<Image src="https://picsum.photos/seed/picsum/200/300" width={64} height={64} className="rounded-full absolute -top-8"/>
|
||||
<p className="text-2xl font-bold">草莓不可爱</p>
|
||||
<div className="my-2 bg-[#FFFFFF1A] px-4 py-2 rounded-lg text-base">
|
||||
解锁后展示
|
||||
</div>
|
||||
<p className="text-[red] text-center mb-2">
|
||||
添加时请备注自己“铁粉空间”昵称
|
||||
<br />
|
||||
若解锁后72小时为通过好友,请联系客服
|
||||
</p>
|
||||
<div className="bg-primary px-4 py-2 rounded-full flex items-center">
|
||||
<span className="text-[16px]">解锁微信(990金币)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Mask>
|
||||
<div className="flex justify-center items-center px-4 py-4 fixed bottom-0 bg-deepBg w-full border-t-2 border-[#FFFFFF1A]">
|
||||
<div className="bg-primary px-10 py-1 text-base rounded-full">
|
||||
{/* <Image/> */}
|
||||
<div className="flex items-center py-2 text-base" onClick={() => {
|
||||
router.push("/pay");
|
||||
}}>
|
||||
<Image width={18} height={18} placeholder="" className="mr-2" src="/icons/money_pink.png"/>
|
||||
<span>39.9元立即加入</span>
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
size="xl"
|
||||
className="h-4 ml-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Image, Mask, Toast } from "antd-mobile";
|
||||
import require from "@/utils/require";
|
||||
import { get } from "@/utils/storeInfo";
|
||||
import { useRouter } from "next/navigation";
|
||||
export default function AddWeChat({
|
||||
visible,
|
||||
closeMask,
|
||||
name,
|
||||
price,
|
||||
streamerMid,
|
||||
avatar
|
||||
}) {
|
||||
const [isMoneyEnough, setIsMoneyEnough] = useState(true);
|
||||
const router = useRouter();
|
||||
//点击解锁微信按钮
|
||||
const unlockWechat = async () => {
|
||||
//余额不够就显示余额不足前往充值,够就直接购买
|
||||
|
||||
//先支付,支付成功后添加解锁关系,再展示解锁界面
|
||||
//支付金币解锁微信
|
||||
const account = get("account");
|
||||
if (account) {
|
||||
try {
|
||||
const userResponse = await require("POST", "/api/account/list_by_mid", {
|
||||
body: {
|
||||
mid: account.mid,
|
||||
},
|
||||
});
|
||||
if (userResponse.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (userResponse?.data.account?.gold_num >= price) {
|
||||
console.log("余额足够");
|
||||
const data = await require("POST", "/api/vas/one_step_unlock", {
|
||||
body: {
|
||||
contact_product_id: "contact_wechat",
|
||||
uid: streamerMid,
|
||||
},
|
||||
});
|
||||
if (data.ret === -1) {
|
||||
Toast.show({
|
||||
icon: "fail",
|
||||
content: data.msg,
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
//展示解锁界面
|
||||
// setIsWechatUnlocked(true);
|
||||
} else {
|
||||
setIsMoneyEnough(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Mask visible={visible}>
|
||||
<div className="relative w-screen h-screen">
|
||||
<div className="w-full h-full" onClick={() => closeMask(false)}></div>
|
||||
<div className="absolute top-1/2 left-1/2 -ml-[35vw] -mt-[35vw] w-[70vw] h-max flex flex-col justify-center items-center p-4 pt-10 bg-[#261e30] rounded-2xl">
|
||||
{isMoneyEnough ? (
|
||||
<>
|
||||
<Image
|
||||
src={avatar}
|
||||
width={64}
|
||||
height={64}
|
||||
className="rounded-full absolute -top-8"
|
||||
/>
|
||||
<p className="text-2xl font-bold">{name}</p>
|
||||
<div className="my-2 bg-[#FFFFFF1A] px-4 py-2 rounded-lg text-base">
|
||||
解锁后展示
|
||||
</div>
|
||||
<p className="text-[red] text-center mb-2">
|
||||
添加时请备注自己“铁粉空间”昵称
|
||||
<br />
|
||||
若解锁后72小时为通过好友,请联系客服
|
||||
</p>
|
||||
<div
|
||||
className="bg-primary px-4 py-2 rounded-full flex items-center"
|
||||
onClick={unlockWechat}
|
||||
>
|
||||
<span className="text-[16px]">解锁微信({price}金币)</span>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="text-2xl text-white font-medium mb-4">
|
||||
余额不足
|
||||
</p>
|
||||
<div
|
||||
onClick={() => {
|
||||
router.push("/my/wallet");
|
||||
closeMask(false);
|
||||
setIsMoneyEnough(true);
|
||||
}}
|
||||
className="px-4 py-2 bg-[#FF669E] rounded-full items-center justify-center"
|
||||
>
|
||||
<span className="text-white text-base">前往充值</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Mask>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { Mask } from "antd-mobile";
|
||||
export default function DefaultMask({
|
||||
visible,
|
||||
closeMask,
|
||||
handleClick,
|
||||
title,
|
||||
content
|
||||
}) {
|
||||
|
||||
return (
|
||||
<Mask visible={visible}>
|
||||
<div className="relative w-screen h-screen">
|
||||
<div className="w-full h-full" onClick={() => closeMask(false)}></div>
|
||||
<div className="absolute top-1/2 left-1/2 -ml-[35vw] -mt-[35vw] w-[70vw] h-max flex flex-col justify-center items-center p-4 bg-[#261e30] rounded-2xl pointer-events-auto">
|
||||
|
||||
<p>{title}</p>
|
||||
<p>{content}</p>
|
||||
<div
|
||||
className="px-8 py-2 rounded-full flex items-center mt-2 bg-gradient-to-r from-[#FF668B] to-[#FF66F0]"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span className="text-base">确定</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Mask>
|
||||
);
|
||||
}
|
|
@ -3,14 +3,18 @@
|
|||
import React, { useRef, useState } from "react";
|
||||
import { Image } from "antd-mobile";
|
||||
|
||||
export default function PaySpacePost({
|
||||
type = "ironFan",
|
||||
price = "0.00",
|
||||
status = 0,
|
||||
}) {
|
||||
export default function PaySpacePost({ type = "ironFan", status = 0,data={} }) {
|
||||
return (
|
||||
<div className={`rounded-md ${type === "ironFan" ? "bg-primary-500" : "bg-super-500"} px-2 py-2 my-2 text-sm`}>
|
||||
<div className={`flex justify-between items-center text-sm text-super mb-2 text-${type === "ironFan" ? "primary" : "super"}`}>
|
||||
<div
|
||||
className={`rounded-md ${
|
||||
type === "ironFan" ? "bg-primary-500" : "bg-super-500"
|
||||
} px-2 py-2 my-2 text-sm`}
|
||||
>
|
||||
<div
|
||||
className={`flex justify-between items-center text-sm ${
|
||||
type === "ironFan" ? "text-primary" : "text-super"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<Image
|
||||
width={18}
|
||||
|
@ -23,21 +27,40 @@ export default function PaySpacePost({
|
|||
: "/icons/money_gold.png"
|
||||
}
|
||||
/>
|
||||
<span className="font-bold">{price}元</span>
|
||||
<span className="font-bold">{data.price / 100}元</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span>{status === 1 ? "已付费解锁" : `${type === "ironFan"?'铁粉':'超粉'}免费查看`}</span>
|
||||
{!data.is_zone_moment_unlocked ? (
|
||||
<span>
|
||||
{status === 1
|
||||
? "已付费解锁"
|
||||
: `${type === "ironFan" ? "铁粉" : "超粉"}免费查看`}
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
{data.is_ironfan_visible === 1
|
||||
? "铁粉免费查看"
|
||||
: data.is_superfanship_enabled === 1
|
||||
? "超粉免费查看"
|
||||
: "付费解锁"}
|
||||
</span>
|
||||
)}
|
||||
<Image
|
||||
height={14}
|
||||
placeholder=""
|
||||
className="ml-2"
|
||||
src={type === "ironFan"?"/icons/pinklink.png":"/icons/goldlink.png"}
|
||||
src={
|
||||
type === "ironFan" ? "/icons/pinklink.png" : "/icons/goldlink.png"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{status === 0 && (
|
||||
<p className="text-xs" style={{color:type === "ironFan" ? "#ff669e54" : "#FFD68554"}}>
|
||||
空间内任何消费满399元即可成为铁粉
|
||||
<p
|
||||
className="text-xs mb-2"
|
||||
style={{ color: type === "ironFan" ? "#ff669e54" : "#FFD68554" }}
|
||||
>
|
||||
空间内任何消费满{data.ironfanship_price}元即可成为铁粉
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|||
import { Image, ImageViewer, Dialog } from "antd-mobile";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleUp, faClose, faSave } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
const tabItems = [
|
||||
{ key: "commend", title: "推荐" },
|
||||
{ key: "follow", title: "关注" },
|
||||
|
@ -13,15 +14,10 @@ export default function Photos({ media }) {
|
|||
const [seeAllPhotos, setSeeAllPhotos] = useState(false);
|
||||
const [currentPhotos, setCurrentPhotos] = useState([]);
|
||||
const [photos, setPhotos] = useState([]);
|
||||
const [currentVideos, setCurrentVideos] = useState([]);
|
||||
const [videoVisible, setVideoVisible] = useState({
|
||||
video: "",
|
||||
visible: false,
|
||||
});
|
||||
useEffect(() => {
|
||||
if (media) {
|
||||
let imgArr = media.images.map(item=>({type:"img",url:item.cover_urls[0]}))
|
||||
let videoArr = media.videos.map(item=>({type:"video",url:item.cover_urls[0],mp4:item.urls[0]}))
|
||||
let imgArr = media.images.map(item=>({type:"img",url:item.urls?.[0]}))
|
||||
let videoArr = media.videos.map(item=>({type:"video",url:item.cover_urls?.[0],mp4:item.urls?.[0]}))
|
||||
let arr=[...imgArr,...videoArr]
|
||||
let newPhotos = [...arr];
|
||||
setPhotos(arr);
|
||||
|
@ -50,7 +46,7 @@ export default function Photos({ media }) {
|
|||
key="closeBtn"
|
||||
onClick={() => Dialog.clear()}
|
||||
>
|
||||
<FontAwesomeIcon icon={faClose} size="2xl" className="h-12" />
|
||||
<FontAwesomeIcon icon={faClose} size="2xl" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-4">
|
||||
|
@ -58,7 +54,7 @@ export default function Photos({ media }) {
|
|||
width="100%"
|
||||
height="100%"
|
||||
controls
|
||||
className="w-screen h-[70vh] rounded-lg object-cover"
|
||||
className="w-screen h-[70vh] rounded-lg object-contain"
|
||||
poster={video.url}
|
||||
>
|
||||
<source
|
||||
|
@ -73,7 +69,7 @@ export default function Photos({ media }) {
|
|||
key="closeBtn"
|
||||
onClick={handleSeeAllPhotos}
|
||||
>
|
||||
<FontAwesomeIcon icon={faSave} size="xl" className="h-12" />
|
||||
<FontAwesomeIcon icon={faSave} size="2xl"/>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
|
@ -120,18 +116,18 @@ export default function Photos({ media }) {
|
|||
placeholder={
|
||||
<div className="w-full h-full bg-[#1d1d1d] rounded"></div>
|
||||
}
|
||||
width={currentPhotos.length > 1 ? "100%" : 150}
|
||||
height={currentPhotos.length > 1 ? "24vw" : 200}
|
||||
className="rounded"
|
||||
width={currentPhotos.length > 1 ? "26vw" : "100%"}
|
||||
height={currentPhotos.length > 1 ? "26vw" : "100%"}
|
||||
className={`rounded max-w-[80vw] max-h-[80vw] `}
|
||||
fit="cover"
|
||||
src={item.url}
|
||||
/>
|
||||
{item.type == "video" && (
|
||||
<div className="absolute top-0 w-full h-full flex justify-center items-center bg-[#33333348]">
|
||||
<div className="absolute top-0 w-full h-full rounded flex justify-center items-center bg-[#33333348]">
|
||||
<Image
|
||||
className=""
|
||||
width={64}
|
||||
height={64}
|
||||
width={98}
|
||||
height={98}
|
||||
src="/icons/play.png"
|
||||
placeholder=""
|
||||
/>
|
||||
|
|
|
@ -7,6 +7,8 @@ import PaySpacePost from "../PaySpacePost";
|
|||
import { Image } 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"
|
||||
export default function PostItem({
|
||||
type,
|
||||
follow,
|
||||
|
@ -15,9 +17,15 @@ 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);
|
||||
//判断是否是发帖人
|
||||
const [isCreator, setIsCreator] = useState(false);
|
||||
useEffect(() => {
|
||||
const account = get("account");
|
||||
if (account.mid === data.mid) setIsCreator(true);
|
||||
return () => {
|
||||
router.prefetch("/profile");
|
||||
router.prefetch("/profile/"+data.mid);
|
||||
};
|
||||
}, []);
|
||||
const getDays = useMemo(() => {
|
||||
|
@ -35,15 +43,18 @@ 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")}
|
||||
onClick={() => router.push("/profile/"+data.mid)}
|
||||
/>
|
||||
|
||||
<div className="flex-1">
|
||||
<div className="flex justify-between items-center">
|
||||
<div
|
||||
className="flex justify-between items-center"
|
||||
onClick={() => handleFollow(isFollow, data?.mid, setIsFollow)}
|
||||
>
|
||||
<span className="font-bold text-md">{data.streamer_ext?.name}</span>
|
||||
{type == "post" && (
|
||||
<span className="rounded-full bg-[#FFFFFF1A] px-2 py-1 text-xs text-white font-medium">
|
||||
{data.is_followed ? "已关注" : "关注"}
|
||||
{isFollow ? "已关注" : "关注"}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
@ -51,50 +62,67 @@ export default function PostItem({
|
|||
<p className={`mb-2 mt-2 ${!isOpenText ? "text-ellipsis-3" : ""}`}>
|
||||
{data.text}
|
||||
</p>
|
||||
{
|
||||
data.text?.length>50 &&
|
||||
{data.text?.length > 50 && (
|
||||
<div
|
||||
className="font-bold text-btn my-4 text-base"
|
||||
onClick={() => setIsOpenText(!isOpenText)}
|
||||
>
|
||||
{isOpenText ? "收起" : "全文"}
|
||||
</div>
|
||||
}
|
||||
className="font-bold text-btn my-4 text-base"
|
||||
onClick={() => setIsOpenText(!isOpenText)}
|
||||
>
|
||||
{isOpenText ? "收起" : "全文"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{data.media_component && <Photos media={data.media_component} />}
|
||||
{type == "space" && (
|
||||
<PaySpacePost type="superFan" price="19.89" status={0} />
|
||||
{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 className="flex justify-between items-center mt-2">
|
||||
{type == "post" ? (
|
||||
<div className="flex items-center">
|
||||
{
|
||||
data.is_active_within_a_week &&
|
||||
<div
|
||||
className="flex items-center"
|
||||
onClick={() => router.push("/profile/"+data.mid)}
|
||||
>
|
||||
{data.is_active_within_a_week ? (
|
||||
<>
|
||||
<Image
|
||||
src="/icons/space_new_post.png"
|
||||
width={18}
|
||||
className="w-4 h-full mr-1"
|
||||
placeholder=""
|
||||
/>
|
||||
<span className="mr-1 text-primary text-xs">
|
||||
{data.days_elapsed_since_the_last_zones_update < 7
|
||||
? `空间${
|
||||
data.days_elapsed_since_the_last_zones_update === 0
|
||||
? "今日"
|
||||
: "new" === 1
|
||||
? "昨日"
|
||||
: "new" === 2
|
||||
? "前天"
|
||||
: data.days_elapsed_since_the_last_zones_update + "天前"
|
||||
}有更新`
|
||||
: "1" === 2
|
||||
? "空间今日有更新"
|
||||
: ""}
|
||||
</span>
|
||||
<FontAwesomeIcon icon={faAngleRight} color="#FF669E" size="sm" />
|
||||
<Image
|
||||
src="/icons/space_new_post.png"
|
||||
width={18}
|
||||
className="w-4 h-full mr-1"
|
||||
placeholder=""
|
||||
/>
|
||||
<span className="mr-1 text-primary text-xs">
|
||||
{data.days_elapsed_since_the_last_zones_update < 7 &&
|
||||
`空间${
|
||||
data.days_elapsed_since_the_last_zones_update === 0
|
||||
? "今日"
|
||||
: "new" === 1
|
||||
? "昨日"
|
||||
: "new" === 2
|
||||
? "前天"
|
||||
: data.days_elapsed_since_the_last_zones_update +
|
||||
"天前"
|
||||
}有更新`}
|
||||
</span>
|
||||
<FontAwesomeIcon
|
||||
icon={faAngleRight}
|
||||
color="#FF669E"
|
||||
size="sm"
|
||||
/>
|
||||
</>
|
||||
}
|
||||
) : (
|
||||
data?.streamer_ext?.zones?.length !== 0 && (
|
||||
<div className="text-[#FFFFFFB2] font-medium text-xs flex items-center">
|
||||
<span className="mr-1">查看TA的空间</span>
|
||||
<FontAwesomeIcon icon={faAngleRight} size="sm" />
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-[#ffffff88] text-xs">
|
||||
|
@ -109,9 +137,16 @@ export default function PostItem({
|
|||
</div>
|
||||
)}
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center mr-4">
|
||||
<div
|
||||
className="flex items-center mr-4 h-[32px]"
|
||||
onClick={() => thumbsUp(data.id, isThumbsUp, setIsThumbsUp)}
|
||||
>
|
||||
<Image
|
||||
src={data.is_thumbed_up ? "/icons/thumbup.png":"/icons/notthumbup.png"}
|
||||
src={
|
||||
isThumbsUp == 1
|
||||
? "/icons/thumbup.png"
|
||||
: "/icons/notthumbup.png"
|
||||
}
|
||||
width={32}
|
||||
className="w-4 h-full"
|
||||
placeholder=""
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Mask, ProgressBar } from "antd-mobile";
|
||||
import require from "@/utils/require";
|
||||
import { get } from "@/utils/storeInfo";
|
||||
import { useRouter } from "next/navigation";
|
||||
export default function SeeTiefen({
|
||||
visible,
|
||||
closeMask,
|
||||
handleClick,
|
||||
ironFanProgress,
|
||||
expenditure,
|
||||
ironfanship_price
|
||||
}) {
|
||||
|
||||
return (
|
||||
<Mask visible={visible}>
|
||||
<div className="relative w-screen h-screen">
|
||||
<div className="w-full h-full" onClick={() => closeMask(false)}></div>
|
||||
<div className="absolute top-1/2 left-1/2 -ml-[35vw] -mt-[35vw] w-[70vw] h-max flex flex-col justify-center items-center p-4 bg-[#261e30] rounded-2xl pointer-events-auto">
|
||||
<p className="text-base text-left w-full">
|
||||
当前铁粉解锁进度:
|
||||
<span className="text-2xl font-bold text-primary">{ironFanProgress}%</span>
|
||||
</p>
|
||||
<ProgressBar
|
||||
percent={ironFanProgress}
|
||||
style={{
|
||||
"--fill-color": "#FF669E",
|
||||
"--track-color": "#FF669E50",
|
||||
}}
|
||||
className="w-full mt-2 mb-4"
|
||||
/>
|
||||
<p className="text-sm text-[#FF669E] font-medium">{`${
|
||||
expenditure / 100
|
||||
} / ${ironfanship_price / 100}`}</p>
|
||||
<p className="text-left my-2 text-sm text-[#FFFFFF40]">
|
||||
空间内累计消费达到¥1280即可成为
|
||||
<span className="text-primary">铁粉</span>
|
||||
,可查看所有铁粉专享内容哟,快来成为我的铁粉吧~
|
||||
</p>
|
||||
<div
|
||||
className="px-8 py-2 rounded-full flex items-center mt-2 bg-gradient-to-r from-[#FF668B] to-[#FF66F0]"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span className="text-base">查看铁粉专享内容</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Mask>
|
||||
);
|
||||
}
|
|
@ -11,12 +11,16 @@
|
|||
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@reduxjs/toolkit": "^2.2.6",
|
||||
"antd-mobile": "^5.36.1",
|
||||
"cookies-next": "^4.0.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"next": "14.0.2",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-redux": "^9.1.2",
|
||||
"redux": "^5.0.1",
|
||||
"sass": "^1.77.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -445,6 +449,29 @@
|
|||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmmirror.com/@reduxjs/toolkit/-/toolkit-2.2.6.tgz",
|
||||
"integrity": "sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA==",
|
||||
"dependencies": {
|
||||
"immer": "^10.0.3",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"reselect": "^5.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.9.0 || ^17.0.0 || ^18",
|
||||
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmmirror.com/@swc/helpers/-/helpers-0.5.2.tgz",
|
||||
|
@ -463,6 +490,11 @@
|
|||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-16.18.101.tgz",
|
||||
"integrity": "sha512-AAsx9Rgz2IzG8KJ6tXd6ndNkVcu+GYB6U/SnFAaokSPNx2N7dcIIfnighYUNumvj6YS2q39Dejz5tT0NCV7CWA=="
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
|
||||
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
|
||||
},
|
||||
"node_modules/@use-gesture/core": {
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/@use-gesture/core/-/core-10.3.0.tgz",
|
||||
|
@ -1180,6 +1212,15 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz",
|
||||
"integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.3.6.tgz",
|
||||
|
@ -1323,6 +1364,11 @@
|
|||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"node_modules/jsencrypt": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/jsencrypt/-/jsencrypt-3.3.2.tgz",
|
||||
"integrity": "sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A=="
|
||||
},
|
||||
"node_modules/kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz",
|
||||
|
@ -2025,6 +2071,28 @@
|
|||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
|
||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
||||
},
|
||||
"node_modules/react-redux": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-9.1.2.tgz",
|
||||
"integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
|
||||
"dependencies": {
|
||||
"@types/use-sync-external-store": "^0.0.3",
|
||||
"use-sync-external-store": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"react": "^18.0",
|
||||
"redux": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",
|
||||
|
@ -2045,11 +2113,29 @@
|
|||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
|
||||
},
|
||||
"node_modules/redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/redux-thunk/-/redux-thunk-3.1.0.tgz",
|
||||
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
|
||||
"peerDependencies": {
|
||||
"redux": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
},
|
||||
"node_modules/reselect": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/reselect/-/reselect-5.1.1.tgz",
|
||||
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="
|
||||
},
|
||||
"node_modules/resize-observer-polyfill": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||
|
@ -2928,6 +3014,17 @@
|
|||
"@react-spring/types": "~9.6.1"
|
||||
}
|
||||
},
|
||||
"@reduxjs/toolkit": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmmirror.com/@reduxjs/toolkit/-/toolkit-2.2.6.tgz",
|
||||
"integrity": "sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA==",
|
||||
"requires": {
|
||||
"immer": "^10.0.3",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"reselect": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"@swc/helpers": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmmirror.com/@swc/helpers/-/helpers-0.5.2.tgz",
|
||||
|
@ -2946,6 +3043,11 @@
|
|||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-16.18.101.tgz",
|
||||
"integrity": "sha512-AAsx9Rgz2IzG8KJ6tXd6ndNkVcu+GYB6U/SnFAaokSPNx2N7dcIIfnighYUNumvj6YS2q39Dejz5tT0NCV7CWA=="
|
||||
},
|
||||
"@types/use-sync-external-store": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
|
||||
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
|
||||
},
|
||||
"@use-gesture/core": {
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/@use-gesture/core/-/core-10.3.0.tgz",
|
||||
|
@ -3457,6 +3559,11 @@
|
|||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"immer": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz",
|
||||
"integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw=="
|
||||
},
|
||||
"immutable": {
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.3.6.tgz",
|
||||
|
@ -3562,6 +3669,11 @@
|
|||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"jsencrypt": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/jsencrypt/-/jsencrypt-3.3.2.tgz",
|
||||
"integrity": "sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A=="
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz",
|
||||
|
@ -4000,6 +4112,15 @@
|
|||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
|
||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-9.1.2.tgz",
|
||||
"integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
|
||||
"requires": {
|
||||
"@types/use-sync-external-store": "^0.0.3",
|
||||
"use-sync-external-store": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",
|
||||
|
@ -4017,11 +4138,27 @@
|
|||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
|
||||
},
|
||||
"redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/redux-thunk/-/redux-thunk-3.1.0.tgz",
|
||||
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
|
||||
"requires": {}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
},
|
||||
"reselect": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/reselect/-/reselect-5.1.1.tgz",
|
||||
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="
|
||||
},
|
||||
"resize-observer-polyfill": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||
|
|
|
@ -12,12 +12,16 @@
|
|||
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@reduxjs/toolkit": "^2.2.6",
|
||||
"antd-mobile": "^5.36.1",
|
||||
"cookies-next": "^4.0.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"next": "14.0.2",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-redux": "^9.1.2",
|
||||
"redux": "^5.0.1",
|
||||
"sass": "^1.77.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
Binary file not shown.
After ![]() (image error) Size: 258 B |
|
@ -0,0 +1,7 @@
|
|||
"use client";
|
||||
export const handleLogin = (data) => ({
|
||||
type: 'HANDLOGIN',
|
||||
data
|
||||
});
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
"use client";
|
||||
|
||||
import { configureStore } from '@reduxjs/toolkit'; // 请确保已安装 "@reduxjs/toolkit"
|
||||
import reducers from './reducers';
|
||||
|
||||
const store = configureStore({
|
||||
reducer: reducers,
|
||||
});
|
||||
// export default rootReducer;
|
||||
|
||||
export default store;
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
"use client";
|
||||
|
||||
import { combineReducers } from "redux";
|
||||
const initialState = {
|
||||
authInfo: {
|
||||
isSignin: false,
|
||||
userToken: null,
|
||||
},
|
||||
};
|
||||
let text = (data) => {
|
||||
return data ? data.token : undefined;
|
||||
};
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case "HANDLOGIN":
|
||||
return { ...state, authInfo: action.data };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
const reducers = combineReducers({
|
||||
reducer,
|
||||
});
|
||||
|
||||
export default reducers;
|
|
@ -1,47 +1,23 @@
|
|||
import { setCookie, deleteCookie, getCookie } from "cookies-next";
|
||||
import baseRequest from "./baseRequest";
|
||||
import { generateSignature } from "@/utils/crypto";
|
||||
|
||||
import require from "./require";
|
||||
export async function checkAuth() {
|
||||
const token = getCookie("token");
|
||||
const account = getCookie("account");
|
||||
if (token && account) {
|
||||
//验证是否过期
|
||||
try {
|
||||
const base = baseRequest();
|
||||
const signature = generateSignature({
|
||||
...base,
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/login/validate?signature=${signature}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...base,
|
||||
}),
|
||||
}
|
||||
);
|
||||
const data = await response.json();
|
||||
if (data.ret === -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
try {
|
||||
const data = await require("POST", `/api/login/validate`);
|
||||
if (data.ret === -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function signIn(data) {
|
||||
setCookie("token", data.data.token);
|
||||
setCookie("account", data.data.account);
|
||||
setCookie("mid", data.data.account.mid);
|
||||
}
|
||||
|
||||
export function signOut() {
|
||||
deleteCookie("token");
|
||||
deleteCookie("account");
|
||||
deleteCookie("mid");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { getCookie } from "cookies-next";
|
||||
|
||||
import { get } from "./storeInfo";
|
||||
export default function baseRequest() {
|
||||
const token = getCookie("token");
|
||||
const accountCookie = getCookie("account");
|
||||
const account = accountCookie === undefined ? {} : JSON.parse(accountCookie);
|
||||
const accountCookie = get("account");
|
||||
const account = accountCookie === undefined ? {} : accountCookie;
|
||||
const mid = getCookie("mid");
|
||||
const b_ts = new Date().getTime();
|
||||
const baseRequest = {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import baseRequest from "./baseRequest";
|
||||
import {get} from "./storeInfo";
|
||||
// import webviewBaseRequest from "@/utils/webviewBaseRequest";
|
||||
const base = baseRequest();
|
||||
// 创建一个封装 fetch 的函数
|
||||
export default function customFetch(method, url, options = {}) {
|
||||
export default function customFetch(method, url, options = {},mid) {
|
||||
// 默认选项
|
||||
const defaultOptions = {
|
||||
method: method,
|
||||
|
@ -14,10 +15,14 @@ export default function customFetch(method, url, options = {}) {
|
|||
}
|
||||
// 可以添加其他默认选项
|
||||
};
|
||||
const body=JSON.stringify({...base,...options.body})
|
||||
let newBody = {...options.body}
|
||||
if(mid){
|
||||
newBody.mid=get("account").mid
|
||||
}
|
||||
const body=JSON.stringify({...base,...newBody})
|
||||
// 合并选项
|
||||
const mergedOptions = { ...defaultOptions, body};
|
||||
console.log("mergedOptions",mergedOptions)
|
||||
// console.log("mergedOptions",mergedOptions)
|
||||
// 返回 Promise 对象
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(url, mergedOptions)
|
||||
|
|
|
@ -2,11 +2,26 @@ export function save(key,value){
|
|||
localStorage.setItem(key,value)
|
||||
}
|
||||
export function get(key){
|
||||
localStorage.getItem(key)
|
||||
let data = localStorage.getItem(key);
|
||||
return data ? JSON.parse(data) : {};
|
||||
}
|
||||
export function remove(key){
|
||||
localStorage.removeItem(key)
|
||||
}
|
||||
export function clear(){
|
||||
localStorage.clear()
|
||||
}
|
||||
}
|
||||
|
||||
export function saveUserInfo (data, mobilePhone, regionCode){
|
||||
save("token", data.data.token);
|
||||
save("account", JSON.stringify(data.data.account));
|
||||
save("mobile_phone", mobilePhone);
|
||||
save("region_code", regionCode);
|
||||
}
|
||||
export function removeUserInfo (){
|
||||
remove("token");
|
||||
remove("account");
|
||||
remove("mobile_phone");
|
||||
remove("region_code");
|
||||
|
||||
}
|
|
@ -1,12 +1,31 @@
|
|||
//格式化时间戳
|
||||
export function formatDeadline(timestamp) {
|
||||
const date = new Date(timestamp * 1000); // 时间戳以秒为单位,需要乘以1000转换成毫秒
|
||||
const year = date.getFullYear();
|
||||
const month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
const day = ("0" + date.getDate()).slice(-2);
|
||||
const hours = ("0" + date.getHours()).slice(-2);
|
||||
const minutes = ("0" + date.getMinutes()).slice(-2);
|
||||
const seconds = ("0" + date.getSeconds()).slice(-2);
|
||||
const date = new Date(timestamp * 1000); // 时间戳以秒为单位,需要乘以1000转换成毫秒
|
||||
const year = date.getFullYear();
|
||||
const month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
const day = ("0" + date.getDate()).slice(-2);
|
||||
const hours = ("0" + date.getHours()).slice(-2);
|
||||
const minutes = ("0" + date.getMinutes()).slice(-2);
|
||||
const seconds = ("0" + date.getSeconds()).slice(-2);
|
||||
|
||||
return `${year}年${month}月${day}日 ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
return `${year}年${month}月${day}日 ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
// 防抖函数
|
||||
export function debounce(fn, delay) {
|
||||
let timer = null;
|
||||
return (fnn) => {
|
||||
//清除上一次的延时器
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
// return;
|
||||
console.log(timer);
|
||||
}
|
||||
//重新设置新的延时器
|
||||
timer = setTimeout(() => {
|
||||
//修改this指向问题
|
||||
// fn.apply(this,value)
|
||||
fn(fnn);
|
||||
}, delay);
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue