Files
ckb-SuperAdmin/nkebao/src/pages/workspace/moments-sync/MomentsSync.tsx
笔记本里的永平 20791a0ab5 feat: 本次提交更新内容如下
朋友圈同步列表完成
2025-07-21 16:37:53 +08:00

275 lines
8.1 KiB
TypeScript
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, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Button, Switch, Input, message, Badge, Dropdown, Menu } from "antd";
import {
PlusOutlined,
SearchOutlined,
ReloadOutlined,
EyeOutlined,
EditOutlined,
DeleteOutlined,
CopyOutlined,
MoreOutlined,
ClockCircleOutlined,
ArrowLeftOutlined,
} from "@ant-design/icons";
import Layout from "@/components/Layout/Layout";
import style from "./index.module.scss";
import request from "@/api/request";
interface MomentsSyncTask {
id: string;
name: string;
status: 1 | 2;
deviceCount: number;
syncCount: number;
lastSyncTime: string;
createTime: string;
creatorName: string;
contentLib?: string;
config?: { devices?: string[]; contentLibraryNames?: string[] };
}
const getStatusText = (status: number) => {
switch (status) {
case 1:
return "进行中";
case 2:
return "已暂停";
default:
return "未知";
}
};
const MomentsSync: React.FC = () => {
const navigate = useNavigate();
const [searchTerm, setSearchTerm] = useState("");
const [loading, setLoading] = useState(false);
const [tasks, setTasks] = useState<MomentsSyncTask[]>([]);
const fetchTasks = async () => {
setLoading(true);
try {
const res = await request(
"/v1/workbench/list",
{ type: 2, page: 1, limit: 100 },
"GET"
);
setTasks(res.list || []);
} catch (e) {
message.error("获取任务失败");
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchTasks();
}, []);
const handleDelete = async (id: string) => {
if (!window.confirm("确定要删除该任务吗?")) return;
try {
await request("/v1/workbench/delete", { id }, "DELETE");
message.success("删除成功");
fetchTasks();
} catch {
message.error("删除失败");
}
};
const handleCopy = async (id: string) => {
try {
await request("/v1/workbench/copy", { id }, "POST");
message.success("复制成功");
fetchTasks();
} catch {
message.error("复制失败");
}
};
const handleToggle = async (id: string, status: number) => {
const newStatus = status === 1 ? 2 : 1;
try {
await request(
"/v1/workbench/update-status",
{ id, status: newStatus },
"POST"
);
setTasks((prev) =>
prev.map((t) => (t.id === id ? { ...t, status: newStatus } : t))
);
message.success("操作成功");
} catch {
message.error("操作失败");
}
};
const filteredTasks = tasks.filter((task) =>
task.name.toLowerCase().includes(searchTerm.toLowerCase())
);
// 菜单
const getMenu = (task: MomentsSyncTask) => (
<Menu>
<Menu.Item
key="view"
icon={<EyeOutlined />}
onClick={() => navigate(`/workspace/moments-sync/${task.id}`)}
>
</Menu.Item>
<Menu.Item
key="edit"
icon={<EditOutlined />}
onClick={() => navigate(`/workspace/moments-sync/edit/${task.id}`)}
>
</Menu.Item>
<Menu.Item
key="copy"
icon={<CopyOutlined />}
onClick={() => handleCopy(task.id)}
>
</Menu.Item>
<Menu.Item
key="delete"
icon={<DeleteOutlined />}
onClick={() => handleDelete(task.id)}
danger
>
</Menu.Item>
</Menu>
);
return (
<Layout
header={
<>
<div className={style.headerBar}>
<Button
type="text"
icon={<ArrowLeftOutlined />}
onClick={() => navigate("/workspace")}
className={style.backBtn}
/>
<span className={style.title}></span>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() => navigate("/workspace/moments-sync/new")}
className={style.addBtn}
>
</Button>
</div>
<div className={style.searchBar}>
<Input
placeholder="搜索任务名称"
prefix={<SearchOutlined />}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
onPressEnter={fetchTasks}
className={style.searchInput}
/>
<Button
icon={<ReloadOutlined />}
onClick={fetchTasks}
loading={loading}
/>
</div>
</>
}
>
<div className={style.pageBg}>
<div className={style.taskList}>
{filteredTasks.length === 0 ? (
<div className={style.emptyBox}>
<span style={{ fontSize: 40, color: "#ddd" }}>
<ClockCircleOutlined />
</span>
<div className={style.emptyText}></div>
<Button
type="primary"
onClick={() => navigate("/workspace/moments-sync/new")}
>
</Button>
</div>
) : (
filteredTasks.map((task) => (
<div key={task.id} className={style.itemCard}>
<div className={style.itemTop}>
<div className={style.itemTitle}>
<span className={style.itemName}>{task.name}</span>
<span
className={
task.status === 1
? style.statusPill + " " + style.statusActive
: style.statusPill + " " + style.statusPaused
}
>
{getStatusText(task.status)}
</span>
</div>
<div className={style.itemActions}>
<Switch
checked={task.status === 1}
onChange={() => handleToggle(task.id, task.status)}
className={style.switchBtn}
size="small"
/>
<Dropdown
overlay={getMenu(task)}
trigger={["click"]}
placement="bottomRight"
>
<Button
type="text"
icon={<MoreOutlined />}
className={style.moreBtn}
/>
</Dropdown>
</div>
</div>
<div className={style.itemInfoRow}>
<div className={style.infoCol}>
{task.config?.devices?.length || 0}
</div>
<div className={style.infoCol}>
{task.syncCount || 0}
</div>
</div>
<div className={style.itemInfoRow}>
<div className={style.infoCol}>
{task.config?.contentLibraryNames?.join(",") ||
task.contentLib ||
"默认内容库"}
</div>
<div className={style.infoCol}>
{task.creatorName}
</div>
</div>
<div className={style.itemBottom}>
<div className={style.bottomLeft}>
<ClockCircleOutlined className={style.clockIcon} />
{task.lastSyncTime || "无"}
</div>
<div className={style.bottomRight}>
{task.createTime}
</div>
</div>
</div>
))
)}
</div>
</div>
</Layout>
);
};
export default MomentsSync;