完善修改网红资料页面

This commit is contained in:
yezian 2024-01-09 23:47:29 +08:00
parent 99c6f600a8
commit 71c6e77da1
3 changed files with 361 additions and 370 deletions

View File

@ -52,7 +52,10 @@ export default function Op() {
getItem("图片机审回查", "imageMachineReview"),
getItem("文本机审回查", "textMachineReview"),
]),
// getItem("", "streamerManagement", <ShopOutlined />),
getItem("网红管理", "streamerManagement", <ShopOutlined />, [
getItem("网红资料", "streamerInformation"),
// getItem("", "streamerPlatform"),
]),
// getItem("", "userManagement", <UsergroupAddOutlined />),
// getItem("", "orderManagement", <FileSearchOutlined />, [
// getItem("", "ordersQuerry"),

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useState } from "react";
import {
Form,
Input,
@ -9,24 +9,21 @@ import {
InputNumber,
Image,
} from "antd";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import Modal from "../../components/Modal";
import VideoUploader from "../../components/VideoUploader";
import ImageUploader from "../../components/ImageUploader";
import baseRequest from "../../utils/baseRequest";
//tab
const GoodsContent = () => {
const StreamerInformationContent = () => {
const { TextArea } = Input;
//
const [showColumns, setShowColumns] = useState([
"baseInfo",
"displayInfo",
"shareRatio",
"platform",
"displayPoster",
"displayVideo",
"displayGallery",
"remark",
]);
//
const dynamicColumns = showColumns.map((item) => {
@ -40,14 +37,11 @@ const GoodsContent = () => {
<div>
<Image src={data.avatar} width={50} />
<p>
mid<span className="text-red-400">{data.mid}</span>
ID<span className="text-red-400">{data.id}</span>
</p>
<p>
昵称<span className="text-red-400">{data.name}</span>
</p>
<p>
联系方式<span className="text-red-400">{data.contact}</span>
</p>
<p>
入驻时间<span className="text-red-400">{data.joinTime}</span>
</p>
@ -61,15 +55,40 @@ const GoodsContent = () => {
key: "displayInfo",
render: (data) => (
<div>
<p>
性别
<span className="text-red-400">
{data.gender === 1 ? "女" : "男"}
</span>
</p>
<p>
全网粉丝<span className="text-red-400">{data.fans}</span>
</p>
<p>
微信<span className="text-red-400">{data.wechat}</span>
微信添加方式
<span className="text-red-400">
{data.wechat_lock_type === 1 ? "主动添加" : "直接展示"}
</span>
</p>
<p>
微信
<span className="text-red-400">
{data.wechat ? data.wechat : "空"}
</span>
</p>
<p>
微信价格
<span className="text-red-400">¥{data.wechat_price / 10}</span>
</p>
<p>
个性签名<span className="text-red-400">{data.signature}</span>
</p>
<p>
私信自动回复
<span className="text-red-400">
{data.auto_response_message}
</span>
</p>
<p>
年龄<span className="text-red-400">{data.age}</span>
</p>
@ -88,45 +107,21 @@ const GoodsContent = () => {
</div>
),
};
case "shareRatio":
return {
title: "分成比例",
dataIndex: "shareRatio",
key: "shareRatio",
render: (data) => <p>{data}%</p>,
};
case "platform":
return {
title: "平台",
dataIndex: "platform",
key: "platform",
render: (data) => (
<div>
<ol>
{data.map((item) => (
<li key={item.name}>
<a href={item.url} target="_blank" rel="noreferrer">
{item.name}{item.id}
</a>
</li>
))}
</ol>
</div>
),
};
case "displayPoster":
return {
title: "封面图片",
dataIndex: "displayPoster",
key: "displayPoster",
render: (data) => <Image src={data} width={100} />,
render: (data) => <Image src={data[0].urls[0]} width={100} />,
};
case "displayVideo":
return {
title: "封面视频",
dataIndex: "displayVideo",
key: "displayVideo",
render: (data) => <video src={data} width={150} controls />,
render: (data) => (
<video src={data[0].urls[0]} width={150} controls />
),
};
case "displayGallery":
return {
@ -137,8 +132,8 @@ const GoodsContent = () => {
<div>
{data.map((item) => (
<Image
key={item}
src={item}
key={item.urls[0]}
src={item.urls[0]}
width={100}
style={{ marginBottom: 10 }}
/>
@ -146,12 +141,6 @@ const GoodsContent = () => {
</div>
),
};
case "remark":
return {
title: "备注",
dataIndex: "remark",
key: "remark",
};
default:
return {};
}
@ -168,120 +157,6 @@ const GoodsContent = () => {
</div>
),
});
//
const data = [
{
key: "1",
baseInfo: {
mid: "654321",
name: "马牛逼",
avatar: "https://s2.loli.net/2023/07/25/fjouqVLAlTn2s58.png",
contact: "wx:woshimaniubi",
joinTime: "2023-09-22 20:00",
},
displayInfo: {
fans: 1000,
wechat: "maniubi",
signature: "马牛逼的个性签名",
age: "21",
height: "175",
weight: "75",
constellation: "天蝎座",
location: "四川",
},
shareRatio: 20,
platform: [
{
index: 1,
name: "抖音",
id: "马牛逼",
url: "https://www.douyin.com/discover",
},
{
index: 2,
name: "哔哩哔哩",
id: "马牛逼",
url: "https://www.bilibili.com",
},
],
displayPoster: "https://s2.loli.net/2023/07/25/fjouqVLAlTn2s58.png",
displayVideo: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",
displayGallery: [
"https://s2.loli.net/2023/07/25/fjouqVLAlTn2s58.png",
"https://s2.loli.net/2023/07/25/1daCqmZGQNUzoJ8.png",
],
remark: "马牛逼的备注",
},
{
key: "2",
baseInfo: {
mid: "10086",
name: "迪迦",
avatar: "https://s2.loli.net/2023/07/25/1daCqmZGQNUzoJ8.png",
contact: "wx:woshidijia",
joinTime: "2023-09-21 20:00",
},
displayInfo: {
fans: 2000,
wechat: "dijia",
signature: "迪迦的个性签名",
age: "88",
height: "170",
weight: "70",
constellation: "处女座",
location: "上海",
},
shareRatio: 20,
platform: [
{
name: "抖音",
id: "迪迦",
url: "https://www.douyin.com/discover",
},
{
name: "哔哩哔哩",
id: "迪迦",
url: "https://www.bilibili.com",
},
],
displayPoster: "https://s2.loli.net/2023/07/25/1daCqmZGQNUzoJ8.png",
displayVideo: "https://media.w3.org/2010/05/sintel/trailer.mp4",
displayGallery: [
"https://s2.loli.net/2023/07/25/1daCqmZGQNUzoJ8.png",
"https://s2.loli.net/2023/07/25/fjouqVLAlTn2s58.png",
],
remark: "迪迦的备注",
},
];
//
// const [pageData, setPageData] = useState([]);
// useEffect(() => {
// const getData = async () => {
// try {
// const base = baseRequest();
// const response = await fetch("/op/streamer/list", {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify({
// mid: 12,
// ...base,
// }),
// });
// const temData = await response.json();
// console.log(temData);
// if (temData.ret === -1) {
// alert(temData.msg);
// return;
// }
// } catch (error) {
// console.error(error);
// }
// };
// getData();
// }, []);
//modalselect
const constellations = [
@ -346,14 +221,6 @@ const GoodsContent = () => {
label: "个人展示信息",
value: "displayInfo",
},
{
label: "分成比例",
value: "shareRatio",
},
{
label: "平台",
value: "platform",
},
{
label: "封面图片",
value: "displayPoster",
@ -366,24 +233,62 @@ const GoodsContent = () => {
label: "相册",
value: "displayGallery",
},
{
label: "备注",
value: "remark",
},
];
//
const [showData, setShowData] = useState(data);
const [showData, setShowData] = useState([]);
//
const search = (value) => {
value.name || value.mid
? setShowData(
data.filter(
(item) =>
item.baseInfo.name === value.name ||
item.baseInfo.mid === value.mid
)
)
: setShowData(data);
const search = async (value) => {
try {
const base = baseRequest();
const detailResponse = await fetch(`/op/streamer/list_ext_by_user_id`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user_id: parseInt(value.id, 10),
...base,
}),
});
const detailData = await detailResponse.json();
if (detailData.ret === -1) {
alert(detailData.msg);
return;
}
setShowData([
{
key: detailData.data.streamer_ext.mid,
baseInfo: {
id: detailData.data.streamer_ext.user_id,
name: detailData.data.streamer_ext.name,
avatar: detailData.data.streamer_ext.avatar.images[0].urls[0],
joinTime: new Date(
detailData.data.streamer_ext.ct * 1000
).toLocaleString(),
},
displayInfo: {
gender: detailData.data.streamer_ext.gender,
fans: detailData.data.streamer_ext.fans,
wechat_lock_type: detailData.data.streamer_ext.wechat_lock_type,
wechat: detailData.data.streamer_ext.wechat_contact,
wechat_price: detailData.data.streamer_ext.wechat_coin_price,
signature: detailData.data.streamer_ext.bio,
age: detailData.data.streamer_ext.age,
height: detailData.data.streamer_ext.height,
weight: detailData.data.streamer_ext.weight,
constellation: detailData.data.streamer_ext.constellation,
location: detailData.data.streamer_ext.city,
auto_response_message:
detailData.data.streamer_ext.auto_response_message,
},
displayPoster: detailData.data.streamer_ext.cover.images,
displayVideo: detailData.data.streamer_ext.shorts.videos,
displayGallery: detailData.data.streamer_ext.album.images,
},
]);
} catch (error) {
console.error(error);
}
};
//
const onFinishFailed = (errorInfo) => {
@ -397,18 +302,89 @@ const GoodsContent = () => {
};
//modal
const [defaultValues, setDefaultValues] = useState({});
const [defaultMedia, setDefaultMedia] = useState({});
//
const handleModal = (record) => {
setDefaultValues(record);
const streamerPlatforms = record.platform.map((item) => item.name);
setDefaultMedia({
displayPoster: record.displayPoster,
displayVideo: record.displayVideo,
displayGallery: record.displayGallery,
});
setIsModalOpen(true);
};
//
const onModalFormFinish = (value) => {
//
const onModalFormFinish = async (value) => {
//...
console.log("Success:", value);
const oldPosterId = defaultMedia.displayPoster.map((item) => item.id);
const oldVideoId = defaultMedia.displayVideo.map((item) => item.id);
const oldGalleryId = defaultMedia.displayGallery.map((item) => item.id);
const newPosterId = [...oldPosterId, ...displayPosterId];
const newVideoId = [...oldVideoId, ...displayVideoId];
const newGalleryId = [...oldGalleryId, ...displayGalleryId];
try {
const base = baseRequest();
const detailResponse = await fetch(`/op/streamer/update`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mid: defaultValues.key,
gender: parseInt(value.gender, 10),
wechat_contact: value.wechat,
bio: value.signature,
cover: { image_ids: newPosterId },
shorts: { video_ids: newVideoId },
album: { image_ids: newGalleryId },
age: parseInt(value.age, 10),
height: parseInt(value.height, 10),
weight: parseInt(value.weight, 10),
constellation: value.constellation,
city: value.location,
wechat_lock_type: parseInt(value.wechat_lock_type, 10),
fans: parseInt(value.fans, 10),
wechat_coin_price: parseInt(value.wechat_price, 10) * 10,
auto_response_message: value.auto_response_message,
...base,
}),
});
console.log(value);
console.log({
mid: defaultValues.key,
gender: parseInt(value.gender, 10),
wechat_contact: value.wechat,
bio: value.signature,
cover: { image_ids: newPosterId },
shorts: { video_ids: newVideoId },
album: { image_ids: newGalleryId },
age: parseInt(value.age, 10),
height: parseInt(value.height, 10),
weight: parseInt(value.weight, 10),
constellation: value.constellation,
city: value.location,
wechat_lock_type: parseInt(value.wechat_lock_type, 10),
fans: parseInt(value.fans, 10),
wechat_coin_price: parseInt(value.wechat_price, 10) * 10,
auto_response_message: value.auto_response_message,
...base,
});
const detailData = await detailResponse.json();
console.log(detailData);
if (detailData.ret === -1) {
alert(detailData.msg);
return;
}
} catch (error) {
console.error(error);
}
//
setShowData([]);
setDefaultValues({});
setDefaultMedia({});
setDisplayVideoId([]);
setDisplayPosterId([]);
setDisplayGalleryId([]);
setIsModalOpen(false);
};
//
@ -417,7 +393,36 @@ const GoodsContent = () => {
};
//id
const [ids, setIds] = useState([]);
const [displayVideoId, setDisplayVideoId] = useState([]);
const [displayPosterId, setDisplayPosterId] = useState([]);
const [displayGalleryId, setDisplayGalleryId] = useState([]);
//
const handleDeleteMedia = (type, id) => {
if (type === "displayPoster") {
setDefaultMedia({
...defaultMedia,
displayPoster: [],
});
return;
}
if (type === "displayVideo") {
setDefaultMedia({
...defaultMedia,
displayVideo: [],
});
return;
}
if (type === "displayGallery") {
setDefaultMedia({
...defaultMedia,
displayGallery: defaultMedia.displayGallery.filter(
(item) => item.id !== id
),
});
return;
}
};
return (
<div style={{ marginLeft: 20, marginRight: 20 }}>
@ -431,10 +436,7 @@ const GoodsContent = () => {
</div>
<Form name="search" onFinish={search} onFinishFailed={onFinishFailed}>
<Space style={{ marginBottom: 20 }}>
<Form.Item label="mid" name="mid" style={{ margin: 0 }}>
<Input />
</Form.Item>
<Form.Item label="昵称" name="name" style={{ margin: 0 }}>
<Form.Item label="ID" name="id" style={{ margin: 0 }}>
<Input />
</Form.Item>
<Button type="primary" htmlType="submit">
@ -465,17 +467,17 @@ const GoodsContent = () => {
style={{ height: (window.innerHeight * 2) / 3 }}
>
<div className="flex flex-row">
<Image width={80} src={defaultValues.baseInfo.avatar} />
<Image
width={80}
height={80}
className="rounded-full"
src={defaultValues.baseInfo.avatar}
/>
<div className="flex flex-col justify-between ml-2">
<p className="font-bold">
mid{defaultValues.baseInfo.mid}
</p>
<p className="font-bold">ID{defaultValues.baseInfo.id}</p>
<p className="font-bold">
昵称{defaultValues.baseInfo.name}
</p>
<p className="font-bold">
联系方式{defaultValues.baseInfo.contact}
</p>
<p className="font-bold">
入驻时间{defaultValues.baseInfo.joinTime}
</p>
@ -501,15 +503,73 @@ const GoodsContent = () => {
</Form.Item>
<Form.Item
className="basis-1/2 px-2"
name="wechat"
label="微信号"
initialValue={defaultValues.displayInfo.wechat}
name="gender"
label="性别"
initialValue={defaultValues.displayInfo.gender}
rules={[
{
required: true,
message: "请输入微信号",
message: "填写性别",
},
]}
>
<select
style={{
height: 32,
padding: "4px 11px",
border: "1px solid #d9d9d9",
borderRadius: 4,
outline: "none",
}}
>
<option value={1}></option>
<option value={0}></option>
</select>
</Form.Item>
<Form.Item
className="basis-1/2 px-2"
name="wechat_lock_type"
label="微信添加方式"
initialValue={defaultValues.displayInfo.wechat_lock_type}
rules={[
{
required: true,
message: "填写添加微信方式",
},
]}
>
<select
style={{
height: 32,
padding: "4px 11px",
border: "1px solid #d9d9d9",
borderRadius: 4,
outline: "none",
}}
>
<option value={1}>主动添加</option>
<option value={0}>直接展示</option>
</select>
</Form.Item>
<Form.Item
className="basis-1/2 px-2"
name="wechat"
label="微信号"
initialValue={defaultValues.displayInfo.wechat}
>
<Input />
</Form.Item>
<Form.Item
className="basis-1/2 px-2"
name="wechat_price"
label="微信价格"
rules={[
{
required: true,
message: "请输入微信价格",
},
]}
initialValue={defaultValues.displayInfo.wechat_price / 10}
>
<Input />
</Form.Item>
@ -527,6 +587,22 @@ const GoodsContent = () => {
>
<Input />
</Form.Item>
<Form.Item
className="basis-1/2 px-2"
name="auto_response_message"
label="私信自动回复"
initialValue={
defaultValues.displayInfo.auto_response_message
}
rules={[
{
required: true,
message: "请输入私信自动回复",
},
]}
>
<Input />
</Form.Item>
<Form.Item
className="basis-1/2 px-2"
name="age"
@ -625,169 +701,81 @@ const GoodsContent = () => {
))}
</select>
</Form.Item>
<Form.Item
className="basis-1/2 px-2"
name="shareRatio"
label="分成比例(%"
initialValue={defaultValues.shareRatio}
rules={[
{
required: true,
message: "请填写分成比例",
},
]}
>
<InputNumber min={0} max={100} />
</Form.Item>
<Form.Item
className="basis-1/2 px-2"
name="remark"
label="备注"
initialValue={defaultValues.remark}
>
<Input />
</Form.Item>
</div>
<div>
<Form.Item
className="px-2"
name="displayPoster"
label="封面图片链接"
initialValue={defaultValues.displayPoster}
rules={[
{
required: true,
message: "请输入封面图片链接",
},
]}
>
<Input />
</Form.Item>
<VideoUploader setIds={setIds} />
<Form.Item
className="px-2"
name="displayVideo"
label="封面视频链接"
initialValue={defaultValues.displayVideo}
rules={[
{
required: true,
message: "请输入封面视频链接",
},
]}
>
<Input />
</Form.Item>
<Form.Item
className="px-2"
name="displayGallery"
label="相册图片链接(用空格分割)"
initialValue={defaultValues.displayGallery.join(" ")}
rules={[
{
required: true,
message: "请输入相册图片链接(用空格分割)",
},
]}
>
<TextArea rows={4} />
</Form.Item>
<Form.List
name="platform111"
initialValue={defaultValues.platform}
>
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name }) => (
<Space
key={key}
style={{
display: "flex",
marginBottom: 8,
}}
align="baseline"
>
<Form.Item
label="顺序"
name={[name, "index"]}
rules={[
{
required: true,
message: "请输入顺序",
},
]}
>
<InputNumber min={0} />
</Form.Item>
<Form.Item
label="平台"
name={[name, "name"]}
rules={[
{
required: true,
message: "请选择平台名称",
},
]}
>
<select
style={{
height: 32,
padding: "4px 11px",
border: "1px solid #d9d9d9",
borderRadius: 4,
outline: "none",
}}
>
{platformList.map((item) => (
<option key={item} value={item}>
{item}
</option>
))}
</select>
</Form.Item>
<Form.Item
label="昵称"
name={[name, "id"]}
rules={[
{
required: true,
message: "请输入昵称",
},
]}
>
<Input />
</Form.Item>
<Form.Item
label="链接"
name={[name, "url"]}
rules={[
{
required: true,
message: "请输入链接",
},
]}
>
<Input />
</Form.Item>
<MinusCircleOutlined
className="text-xl text-red-400"
onClick={() => remove(name)}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
icon={<PlusOutlined />}
onClick={() => add()}
block
>
添加平台
</Button>
</Form.Item>
</>
<div className="flex flexp-row flex-wrap gap-2 mb-2">
<p>
<span className="text-red-400 text-base">*</span>
封面图片
</p>
{defaultMedia.displayPoster.length !== 0 && (
<div className="relative">
<Image
src={defaultMedia.displayPoster[0].urls[0]}
width={100}
/>
<Button
className="absolute top-0 left-0 w-full"
danger
type="primary"
onClick={() => handleDeleteMedia("displayPoster")}
>
删除
</Button>
</div>
)}
</Form.List>
<ImageUploader setIds={setDisplayPosterId} />
</div>
<div className="flex flexp-row flex-wrap gap-2 mb-2">
<p>
<span className="text-red-400 text-base">*</span>
封面视频
</p>
{defaultMedia.displayVideo.length !== 0 && (
<div className="relative">
<video
src={defaultMedia.displayVideo[0].urls[0]}
width={150}
controls
/>
<Button
className="absolute top-0 left-0 w-full"
danger
type="primary"
onClick={() => handleDeleteMedia("displayVideo")}
>
删除
</Button>
</div>
)}
<VideoUploader setIds={setDisplayVideoId} />
</div>
<div className="flex flexp-row flex-wrap gap-2">
<p>
<span className="text-red-400 text-base">*</span>
相册图片
</p>
{defaultMedia.displayGallery.length !== 0 && (
<div>
{defaultMedia.displayGallery.map((item) => (
<div key={item.urls[0]} className="relative">
<Image src={item.urls[0]} width={100} />
<Button
className="absolute top-0 left-0 w-full"
danger
type="primary"
onClick={() =>
handleDeleteMedia("displayGallery", item.id)
}
>
删除
</Button>
</div>
))}
</div>
)}
<ImageUploader setIds={setDisplayGalleryId} />
</div>
</div>
</div>
}
@ -798,6 +786,6 @@ const GoodsContent = () => {
);
};
export default function StreamerManagement() {
return <GoodsContent />;
export default function StreamerInformation() {
return <StreamerInformationContent />;
}

View File

@ -2,7 +2,7 @@ import Banner from "../pages/Banner";
import Login from "../pages/Login";
import Op from "../pages/Op";
import Feed from "../pages/Feed";
import StreamerManagement from "../pages/StreamerManagement";
import StreamerInformation from "../pages/StreamerInformation";
import StreamerJoin from "../pages/StreamerJoin";
import Feedback from "../pages/Feedback";
import Contact from "../pages/Contact";
@ -34,8 +34,8 @@ const routes = [
element: <Feed />,
},
{
path: "streamerManagement/*",
element: <StreamerManagement />,
path: "streamerInformation/*",
element: <StreamerInformation />,
},
{
path: "streamerJoin/*",