tiefen_space_op/src/pages/EditSpacePost/index.jsx

519 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useRef, useEffect } from "react";
import { Form, Input, Table, Image, Space, Button, Modal, message } from "antd";
import baseRequest from "../../utils/baseRequest";
import ImageUploader from "../../components/ImageUploader";
import VideoUploader from "../../components/VideoUploader";
import { useSearchParams } from "react-router-dom";
const EditSpacePostContent = (props) => {
const { TextArea } = Input;
const [searchParams, setSearchParams] = useSearchParams();
const userId = searchParams.get("user_id");
//表头
const columns = [
{
title: "发帖人",
dataIndex: "creator",
key: "creator",
render: (data) => (
<div>
<Image src={data.avatar.images[0].urls[0]} width={50} />
<p>
ID<span className="text-red-400">{data.user_id}</span>
</p>
<p>
昵称<span className="text-red-400">{data.name}</span>
</p>
</div>
),
},
{
title: "动态内容",
dataIndex: "content",
key: "content",
render: (data) => (
<div className="flex flex-col">
<div>
<p className="text-red-400">
当前状态
<span className="text-black">
{data.status === 0 && "机审中"}
{data.status === 1 && "运营待审核"}
{data.status === 2 && "可见"}
{data.status === 3 && "审核不通过"}
</span>
</p>
<hr />
<p className="text-red-400">
文案<span className="text-black">{data.content}</span>
</p>
</div>
<p className="text-red-400">媒体</p>
<div className="flex flex-wrap gap-1">
{data.media.images.map((item, index) => (
<Image key={index} src={item.urls[0]} width={100} />
))}
{data.media.videos.map((item, index) => (
<video key={index} src={item.urls[0]} width={150} controls />
))}
</div>
</div>
),
},
{
title: "付费设置",
dataIndex: "paymentSettings",
key: "paymentSettings",
render: (data) => (
<div className="flex flex-col">
<p className="text-red-400">
类型
<span className="text-black">
{data.c_type === 0 ? "免费" : "付费"}
</span>
</p>
{data.c_type === 1 && (
<div>
<hr />
<p className="text-red-400">
价格
<span className="text-black">¥{data.price}</span>
</p>
<hr />
<p className="text-red-400">
是否铁粉免费看
<span className="text-black">
{data.is_ironfan_visible === 0 ? "否" : "是"}
</span>
</p>
<hr />
<p className="text-red-400">
文案可见行数
<span className="text-black">{data.text_visible_range}</span>
</p>
{data.m_type === 1 ? (
<>
<hr />
<p className="text-red-400">
图片可见张数
<span className="text-black">
{data.media_visible_range}
</span>
</p>
</>
) : (
<>
<hr />
<p className="text-red-400">
是否模糊封面
<span className="text-black">
{data.is_blurring_cover === 0 ? "否" : "是"}
</span>
</p>
</>
)}
</div>
)}
</div>
),
},
{
title: "审核结果",
dataIndex: "info",
key: "info",
render: (data) => (
<div className="flex flex-col">
<p>文案审核结果</p>
<p className="text-green-400">{data.text_audit_opinion}</p>
<hr className="w-full" />
<p>媒体审核结果</p>
<p className="text-green-400">{data.image_audit_opinion}</p>
</div>
),
},
{
title: "发布时间",
dataIndex: "submitTime",
key: "submitTime",
},
{
title: "备注",
dataIndex: "remarks",
key: "remarks",
render: (_, record) => (
<div className="flex flex-col">
<Form.Item
name={record.momentId}
initialValue={record.remarks.manually_review_opinion}
>
<TextArea rows={4} />
</Form.Item>
</div>
),
},
{
title: "操作",
dataIndex: "opeartion",
key: "opeartion",
render: (_, record) => (
<div>
<Space>
<Space.Compact direction="vertical">
<Button type="primary" onClick={() => onClickEdit(record)}>
编辑
</Button>
<Button onClick={() => onClickInvisible(record)}>设为违规</Button>
<Button onClick={() => onClickDelete(record)}>删除</Button>
</Space.Compact>
</Space>
</div>
),
},
];
//控制编辑modal是否出现
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
//modal打开时的默认值
const [defaultValues, setDefaultValues] = useState({});
const [defaultMedia, setDefaultMedia] = useState({});
//点击modal取消按钮
const handleCancel = () => {
setDefaultValues({});
setDefaultMedia({});
setEditImageId([]);
setEditVideoId([]);
setIsEditModalOpen(false);
};
//点击编辑按钮
const onClickEdit = (record) => {
setDefaultValues(record);
setDefaultMedia(record.content.media);
setIsEditModalOpen(true);
};
//保存上传的媒体id
const [editImageId, setEditImageId] = useState([]);
const [editVideoId, setEditVideoId] = useState([]);
//删除默认的媒体
const handleDeleteMedia = (type, id) => {
if (type === "video") {
setDefaultMedia({
...defaultMedia,
video_ids: [],
});
return;
}
if (type === "image") {
setDefaultMedia({
...defaultMedia,
image_ids: defaultMedia.image_ids.filter((item) => item !== id),
images: defaultMedia.images.filter((item) => item.id !== id),
});
return;
}
};
//点击确认提交更改动态
const handleChange = async (value) => {
const imageIds = [...defaultMedia.image_ids, ...editImageId];
const videoIds = [...defaultMedia.video_ids, ...editVideoId];
if (imageIds.length === 0 && videoIds.length === 0) {
alert("图片或视频不可为空");
return;
}
if (imageIds.length !== 0 && videoIds.length !== 0) {
alert("不可同时上传图片和视频");
return;
}
if (imageIds.length > 30) {
alert("图片不可超过30张");
return;
}
if (videoIds.length > 1) {
alert("视频不可超过1个");
return;
}
try {
const base = baseRequest();
const response = await fetch("/op/zone_moment/update", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
id: defaultValues.momentId,
text: value.content,
media_component: {
image_ids: imageIds,
video_ids: videoIds,
},
c_type: defaultValues.data.c_type,
m_type: defaultValues.data.m_type,
...base,
}),
});
const temData = await response.json();
if (temData.ret === -1) {
alert(temData.msg);
return;
}
setShowData(
showData.filter((item) => item.momentId !== defaultValues.momentId)
);
handleCancel();
} catch (error) {
console.error(error);
}
};
//点击删除按钮
const onClickDelete = async (record) => {
try {
const base = baseRequest();
const response = await fetch("/op/zone_moment/delete", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
id: record.momentId,
...base,
}),
});
const temData = await response.json();
if (temData.ret === -1) {
alert(temData.msg);
return;
}
setShowData(showData.filter((item) => item.momentId !== record.momentId));
} catch (error) {
console.error(error);
}
};
//给表单绑定ref
const formRef = useRef(null);
//点击设为违规按钮
const onClickInvisible = (record) => {
formRef.current.record = record;
formRef.current.type = 0;
formRef.current.submit();
};
//提交备注
const handleSubmit = async (value) => {
try {
const base = baseRequest();
const response = await fetch("/op/zone_moment/set_private", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
zone_moment_id: parseInt(formRef.current.record.momentId, 10),
manually_review_opinion: value[formRef.current.record.momentId]
? value[formRef.current.record.momentId]
: "",
...base,
}),
});
const temData = await response.json();
if (temData.ret === -1) {
alert(temData.msg);
return;
}
setShowData(
showData.filter(
(item) => item.momentId !== formRef.current.record.momentId
)
);
} catch (error) {
console.error(error);
}
};
//展示的数据
const [showData, setShowData] = useState([]);
//搜索
const search = async (value) => {
try {
const base = baseRequest();
const detailResponse = await fetch(`/op/zone_moment/list_by_user_id`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user_id: parseInt(value.userId, 10),
offset: 0,
limit: 1000,
...base,
}),
});
const detailData = await detailResponse.json();
console.log(detailData.data);
if (detailData.ret === -1) {
alert(detailData.msg);
return;
}
//匹配表格格式
const structedData = detailData.data.list.map((item, index) => {
return {
key: index,
data: item,
momentId: item.id,
creator: item.streamer_ext,
content: {
status: item.status,
media: item.media_component,
content: item.text,
},
paymentSettings: {
c_type: item.c_type,
m_type: item.m_type,
price: item.price / 100,
is_ironfan_visible: item.is_ironfan_visible,
text_visible_range: item.text_visible_range,
media_visible_range: item.media_visible_range,
is_blurring_cover: item.is_blurring_cover,
},
info: {
image_audit_status: item.image_audit_status,
image_audit_opinion: item.image_audit_opinion,
text_audit_status: item.text_audit_status,
text_audit_opinion: item.text_audit_opinion,
},
submitTime: new Date(item.ct * 1000).toLocaleString(),
remarks: {
manually_review_status: item.manually_review_status,
manually_review_opinion: item.manually_review_opinion,
manually_review_operator: item.manually_review_operator,
},
};
});
setShowData(structedData);
} catch (error) {
console.error(error);
}
};
useEffect(() => {
if (!userId) return;
search({ userId });
}, []);
//表单提交失败
const onFinishFailed = (errorInfo) => {
console.log("Failed:", errorInfo);
};
return (
<div className="mt-4" style={{ marginLeft: 20, marginRight: 20 }}>
<Form name="search" onFinish={search} onFinishFailed={onFinishFailed}>
<Space style={{ marginBottom: 20 }}>
<Form.Item label="主播ID" name="userId" style={{ margin: 0 }}>
<Input type="number" />
</Form.Item>
<Button type="primary" htmlType="submit">
搜索
</Button>
</Space>
</Form>
<Form
ref={formRef}
name="remarks"
onFinish={handleSubmit}
onFinishFailed={onFinishFailed}
>
<Table
columns={columns}
dataSource={showData}
pagination={{ pageSize: 20 }}
scroll={{ y: window.innerHeight - 300 }}
/>
</Form>
{/* 编辑动态内容的弹窗重复判断isEditModalOpen是为了重新渲染ImageUploader和VideoUploader组件 */}
{isEditModalOpen && (
<Modal footer={null} open={isEditModalOpen} onCancel={handleCancel}>
<p className="text-sm text-red-400 font-bold">
*请确保文案不为空图片数不超过30视频数不超过1图片视频不同时存在
</p>
<Form className="mt-4 flex flex-col" onFinish={handleChange}>
<Space>
<Form.Item
label="文案"
name="content"
initialValue={defaultValues.content.content}
rules={[
{
required: true,
message: "请填写文案",
},
]}
style={{ margin: 0 }}
>
<TextArea />
</Form.Item>
</Space>
{defaultMedia.image_ids.length !== 0 && (
<div className="flex flex-row flex-wrap gap-2 mt-4">
{defaultMedia.images.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("image", item.id)}
>
删除
</Button>
</div>
))}
</div>
)}
{defaultMedia.video_ids.length !== 0 && (
<div className="flex flex-row mt-4">
<div className="relative">
<video
src={defaultMedia.videos[0].urls[0]}
width={150}
controls
className="mr-auto"
/>
<Button
className="absolute top-0 left-0 w-full"
danger
type="primary"
onClick={() => handleDeleteMedia("video")}
>
删除
</Button>
</div>
</div>
)}
{defaultValues.data.m_type === 1 && (
<ImageUploader setIds={setEditImageId} />
)}
{defaultValues.data.m_type === 2 && (
<VideoUploader setIds={setEditVideoId} />
)}
<Button className="ml-8" type="primary" htmlType="submit">
确认
</Button>
</Form>
</Modal>
)}
</div>
);
};
export default function EditSpacePost() {
return <EditSpacePostContent />;
}