528 lines
17 KiB
React
528 lines
17 KiB
React
|
"use client";
|
|||
|
|
|||
|
import React, { useState, useEffect } from "react";
|
|||
|
import {
|
|||
|
List,
|
|||
|
Toast,
|
|||
|
Image,
|
|||
|
Space,
|
|||
|
Picker,
|
|||
|
TextArea,
|
|||
|
Modal,
|
|||
|
Mask,
|
|||
|
SpinLoading,
|
|||
|
Button,
|
|||
|
} from "antd-mobile";
|
|||
|
import { DragDropContext, Draggable, Droppable } from "@hello-pangea/dnd";
|
|||
|
import { useRouter } from "next/navigation";
|
|||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||
|
import {
|
|||
|
faAngleLeft,
|
|||
|
faAdd,
|
|||
|
faEdit,
|
|||
|
faTrashCan,
|
|||
|
faSortDown,
|
|||
|
} from "@fortawesome/free-solid-svg-icons";
|
|||
|
import OwnInput from "@/components/OwnInput";
|
|||
|
import requireAPI from "@/utils/requireAPI";
|
|||
|
import { get } from "@/utils/storeInfo";
|
|||
|
|
|||
|
const reorder = (list, startIndex, endIndex) => {
|
|||
|
const result = Array.from(list);
|
|||
|
const [removed] = result.splice(startIndex, 1);
|
|||
|
result.splice(endIndex, 0, removed);
|
|||
|
|
|||
|
return result;
|
|||
|
};
|
|||
|
const defaultFormData = {
|
|||
|
nickname: "",
|
|||
|
url: "",
|
|||
|
selectedPlatform: [],
|
|||
|
};
|
|||
|
export default function EditPlace() {
|
|||
|
const router = useRouter();
|
|||
|
const [formData, setFormData] = useState(defaultFormData);
|
|||
|
const [allPlatforms, setAllPlatforms] = useState([]);
|
|||
|
const [platform, setPlatform] = useState([]);
|
|||
|
const [currentPlat, setcurrentPlat] = useState(null);
|
|||
|
//正在提交状态
|
|||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|||
|
const [platformEditable, setPlatformEditable] = useState(false);
|
|||
|
useEffect(() => {
|
|||
|
getAllPlatforms();
|
|||
|
}, []);
|
|||
|
const getAllPlatforms = async () => {
|
|||
|
try {
|
|||
|
const detailData = await requireAPI("POST", "/api/platform/list", {});
|
|||
|
if (detailData.ret === -1) {
|
|||
|
Toast.show({
|
|||
|
icon: "fail",
|
|||
|
content: detailData.msg,
|
|||
|
position: "top",
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
const detailDataValues = Object.entries(detailData.data);
|
|||
|
const temAllPlatforms = detailDataValues.map((item) => {
|
|||
|
return {
|
|||
|
label: item[1].name,
|
|||
|
value: {
|
|||
|
link_no: parseInt(item[0], 10),
|
|||
|
link_name: item[1].name,
|
|||
|
link_icon: item[1].icon,
|
|||
|
},
|
|||
|
};
|
|||
|
});
|
|||
|
|
|||
|
//获取主播当前所有平台
|
|||
|
const streamerPlatformData = await requireAPI(
|
|||
|
"POST",
|
|||
|
"/api/streamer_link/list_by_mid",
|
|||
|
{},
|
|||
|
true
|
|||
|
);
|
|||
|
if (streamerPlatformData.ret === -1) {
|
|||
|
Toast.show({
|
|||
|
icon: "error",
|
|||
|
content: streamerPlatformData.msg,
|
|||
|
position: "top",
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
const streamerPlatList = streamerPlatformData.data.list;
|
|||
|
setAllPlatforms(temAllPlatforms);
|
|||
|
const platformsWithIcon = streamerPlatList.map((item) => {
|
|||
|
return {
|
|||
|
...item,
|
|||
|
link_icon: detailData.data[item.link_no].icon,
|
|||
|
};
|
|||
|
});
|
|||
|
setPlatform(platformsWithIcon);
|
|||
|
} catch (error) {
|
|||
|
console.error(error);
|
|||
|
}
|
|||
|
};
|
|||
|
//点击删除按钮
|
|||
|
const handleDelete = (index) => {
|
|||
|
const updatedPlatform = [...platform];
|
|||
|
updatedPlatform.splice(index, 1);
|
|||
|
setPlatform(updatedPlatform);
|
|||
|
};
|
|||
|
const handSubmit = async () => {
|
|||
|
const account = get("account");
|
|||
|
const newPlatforms = [...platform];
|
|||
|
newPlatforms.forEach((item, index) => {
|
|||
|
item.order = index + 1;
|
|||
|
item.mid = account.mid;
|
|||
|
});
|
|||
|
try {
|
|||
|
//获取主播当前所有平台
|
|||
|
const streamerPlatformData = await requireAPI(
|
|||
|
"POST",
|
|||
|
"/api/streamer_link/list_by_mid",
|
|||
|
{},
|
|||
|
true
|
|||
|
);
|
|||
|
if (streamerPlatformData.ret === -1) {
|
|||
|
Toast.show({
|
|||
|
icon: "fail",
|
|||
|
content: streamerPlatformData.msg,
|
|||
|
position: "top",
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
//删除全部现有平台
|
|||
|
const ids = streamerPlatformData.data.list.map((item) => item.id);
|
|||
|
if (ids.length !== 0) {
|
|||
|
const deleteData = await requireAPI(
|
|||
|
"POST",
|
|||
|
"/api/streamer_link/delete_batch",
|
|||
|
{
|
|||
|
body: {
|
|||
|
ids: ids,
|
|||
|
},
|
|||
|
}
|
|||
|
);
|
|||
|
if (deleteData.ret === -1) {
|
|||
|
Toast.show({
|
|||
|
icon: "fail",
|
|||
|
content: deleteData.msg,
|
|||
|
position: "top",
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
//批量创建新的平台
|
|||
|
if (newPlatforms.length === 0) {
|
|||
|
Toast.show({
|
|||
|
icon: "success",
|
|||
|
content: "更改成功",
|
|||
|
position: "top",
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
const data = await requireAPI("POST", "/api/streamer_link/create_batch", {
|
|||
|
body: {
|
|||
|
streamer_links: newPlatforms,
|
|||
|
},
|
|||
|
});
|
|||
|
if (data.ret === -1) {
|
|||
|
Toast.show({
|
|||
|
icon: "fail",
|
|||
|
content: data.msg,
|
|||
|
position: "top",
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
Toast.show({
|
|||
|
icon: "success",
|
|||
|
content: "更改成功",
|
|||
|
position: "top",
|
|||
|
});
|
|||
|
router.back();
|
|||
|
} catch (error) {
|
|||
|
console.error(error);
|
|||
|
} finally {
|
|||
|
setPlatformEditable(false);
|
|||
|
setFormData(defaultFormData);
|
|||
|
setIsSubmitting(false);
|
|||
|
}
|
|||
|
};
|
|||
|
const handleEditPlatform = (values) => {
|
|||
|
if (!values.nickname || !values.selectedPlatform.length || !values.url) {
|
|||
|
Toast.show({
|
|||
|
icon: "fail",
|
|||
|
content: "请完整填写信息",
|
|||
|
position: "top",
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
if (
|
|||
|
values.url.indexOf("http://") == -1 &&
|
|||
|
values.url.indexOf("https://") == -1
|
|||
|
) {
|
|||
|
Toast.show({
|
|||
|
icon: "fail",
|
|||
|
content: "链接必须以https://或http://开头",
|
|||
|
position: "top",
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
let newPlatforms = [];
|
|||
|
if (!formData.id) {
|
|||
|
const currentPlatFormEle = allPlatforms.filter(
|
|||
|
(it) => it.label == values.selectedPlatform[0]
|
|||
|
)[0];
|
|||
|
const newPlatform = {
|
|||
|
link_name: values.selectedPlatform[0],
|
|||
|
link_icon: currentPlatFormEle.value.link_icon,
|
|||
|
link_no: currentPlatFormEle.value.link_no,
|
|||
|
nickname: values.nickname,
|
|||
|
url: values.url,
|
|||
|
};
|
|||
|
newPlatforms = platform.concat(newPlatform);
|
|||
|
// setIsSubmitting(true);
|
|||
|
} else {
|
|||
|
const index = platform.findIndex(
|
|||
|
(it) => it.link_name == formData.selectedPlatform
|
|||
|
);
|
|||
|
newPlatforms = [...platform];
|
|||
|
newPlatforms[index].link_name = formData.selectedPlatform;
|
|||
|
newPlatforms[index] = {
|
|||
|
...newPlatforms[index],
|
|||
|
link_name: formData.selectedPlatform,
|
|||
|
nickname: formData.nickname,
|
|||
|
url: formData.url,
|
|||
|
};
|
|||
|
}
|
|||
|
setFormData(defaultFormData);
|
|||
|
setPlatform(newPlatforms);
|
|||
|
setPlatformEditable(false);
|
|||
|
};
|
|||
|
|
|||
|
const onDragEnd = (result) => {
|
|||
|
if (!result.destination) return;
|
|||
|
const newList = reorder(
|
|||
|
platform,
|
|||
|
result.source.index,
|
|||
|
result.destination.index
|
|||
|
);
|
|||
|
setPlatform([...newList]);
|
|||
|
};
|
|||
|
return (
|
|||
|
<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="pt-16 p-4">
|
|||
|
<div
|
|||
|
className="mt-2 text-sm flex justify-center items-center font-medium border border-dashed border-white rounded-md px-4 py-3"
|
|||
|
onClick={() => setPlatformEditable(true)}
|
|||
|
>
|
|||
|
<FontAwesomeIcon
|
|||
|
icon={faAdd}
|
|||
|
style={{ maxWidth: "12px" }}
|
|||
|
size="xl"
|
|||
|
/>
|
|||
|
<span className="ml-2">添加</span>
|
|||
|
</div>
|
|||
|
<List
|
|||
|
className="mt-4"
|
|||
|
style={{
|
|||
|
"--padding-left": 0,
|
|||
|
"--padding-right": 0,
|
|||
|
"--border-inner": "none",
|
|||
|
}}
|
|||
|
>
|
|||
|
<DragDropContext onDragEnd={onDragEnd}>
|
|||
|
<Droppable droppableId="droppable11">
|
|||
|
{(droppableProvided) => (
|
|||
|
<div
|
|||
|
{...droppableProvided.droppableProps}
|
|||
|
ref={droppableProvided.innerRef}
|
|||
|
>
|
|||
|
{platform.map((item, index) => (
|
|||
|
<Draggable
|
|||
|
key={item.id + index}
|
|||
|
draggableId={(item.id || index).toString()}
|
|||
|
index={index}
|
|||
|
>
|
|||
|
{(provided, snapshot) => (
|
|||
|
<div
|
|||
|
key={item.name}
|
|||
|
ref={provided.innerRef}
|
|||
|
{...provided.draggableProps}
|
|||
|
{...provided.dragHandleProps}
|
|||
|
style={{
|
|||
|
...provided.draggableProps.style,
|
|||
|
opacity: snapshot.isDragging ? 0.8 : 1,
|
|||
|
}}
|
|||
|
>
|
|||
|
<div
|
|||
|
key={index}
|
|||
|
className="w-full grid grid-cols-[auto,20px] gap-4 justify-between bg-[#13121F] rounded-lg p-4 my-2"
|
|||
|
>
|
|||
|
<div className="text-base font-medium">
|
|||
|
<div className="flex items-center">
|
|||
|
<span>平台:</span>
|
|||
|
<div className="flex items-center">
|
|||
|
<Image
|
|||
|
src={item?.link_icon?.images[0]?.urls[0]}
|
|||
|
width={18}
|
|||
|
/>
|
|||
|
<span className="ml-2">{item.link_name}</span>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<p className="flex items-center">
|
|||
|
<span>昵称:</span>
|
|||
|
<span>{item.nickname}</span>
|
|||
|
</p>
|
|||
|
<p className="flex">
|
|||
|
<span className="whitespace-nowrap">
|
|||
|
链接:
|
|||
|
</span>
|
|||
|
<span
|
|||
|
className="whitespace-normal inline-block"
|
|||
|
style={{ overflowWrap: "anywhere" }}
|
|||
|
>
|
|||
|
{item.url}
|
|||
|
</span>
|
|||
|
</p>
|
|||
|
</div>
|
|||
|
<div className="grid grid-rows-[32px,32px] gap-2 items-center">
|
|||
|
<div onClick={() => handleDelete(index)}>
|
|||
|
<FontAwesomeIcon
|
|||
|
icon={faTrashCan}
|
|||
|
style={{ maxWidth: "18px" }}
|
|||
|
size="xl"
|
|||
|
/>
|
|||
|
</div>
|
|||
|
<div
|
|||
|
onClick={() => {
|
|||
|
setPlatformEditable(true);
|
|||
|
setFormData({
|
|||
|
nickname: item.nickname,
|
|||
|
url: item.url,
|
|||
|
selectedPlatform: item.link_name,
|
|||
|
id: item.id,
|
|||
|
});
|
|||
|
}}
|
|||
|
>
|
|||
|
<FontAwesomeIcon
|
|||
|
icon={faEdit}
|
|||
|
style={{ maxWidth: "18px" }}
|
|||
|
size="xl"
|
|||
|
/>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
)}
|
|||
|
</Draggable>
|
|||
|
))}
|
|||
|
{droppableProvided.placeholder}
|
|||
|
</div>
|
|||
|
)}
|
|||
|
</Droppable>
|
|||
|
</DragDropContext>
|
|||
|
</List>
|
|||
|
<div className="fixed bottom-8 flex justify-center w-full">
|
|||
|
<Button
|
|||
|
size="middle"
|
|||
|
shape="rounded"
|
|||
|
style={{
|
|||
|
"--background-color": "#FF669E",
|
|||
|
paddingLeft: "32px",
|
|||
|
paddingRight: "32px",
|
|||
|
}}
|
|||
|
disabled={isSubmitting}
|
|||
|
onClick={() => handSubmit()}
|
|||
|
>
|
|||
|
{isSubmitting ? "正在提交..." : "确认修改"}
|
|||
|
</Button>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<Modal
|
|||
|
visible={platformEditable}
|
|||
|
content={
|
|||
|
<div className="w-full px-4">
|
|||
|
<p className="text-lg font-medium text-center mb-2">
|
|||
|
编辑/添加平台
|
|||
|
</p>
|
|||
|
<div className="flex items-center my-4">
|
|||
|
<span className="text-base font-medium mr-1">平台:</span>
|
|||
|
{!formData.id ? (
|
|||
|
<div className="w-1/2">
|
|||
|
<Picker
|
|||
|
columns={[
|
|||
|
[
|
|||
|
...allPlatforms
|
|||
|
.map((it) => {
|
|||
|
return {
|
|||
|
label: it.label,
|
|||
|
value: it.label,
|
|||
|
};
|
|||
|
})
|
|||
|
.filter((it) => {
|
|||
|
return !platform.some(
|
|||
|
(el) => el.link_name == it.label
|
|||
|
);
|
|||
|
}),
|
|||
|
],
|
|||
|
]}
|
|||
|
onSelect={(value) => {
|
|||
|
setFormData((old) => ({
|
|||
|
...old,
|
|||
|
selectedPlatform: value,
|
|||
|
}));
|
|||
|
}}
|
|||
|
value={formData.selectedPlatform}
|
|||
|
>
|
|||
|
{(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>
|
|||
|
) : (
|
|||
|
<span className="text-base font-medium mr-1">
|
|||
|
{formData?.selectedPlatform}
|
|||
|
</span>
|
|||
|
)}
|
|||
|
</div>
|
|||
|
<div className="flex items-center my-4">
|
|||
|
<span className="text-base font-medium mr-1">昵称:</span>
|
|||
|
<OwnInput
|
|||
|
placeholder="请输入昵称"
|
|||
|
onChange={(value) => {
|
|||
|
setFormData((old) => ({ ...old, nickname: value }));
|
|||
|
}}
|
|||
|
value={formData.nickname}
|
|||
|
className="border border-[#2c2b2f] font-medium rounded-lg h-10 px-2"
|
|||
|
/>
|
|||
|
</div>
|
|||
|
<div className="flex my-4">
|
|||
|
<span className="text-base font-medium mr-1 whitespace-nowrap">
|
|||
|
链接:
|
|||
|
</span>
|
|||
|
<TextArea
|
|||
|
placeholder="请输入链接"
|
|||
|
onChange={(value) => {
|
|||
|
setFormData((old) => ({ ...old, url: value }));
|
|||
|
}}
|
|||
|
value={formData.url}
|
|||
|
style={{
|
|||
|
"--placeholder-color": "#FFFFFF80",
|
|||
|
"--font-size": "16px",
|
|||
|
}}
|
|||
|
className="border border-[#2c2b2f] font-medium rounded-lg h-24 p-2 "
|
|||
|
/>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
}
|
|||
|
actions={[
|
|||
|
{
|
|||
|
key: "confirm",
|
|||
|
text: "确认",
|
|||
|
className: "rounded-full",
|
|||
|
style: {
|
|||
|
background: "#FF669E",
|
|||
|
border: "none",
|
|||
|
borderRadius: "100px",
|
|||
|
},
|
|||
|
primary: true,
|
|||
|
},
|
|||
|
{
|
|||
|
key: "cancle",
|
|||
|
text: "取消",
|
|||
|
style: { color: "#ffffff80" },
|
|||
|
},
|
|||
|
]}
|
|||
|
onAction={(action, index) => {
|
|||
|
if (action.key == "confirm") {
|
|||
|
handleEditPlatform(formData);
|
|||
|
} else {
|
|||
|
setPlatformEditable(false);
|
|||
|
setFormData(defaultFormData);
|
|||
|
}
|
|||
|
}}
|
|||
|
></Modal>
|
|||
|
<Mask visible={isSubmitting}>
|
|||
|
<div className="w-full h-screen flex justify-center items-center">
|
|||
|
<SpinLoading color="default" />
|
|||
|
</div>
|
|||
|
</Mask>
|
|||
|
</div>
|
|||
|
);
|
|||
|
}
|