diff --git a/app/my/wallet/page.js b/app/my/wallet/page.js
index e9f5eb9..3f79089 100644
--- a/app/my/wallet/page.js
+++ b/app/my/wallet/page.js
@@ -190,6 +190,28 @@ export default function Wallet() {
style={{ maxWidth: "12px" }}
/>
+
@@ -233,8 +257,47 @@ export default function Setting() {
+ {isAgencyHided && (
+
+
+ router.push("agencySetting?zid=" + streamerInfo.id)
+ }
+ className="flex justify-between"
+ >
+ 代运营设置
+
+
+
+
+ )}
>
)}
+ {(streamerInfo?.visitor_role === 1 ||
+ streamerInfo?.visitor_role === 2) && (
+
+
+ router.push(
+ `collaboratorSetting?zid=${streamerInfo.id}&visitor_role=${streamerInfo.visitor_role}`
+ )
+ }
+ className="flex justify-between"
+ >
+ 合伙人设置
+
+
+
+
+ )}
{streamerInfo?.refund_enable === 1 &&
streamerInfo?.admission_price > 0 &&
streamerInfo?.visitor_role === 0 && (
diff --git a/app/space/setting/agencySetting/page.jsx b/app/space/setting/agencySetting/page.jsx
new file mode 100644
index 0000000..6cad7cd
--- /dev/null
+++ b/app/space/setting/agencySetting/page.jsx
@@ -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:
,
+ bodyStyle: {
+ backgroundColor: "#17161A",
+ maxHeight: "none",
+ width: "90vw",
+ position: "fixed",
+ top: "200px",
+ left: "5vw",
+ "--text-color": "#fff",
+ color: "#fff",
+ },
+ });
+ };
+ return (
+
+ {isloading && (
+
+
+
+ )}
+ {/* 头部标题 */}
+
+
+ {
+ router.back();
+ }}
+ />
+
+
代运营设置
+
+ {/* 内容 */}
+
+
+ {data ? (
+
+ ) : (
+
+
+
+ )}
+
+
+
+
注意事项:
+
+ 1、一个空间仅可设置一个代运营,若您的代运营团队为多人,请设置代运营主账号后,让代运营主账号进入当前空间设置合伙人;
+
+
+ 2、设置完成后无法再次修改人员和分成比例,请确认后再提交,后续如需修改请联系人工客服;
+
+
+ 3、您获得的收益会按照您设置的分成比例直接转移至代运营及协作者账户,您将不会得到这部分的收益,如有疑问请咨询人工客服。
+
+
+
+
+ );
+}
+
+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 (
+
+
+ 搜索用户:
+ {
+ setUserId(value);
+ }}
+ value={userId}
+ className="flex-1 bg-[#FFFFFF1A] text-white rounded-2xl px-4 h-8 mx-2"
+ />
+ handleSearch(userId)}
+ className="text-[#FF669E] text-base font-medium"
+ >
+ 搜索
+
+
+ {agencyData && (
+
+
+
+
+ {agencyData?.name}
+
+
+
+
+ {agencyData?.user_id}
+
+
+
+
setIsSelected(!isSelected)}
+ >
+ {isSelected ? "取消" : "选择"}
+
+
+ )}
+
+
+ 手机号:
+
+ {mobilePhone?.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2")}
+
+
+
+
+
验证码:
+
setVeriCode(value)}
+ value={veriCode}
+ className="flex-1 bg-[#FFFFFF1A] rounded-2xl px-4 h-8 mx-2"
+ />
+
+ {isCounting ? `(${seconds})重新发送` : "获取验证码"}
+
+
+
+
分成比例:
+
+
+ {(items, { open }) => {
+ return (
+
+ {items.every((item) => item === null)
+ ? "未选择"
+ : items.map((item) => item?.label ?? "未选择").join("")}
+
+
+ );
+ }}
+
+
+
+
+ 注意事项:分成比例不得超过50%且确认后无法修改
+
+
+
+ 确认
+
+
setModalVisible(false)}
+ >
+ 取消
+
+
+
+ );
+};
diff --git a/app/space/setting/collaboratorSetting/page.jsx b/app/space/setting/collaboratorSetting/page.jsx
new file mode 100644
index 0000000..a6ac83b
--- /dev/null
+++ b/app/space/setting/collaboratorSetting/page.jsx
@@ -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: (
+
+ ),
+ 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 (
+
+
+
+
+
+
+
+ {item?.collaborator_account?.name}
+
+
+
+
+ {item?.collaborator_account?.user_id}
+
+
+
+
+
+
+
+ {item?.sharing_ratio
+ ? (item?.sharing_ratio * 100).toFixed()
+ : 0}
+ %
+
+
+
+
+ {!item?.isDeleteBtnInvisible && (
+
handleDelete(item.id)}
+ >
+ 移除
+
+ )}
+
+
+
+
+ );
+ }, []);
+ const selfData = data?.list?.filter(
+ (item) => item.collaborator_mid === selfMid
+ );
+ return (
+
+ {isloading && (
+
+
+
+ )}
+ {/* 头部标题 */}
+
+
+ {
+ router.back();
+ }}
+ />
+
+
合伙人设置
+
+ {/* 内容 */}
+
+ {searchParams.get("visitor_role") === 2 ? (
+
+
+
合伙人昵称:{selfData[0]?.collaborator_account?.name}
+
ID:{selfData[0]?.collaborator_account?.user_id}
+
+ 分成比例:
+ {selfData[0]?.sharing_ratio
+ ? (selfData[0]?.sharing_ratio * 100).toFixed()
+ : 0}
+ %
+
+
+
+ ) : (
+
+
+
总分成比例
+
+ {data?.zone_third_partner?.sharing_ratio
+ ? (data?.zone_third_partner?.sharing_ratio * 100).toFixed()
+ : 0}
+ %
+
+
修改比例请联系平台客服
+
+
+
+
+
+ {data?.list?.map((item, index) => (
+
+ ))}
+
+
+
+
+
+
+ )}
+
+
注意事项:
+
+ 1、总分成比例由当前空间主人设置,您的个人分成比例由代运营进行设置;
+
+
+ 2、您的个人收益计算公式为:空间收益x个人分成比例=个人收益,收益将以钻石形式发放至您的钱包;
+
+
3、若您对收益情况存在任何疑问,请联系人工客服。
+
+
+
+ );
+}
+
+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 (
+
+
+ 搜索用户:
+ setUserId(value)}
+ value={userId}
+ className="flex-1 bg-[#FFFFFF1A] text-white rounded-2xl px-4 h-8 mx-2"
+ />
+ handleSearch(userId)}
+ className="text-[#FF669E] text-base font-medium"
+ >
+ 搜索
+
+
+ {collaboratorData && (
+
+
+
+
+ {collaboratorData?.name}
+
+
+
+
+ {collaboratorData?.user_id}
+
+
+
+
setIsSelected(!isSelected)}
+ >
+ {isSelected ? "取消" : "选择"}
+
+
+ )}
+
+
分成比例:
+
+
+ {(items, { open }) => {
+ return (
+
+ {items.every((item) => item === null)
+ ? "未选择"
+ : items.map((item) => item?.label ?? "未选择").join("")}
+
+
+ );
+ }}
+
+
+
+
+ 注意事项:分成比例不得超过50%且确认后无法修改
+
+
+
+ 确认
+
+
setModalVisible(false)}
+ >
+ 取消
+
+
+
+ );
+};