添加合伙人和代运营设置

This commit is contained in:
al 2024-11-18 18:40:08 +08:00
parent b175252714
commit c6ac80cd12
6 changed files with 1078 additions and 13 deletions

View File

@ -190,6 +190,28 @@ export default function Wallet() {
style={{ maxWidth: "12px" }}
/>
</div>
<div
onClick={() => router.push("/bill/income/income_querry")}
className="flex justify-between items-center py-4"
>
<div className="flex flex-row items-center">
<FontAwesomeIcon
icon={faPrint}
size="xl"
color="#60a5fa"
className="w-[28px]"
style={{ maxWidth: "20px" }}
/>
<span className="text-base text-white font-medium ml-2">
近一周收支
</span>
</div>
<FontAwesomeIcon
icon={faAngleRight}
size="xl"
style={{ maxWidth: "12px" }}
/>
</div>
</div>
</div>
</div>

View File

@ -155,7 +155,6 @@ export default function CreateImagePost() {
...imageAssets.filter((it) => it.id != undefined).map((it) => it.id),
...media.image_ids,
];
debugger;
try {
const body = {
c_type: parseInt(price) ? 1 : 0,

View File

@ -1,7 +1,7 @@
"use client";
import React, { useEffect, useState, useRef } from "react";
import { Image, Toast } from "antd-mobile";
import { Image, Toast, Dialog } from "antd-mobile";
import { useRouter, useParams } from "next/navigation";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
@ -20,6 +20,7 @@ export default function PersonSpaceIntroduce() {
const base = baseRequest();
const router = useRouter();
const contentBox = useRef();
const handler = useRef(null);
// 获取屏幕高度
// const scrollHeight = 600;
const [visible, setVisible] = useState(false);
@ -249,17 +250,34 @@ export default function PersonSpaceIntroduce() {
if (data?.admission_price === 0) {
handleJoinFreeSpace();
} else {
// router.push("/pay");
router.push(
"/webView/" +
encodeURIComponent(
"/zone/pay/" +
data?.id +
"/h5_zone_admission/0" +
"?base=" +
encodeURIComponent(JSON.stringify(base))
)
);
handler.current = Dialog.confirm({
header: "提醒",
content:
"本空间内容为达人创建并维护,属于虚拟服务,不可退款,且空间内存在部分内容需要另外付费,请再次确认是否付费加入",
bodyStyle: {
maxHeight: "none",
width: "80vw",
position: "fixed",
top: "200px",
left: "10vw",
"--text-color": "#fff",
},
onAction: (res) => {
if (res.key === "confirm") {
// router.push("/pay");
router.push(
"/webView/" +
encodeURIComponent(
"/zone/pay/" +
data?.id +
"/h5_zone_admission/0" +
"?base=" +
encodeURIComponent(JSON.stringify(base))
)
);
}
},
});
}
}}
>

View File

@ -19,6 +19,8 @@ export default function Setting() {
const router = useRouter();
const params = useParams();
const [streamerInfo, setStreamerInfo] = useState(null);
//是否对主播展示代运营设置
const [isAgencyHided, setIsAgencyHided] = useState(false);
useEffect(() => {
(async () => {
const { mid } = params;
@ -31,6 +33,7 @@ export default function Setting() {
...info,
refund_enable: res?.refund_enable,
});
isShowThird(parseInt(mid));
});
}
})();
@ -112,6 +115,27 @@ export default function Setting() {
// console.error(error);
}
};
const isShowThird = async (id) => {
console.log(id);
try {
const _data = await requireAPI("POST", "/api/zone_third_partner/list", {
body: {
zid: id,
},
});
if (_data.ret === -1) {
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
setIsAgencyHided(_data.data.zone_third_partner?.is_hided != 1);
} catch (error) {
// console.error(error);
}
};
return (
<div className="">
<div className="p-4 fixed top-0 z-10 w-full">
@ -233,8 +257,47 @@ export default function Setting() {
</div>
<Divider />
</li>
{isAgencyHided && (
<li>
<div
onClick={() =>
router.push("agencySetting?zid=" + streamerInfo.id)
}
className="flex justify-between"
>
<span className="text-base text-white">代运营设置</span>
<FontAwesomeIcon
icon={faAngleRight}
size="xl"
style={{ maxWidth: "12px" }}
/>
</div>
<Divider />
</li>
)}
</>
)}
{(streamerInfo?.visitor_role === 1 ||
streamerInfo?.visitor_role === 2) && (
<li>
<div
onClick={() =>
router.push(
`collaboratorSetting?zid=${streamerInfo.id}&visitor_role=${streamerInfo.visitor_role}`
)
}
className="flex justify-between"
>
<span className="text-base text-white">合伙人设置</span>
<FontAwesomeIcon
icon={faAngleRight}
size="xl"
style={{ maxWidth: "12px" }}
/>
</div>
<Divider />
</li>
)}
{streamerInfo?.refund_enable === 1 &&
streamerInfo?.admission_price > 0 &&
streamerInfo?.visitor_role === 0 && (

View File

@ -0,0 +1,448 @@
"use client";
import React, {
useState,
useEffect,
useMemo,
useCallback,
useRef,
} from "react";
import {
Image,
Toast,
Dialog,
Picker,
Avatar,
Space,
SpinLoading,
} from "antd-mobile";
import Empty from "@/components/Empty";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faAngleLeft,
faAdd,
faSortDown,
} from "@fortawesome/free-solid-svg-icons";
import requireAPI from "@/utils/requireAPI";
import { useRouter, useSearchParams } from "next/navigation";
import OwnInput from "@/components/OwnInput";
import { get } from "@/utils/storeInfo";
import { JSEncrypt } from "jsencrypt";
export default function AgencySetting() {
const [data, setData] = useState(null);
const [modalVisible, setModalVisible] = useState(false);
const [isloading, setIsloading] = useState([]);
const searchParams = useSearchParams();
const router = useRouter();
const handler = useRef(null);
const getData = async () => {
const zid = Number(searchParams.get("zid"));
try {
setIsloading(true);
const body = {
zid,
};
const _data = await requireAPI("POST", "/api/zone_third_partner/list", {
body,
});
if (_data.ret === -1) {
setIsloading(false);
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
setData(_data.data.zone_third_partner);
} catch (error) {
console.error(error);
}
setIsloading(false);
};
useEffect(() => {
getData();
}, []);
useEffect(() => {
if (!modalVisible && handler.current) {
handler.current?.close();
}
}, [modalVisible]);
const handleAddAgency = () => {
setModalVisible(!modalVisible);
const zid = Number(searchParams.get("zid"));
handler.current = Dialog.show({
content: <ModalMask setModalVisible={setModalVisible} zid={zid} />,
bodyStyle: {
backgroundColor: "#17161A",
maxHeight: "none",
width: "90vw",
position: "fixed",
top: "200px",
left: "5vw",
"--text-color": "#fff",
color: "#fff",
},
});
};
return (
<div>
{isloading && (
<div
className="bg-[#00000099] fixed top-0 w-full text-center flex items-center justify-center h-screen"
// style={{ height: scrollHeight - 60 + "px" }}
>
<SpinLoading />
</div>
)}
{/* 头部标题 */}
<div className="p-4 fixed top-0 z-10 w-full bg-black">
<div className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full absolute">
<FontAwesomeIcon
icon={faAngleLeft}
style={{ maxWidth: "12px" }}
size="xl"
onClick={() => {
router.back();
}}
/>
</div>
<p className="text-base text-center leading-9">代运营设置</p>
</div>
{/* 内容 */}
<div className="p-4 pt-20">
<div className="flex justify-center items-center">
{data ? (
<Image
src={data?.third_partner_account.avatar.images[0].urls[0]}
width={74}
height={74}
className="h-full mr-1"
placeholder=""
/>
) : (
<div
onClick={handleAddAgency}
className="border border-white rounded-full w-[4.6rem] h-[4.6rem] flex items-center justify-center"
>
<FontAwesomeIcon
icon={faAdd}
style={{ maxWidth: "20px" }}
size="2xl"
/>
</div>
)}
</div>
<div className="mt-8 text-[#FFFFFF80] text-sm">
<p className="text-base font-medium">注意事项</p>
<p>
1一个空间仅可设置一个代运营若您的代运营团队为多人请设置代运营主账号后让代运营主账号进入当前空间设置合伙人
</p>
<p>
2设置完成后无法再次修改人员和分成比例请确认后再提交后续如需修改请联系人工客服
</p>
<p>
3您获得的收益会按照您设置的分成比例直接转移至代运营及协作者账户您将不会得到这部分的收益如有疑问请咨询人工客服
</p>
</div>
</div>
</div>
);
}
const ModalMask = ({ setModalVisible, zid }) => {
const [isloading, setIsloading] = useState([]);
const [isSelected, setIsSelected] = useState(false);
const [seconds, setSeconds] = useState(60);
const [agencyData, setAgencyData] = useState(null);
const [mobilePhone, setMobilePhone] = useState("");
const [regionCode, setRegionCode] = useState("");
const [veriCode, setVeriCode] = useState("");
const [userId, setUserId] = useState("");
const [isCounting, setIsCounting] = useState(false);
const [rate, setRate] = useState([null]);
//
const generateItems = useCallback((min, max) => {
const items = [];
for (let i = min; i <= max; i++) {
items.push({ label: `${i.toString()}%`, value: i.toString() });
}
return items;
}, []);
const rates = useMemo(() => generateItems(1, 50), []);
useEffect(() => {
async function getMobilePhone() {
setMobilePhone(await get("mobile_phone"));
setRegionCode(await get("region_code"));
}
getMobilePhone();
}, []);
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 handleSearch = async (id) => {
try {
setIsloading(true);
const body = {
user_id: parseInt(id, 10),
};
const _data = await requireAPI(
"POST",
"/api/account/list_others_by_user_id",
{
body,
}
);
if (_data.ret === -1) {
setIsloading(false);
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
setAgencyData(_data.data.account);
setIsSelected(false);
} catch (error) {
console.error(error);
}
};
//
const handleVerification = async () => {
if (!isSelected) {
Toast.show({
icon: "fail",
content: "请先选中用户",
position: "top",
});
return;
}
//
setIsCounting(true);
//RSA
const encrypt = new JSEncrypt();
encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY);
const mobile_phone = encrypt.encrypt(mobilePhone);
//
try {
const data = await fetch(`/api/veri_code/send`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mobile_phone,
region_code: regionCode,
}),
});
if (data.ret === -1) {
Toast.show({
icon: "fail",
content: data.msg,
position: "top",
});
return;
}
} catch (error) {
// console.error(error);
}
};
const handleSubmit = async () => {
if (!isSelected) {
Toast.show({
icon: "fail",
content: "请先选中用户",
position: "top",
});
return;
}
if (!veriCode) {
Toast.show({
icon: "fail",
content: "请输入验证码",
position: "top",
});
return;
}
if (!rate[0]) {
Toast.show({
icon: "fail",
content: "请选择分成比例",
position: "top",
});
return;
}
try {
//RSA
const encrypt = new JSEncrypt();
encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY);
const mobile_phone = encrypt.encrypt(mobilePhone);
const body = {
zid,
third_partner_mid: agencyData.mid,
region_code: regionCode,
mobile_phone: mobile_phone,
veri_code: veriCode,
sharing_ratio: parseInt(rate[0], 10) / 100,
};
const _data = await requireAPI("POST", "/api/zone_third_partner/create", {
body,
});
if (_data.ret === -1) {
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
setModalVisible(false);
} catch (error) {
console.error(error);
}
};
return (
<div className="flex flex-col w-full rounded-3xl ">
<div className="flex flex-row items-center mb-4">
<span className="text-base font-medium">搜索用户:</span>
<OwnInput
placeholder="请输入用户ID"
type="number"
onChange={(value) => {
setUserId(value);
}}
value={userId}
className="flex-1 bg-[#FFFFFF1A] text-white rounded-2xl px-4 h-8 mx-2"
/>
<span
onClick={() => handleSearch(userId)}
className="text-[#FF669E] text-base font-medium"
>
搜索
</span>
</div>
{agencyData && (
<div
className="flex flex-row items-center rounded-2xl p-4 mb-4 border"
style={{ borderColor: isSelected ? "#FF669E" : "#2c2b2f" }}
>
<Avatar
src={agencyData?.avatar?.images[0]?.urls[0]}
fit="cover"
style={{ "--border-radius": "100px", "--size": "42px" }}
/>
<div className="flex flex-1 flex-col justify-around items-start ml-2">
<span className="text-base font-medium whitespace-nowrap">
{agencyData?.name}
</span>
<div className="flex flex-row items-center py-0.5 px-2 bg-[#FFFFFF1A] rounded-full">
<Image
src={
process.env.NEXT_PUBLIC_WEB_ASSETS_URL + "/icons/info/ID.png"
}
width={14}
height={14}
className="w-4 h-full mr-1"
/>
<span className="text-xs font-medium ml-0.5 whitespace-nowrap">
{agencyData?.user_id}
</span>
</div>
</div>
<div
className="px-4 py-2 text-sm font-medium rounded-full"
style={{
backgroundColor: isSelected ? "#FFFFFF1A" : "#FF669E",
}}
onClick={() => setIsSelected(!isSelected)}
>
{isSelected ? "取消" : "选择"}
</div>
</div>
)}
<div className="flex flex-row items-center mb-4">
<span className="text-base font-medium">
手机号:
<span className="text-[#FFFFFF80] ml-2">
{mobilePhone?.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2")}
</span>
</span>
</div>
<div className="flex flex-row items-center mb-4">
<span className="text-base font-medium">验证码:</span>
<OwnInput
placeholder="请输入验证码"
type="number"
onChange={(value) => setVeriCode(value)}
value={veriCode}
className="flex-1 bg-[#FFFFFF1A] rounded-2xl px-4 h-8 mx-2"
/>
<div
className="bg-[#FF669E] px-2 py-1 text-sm font-medium rounded-full"
disabled={isCounting}
onClick={handleVerification}
>
{isCounting ? `(${seconds})重新发送` : "获取验证码"}
</div>
</div>
<div className="flex flex-row items-center mb-4">
<span className="text-base font-medium">分成比例</span>
<div className="w-1/3">
<Picker columns={[rates]} onConfirm={setRate} value={rate}>
{(items, { open }) => {
return (
<Space
align="center"
direction="horizontal"
justify="center"
onClick={open}
>
{items.every((item) => item === null)
? "未选择"
: items.map((item) => item?.label ?? "未选择").join("")}
<FontAwesomeIcon
icon={faSortDown}
style={{ maxWidth: "12px", marginBottom: 6 }}
size="lg"
/>
</Space>
);
}}
</Picker>
</div>
</div>
<span className="text-[#F53030] text-xs font-medium">
注意事项分成比例不得超过50%且确认后无法修改
</span>
<div className="grid grid-cols-2 gap-2 mt-2">
<div
className="bg-[#FF669E] text-center w-full py-2 text-md font-medium rounded-full"
onClick={handleSubmit}
>
确认
</div>
<div
className="bg-[#FFFFFF1A] text-center w-full py-2 text-md font-medium rounded-full"
onClick={() => setModalVisible(false)}
>
取消
</div>
</div>
</div>
);
};

View File

@ -0,0 +1,515 @@
"use client";
import React, {
useState,
useEffect,
useMemo,
useCallback,
useRef,
} from "react";
import {
Image,
Toast,
SpinLoading,
Picker,
Avatar,
Space,
List,
Dialog,
} from "antd-mobile";
import Empty from "@/components/Empty";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faAngleLeft,
faAdd,
faSortDown,
faMoneyBill,
} from "@fortawesome/free-solid-svg-icons";
import requireAPI from "@/utils/requireAPI";
import { useRouter, useSearchParams } from "next/navigation";
import OwnInput from "@/components/OwnInput";
import { get } from "@/utils/storeInfo";
import { JSEncrypt } from "jsencrypt";
export default function CollaboratorSetting() {
const [data, setData] = useState(null);
const [selfMid, setSelfMid] = useState();
const [modalVisible, setModalVisible] = useState(false);
const [isloading, setIsloading] = useState([]);
const searchParams = useSearchParams();
const router = useRouter();
const handler = useRef(null);
useEffect(() => {
getData();
}, []);
useEffect(() => {
if (!modalVisible && handler.current) {
handler.current?.close();
}
}, [modalVisible]);
//
const remainingRate = useMemo(() => {
if (!data) return;
const totalRate = data?.list?.reduce((acc, cur) => {
return acc + cur.sharing_ratio || 0;
}, 0);
return !totalRate
? 0
: (data?.zone_third_partner?.sharing_ratio - totalRate).toFixed(2);
}, [data]);
const getData = async () => {
const zid = Number(searchParams.get("zid"));
const visitor_role = Number(searchParams.get("visitor_role"));
try {
setIsloading(true);
setSelfMid(zid);
const body = {
zid,
visitor_role,
};
const _data = await requireAPI("POST", "/api/zone_collaborator/list", {
body,
});
if (_data.ret === -1) {
setIsloading(false);
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
setData(_data.data);
} catch (error) {
console.error(error);
}
setIsloading(false);
};
const handleAddCollaborator = () => {
setModalVisible(!modalVisible);
const zid = Number(searchParams.get("zid"));
handler.current = Dialog.show({
content: (
<ModalMask
setModalVisible={setModalVisible}
zid={zid}
handleRefresh={getData}
/>
),
bodyStyle: {
backgroundColor: "#17161A",
maxHeight: "none",
width: "80vw",
position: "fixed",
top: "200px",
left: "10vw",
"--text-color": "#fff",
color: "#fff",
},
});
};
//
const handleDelete = async (id) => {
const visitor_role = Number(searchParams.get("visitor_role"));
if (visitor_role !== 1) return;
try {
const body = {
id,
};
const _data = await requireAPI("POST", "/api/zone_collaborator/delete", {
body,
});
if (_data.ret === -1) {
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
Toast.show({
icon: "success",
content: "移除合伙人成功",
position: "top",
});
getData();
} catch (error) {
console.error(error);
}
};
//
const CollaboratorItem = useCallback(({ item }) => {
return (
<div className="border-b border-[#ffffff80]">
<List.Item className="p-0 bg-transparent">
<div className="flex-1">
<div className="flex items-center">
<Avatar
src={item?.collaborator_account?.avatar.images[0].urls[0]}
fit="cover"
style={{ "--border-radius": "100px", "--size": "42px" }}
/>
<div className="ml-2 justify-around flex-1">
<p
className="text-base font-medium"
numberOfLines={1}
ellipsizeMode="tail"
>
{item?.collaborator_account?.name}
</p>
<div className="flex">
<div className="h-4 mr-1 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mt-1 w-max">
<Image
src={
process.env.NEXT_PUBLIC_WEB_ASSETS_URL +
"/icons/info/ID.png"
}
width={14}
height={14}
className="w-4 h-full mr-1"
placeholder=""
/>
<span>{item?.collaborator_account?.user_id}</span>
</div>
<div className="h-4 mr-1 flex items-center text-xs bg-[#ffffff18] rounded-full px-2 py-2.5 mt-1 w-max">
<div className="mr-1">
<FontAwesomeIcon icon={faMoneyBill} size="sm" />
</div>
<span>
{item?.sharing_ratio
? (item?.sharing_ratio * 100).toFixed()
: 0}
%
</span>
</div>
</div>
</div>
{!item?.isDeleteBtnInvisible && (
<div
className="bg-[#F53030] ml-2 h-8 flex justify-center items-center text-sm font-medium px-3 rounded-full"
onClick={() => handleDelete(item.id)}
>
移除
</div>
)}
</div>
</div>
</List.Item>
</div>
);
}, []);
const selfData = data?.list?.filter(
(item) => item.collaborator_mid === selfMid
);
return (
<div>
{isloading && (
<div
className="bg-[#00000099] fixed top-0 w-full text-center flex items-center justify-center h-screen"
// style={{ height: scrollHeight - 60 + "px" }}
>
<SpinLoading />
</div>
)}
{/* 头部标题 */}
<div className="p-4 fixed top-0 z-10 w-full bg-black">
<div className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full absolute">
<FontAwesomeIcon
icon={faAngleLeft}
style={{ maxWidth: "12px" }}
size="xl"
onClick={() => {
router.back();
}}
/>
</div>
<p className="text-base text-center leading-9">合伙人设置</p>
</div>
{/* 内容 */}
<div className="p-4 pt-20">
{searchParams.get("visitor_role") === 2 ? (
<div className="p-4 pt-20">
<div className="flex flex-col border-2 border-[#2c2b2f] rounded-2xl p-4 w-full mt-6">
<p>合伙人昵称{selfData[0]?.collaborator_account?.name}</p>
<p>ID{selfData[0]?.collaborator_account?.user_id}</p>
<p>
分成比例
{selfData[0]?.sharing_ratio
? (selfData[0]?.sharing_ratio * 100).toFixed()
: 0}
%
</p>
</div>
</div>
) : (
<div className="flex flex-col items-center p-4">
<div className="flex flex-col items-center">
<p className="text-base font-medium">总分成比例</p>
<p className="text-[#F53030] text-3xl font-medium my-2">
{data?.zone_third_partner?.sharing_ratio
? (data?.zone_third_partner?.sharing_ratio * 100).toFixed()
: 0}
%
</p>
<p className="text-[#FFFFFF80] text-sm">修改比例请联系平台客服</p>
</div>
<div className="h-[3px] rounded-full w-full bg-[#FFFFFF26] mt-4"></div>
<div className="flex flex-col w-full mb-4">
<List style={{ "--padding-left": "0" }}>
<CollaboratorItem
item={{
collaborator_account:
data?.zone_third_partner?.third_partner_account,
sharing_ratio: remainingRate,
isDeleteBtnInvisible: true,
}}
/>
{data?.list?.map((item, index) => (
<CollaboratorItem key={index} item={item} />
))}
</List>
</div>
<div
onClick={handleAddCollaborator}
className="border border-white rounded-full w-[4.6rem] h-[4.6rem] flex items-center justify-center"
>
<FontAwesomeIcon
icon={faAdd}
style={{ maxWidth: "20px" }}
size="2xl"
/>
</div>
</div>
)}
<div className="mt-8 text-[#FFFFFF80] text-sm">
<p className="text-base font-medium">注意事项</p>
<p>
1总分成比例由当前空间主人设置您的个人分成比例由代运营进行设置
</p>
<p>
2您的个人收益计算公式为空间收益x个人分成比例=个人收益收益将以钻石形式发放至您的钱包
</p>
<p>3若您对收益情况存在任何疑问请联系人工客服</p>
</div>
</div>
</div>
);
}
const ModalMask = ({ setModalVisible, zid, handleRefresh }) => {
const [isloading, setIsloading] = useState([]);
const [isSelected, setIsSelected] = useState(false);
const [seconds, setSeconds] = useState(60);
const [mobilePhone, setMobilePhone] = useState("");
const [regionCode, setRegionCode] = useState("");
const [userId, setUserId] = useState("");
const [isCounting, setIsCounting] = useState(false);
const [rate, setRate] = useState([null]);
const [collaboratorData, setCollaboratorData] = useState();
//
const generateItems = useCallback((min, max) => {
const items = [];
for (let i = min; i <= max; i++) {
items.push({ label: `${i.toString()}%`, value: i.toString() });
}
return items;
}, []);
const rates = useMemo(() => generateItems(1, 50), []);
useEffect(() => {
async function getMobilePhone() {
setMobilePhone(await get("mobile_phone"));
setRegionCode(await get("region_code"));
}
getMobilePhone();
}, []);
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 handleSearch = async (id) => {
try {
setIsloading(true);
const body = {
user_id: parseInt(id, 10),
};
const _data = await requireAPI(
"POST",
"/api/account/list_others_by_user_id",
{
body,
}
);
if (_data.ret === -1) {
setIsloading(false);
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
setCollaboratorData(_data.data.account);
setIsSelected(false);
} catch (error) {
console.error(error);
}
};
const handleSubmit = async () => {
if (!isSelected) {
Toast.show({
icon: "fail",
content: "请先选中用户",
position: "top",
});
return;
}
if (!rate[0]) {
Toast.show({
icon: "fail",
content: "请选择分成比例",
position: "top",
});
return;
}
try {
const body = {
zid,
collaborator_mid: collaboratorData.mid,
sharing_ratio: parseInt(rate[0], 10) / 100,
};
const data = await requireAPI("POST", "/api/zone_collaborator/create", {
body,
});
if (data.ret === -1) {
Toast.show({
icon: "fail",
content: data.msg,
position: "top",
});
return;
}
Toast.show({
icon: "success",
content: "添加合伙人成功",
position: "top",
});
handleRefresh();
setModalVisible(false);
} catch (error) {
console.error(error);
}
};
return (
<div className="flex flex-col w-full bg-[#17161A] rounded-3xl ">
<div className="flex flex-row items-center mb-4">
<span className="text-base font-medium">搜索用户</span>
<OwnInput
placeholder="请输入用户ID"
type="number"
onChange={(value) => setUserId(value)}
value={userId}
className="flex-1 bg-[#FFFFFF1A] text-white rounded-2xl px-4 h-8 mx-2"
/>
<span
onClick={() => handleSearch(userId)}
className="text-[#FF669E] text-base font-medium"
>
搜索
</span>
</div>
{collaboratorData && (
<div
className="flex flex-row items-center rounded-2xl p-4 mb-4 border"
style={{ borderColor: isSelected ? "#FF669E" : "#2c2b2f" }}
>
<Avatar
src={collaboratorData?.avatar?.images[0]?.urls[0]}
fit="cover"
style={{ "--border-radius": "100px", "--size": "42px" }}
/>
<div className="flex flex-1 flex-col justify-around items-start ml-2">
<span className="text-base font-medium whitespace-nowrap">
{collaboratorData?.name}
</span>
<div className="flex flex-row items-center py-0.5 px-2 bg-[#FFFFFF1A] rounded-full">
<Image
src={
process.env.NEXT_PUBLIC_WEB_ASSETS_URL + "/icons/info/ID.png"
}
width={14}
height={14}
className="w-4 h-full mr-1"
/>
<span className="text-xs font-medium ml-0.5 whitespace-nowrap">
{collaboratorData?.user_id}
</span>
</div>
</div>
<div
className="px-4 py-2 text-sm font-medium rounded-full"
style={{
backgroundColor: isSelected ? "#FFFFFF1A" : "#FF669E",
}}
onClick={() => setIsSelected(!isSelected)}
>
{isSelected ? "取消" : "选择"}
</div>
</div>
)}
<div className="flex flex-row items-center mb-4">
<span className="text-base font-medium">分成比例</span>
<div className="w-1/3">
<Picker columns={[rates]} onConfirm={setRate} value={rate}>
{(items, { open }) => {
return (
<Space
align="center"
direction="horizontal"
justify="center"
onClick={open}
>
{items.every((item) => item === null)
? "未选择"
: items.map((item) => item?.label ?? "未选择").join("")}
<FontAwesomeIcon
icon={faSortDown}
style={{ maxWidth: "12px", marginBottom: 6 }}
size="lg"
/>
</Space>
);
}}
</Picker>
</div>
</div>
<p className="text-[#F53030] text-xs font-medium">
注意事项分成比例不得超过50%且确认后无法修改
</p>
<div className="grid grid-cols-2 gap-2 mt-2">
<div
className="bg-[#FF669E] text-center w-full py-2 text-md font-medium rounded-full"
onClick={handleSubmit}
>
确认
</div>
<div
className="bg-[#FFFFFF1A] text-center w-full py-2 text-md font-medium rounded-full"
onClick={() => setModalVisible(false)}
>
取消
</div>
</div>
</div>
);
};