feat: 本次提交更新内容如下
路由处理下
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import {
|
||||
Plus,
|
||||
Search,
|
||||
@@ -12,21 +12,21 @@ import {
|
||||
Copy,
|
||||
ChevronLeft,
|
||||
Share2,
|
||||
} from 'lucide-react';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { useToast } from '@/components/ui/toast';
|
||||
import '@/components/Layout.css';
|
||||
import {
|
||||
fetchMomentsSyncTasks,
|
||||
deleteMomentsSyncTask,
|
||||
toggleMomentsSyncTask,
|
||||
} from "lucide-react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { useToast } from "@/components/ui/toast";
|
||||
import "@/components/Layout.css";
|
||||
import {
|
||||
fetchMomentsSyncTasks,
|
||||
deleteMomentsSyncTask,
|
||||
toggleMomentsSyncTask,
|
||||
copyMomentsSyncTask,
|
||||
MomentsSyncTask
|
||||
} from '@/api/momentsSync';
|
||||
MomentsSyncTask,
|
||||
} from "@/api/momentsSync";
|
||||
|
||||
type CardMenuProps = {
|
||||
onView: () => void;
|
||||
@@ -51,7 +51,16 @@ function CardMenu({ onView, onEdit, onCopy, onDelete }: CardMenuProps) {
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
<button onClick={() => setOpen((v) => !v)} style={{ background: "none", border: "none", padding: 0, margin: 0, cursor: "pointer" }}>
|
||||
<button
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
style={{
|
||||
background: "none",
|
||||
border: "none",
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
<MoreVertical className="h-4 w-4" />
|
||||
</button>
|
||||
{open && (
|
||||
@@ -69,17 +78,106 @@ function CardMenu({ onView, onEdit, onCopy, onDelete }: CardMenuProps) {
|
||||
padding: 4,
|
||||
}}
|
||||
>
|
||||
<div onClick={() => { onView(); setOpen(false); }} style={{ padding: 8, cursor: "pointer", display: "flex", alignItems: "center", borderRadius: 6, fontSize: 14, gap: 6, transition: "background .2s" }} onMouseOver={e => (e.currentTarget as HTMLDivElement).style.background="#f5f5f5"} onMouseOut={e => (e.currentTarget as HTMLDivElement).style.background=""}>
|
||||
<Eye className="h-4 w-4 mr-2" />查看
|
||||
<div
|
||||
onClick={() => {
|
||||
onView();
|
||||
setOpen(false);
|
||||
}}
|
||||
style={{
|
||||
padding: 8,
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
borderRadius: 6,
|
||||
fontSize: 14,
|
||||
gap: 6,
|
||||
transition: "background .2s",
|
||||
}}
|
||||
onMouseOver={(e) =>
|
||||
((e.currentTarget as HTMLDivElement).style.background = "#f5f5f5")
|
||||
}
|
||||
onMouseOut={(e) =>
|
||||
((e.currentTarget as HTMLDivElement).style.background = "")
|
||||
}
|
||||
>
|
||||
<Eye className="h-4 w-4 mr-2" />
|
||||
查看
|
||||
</div>
|
||||
<div onClick={() => { onEdit(); setOpen(false); }} style={{ padding: 8, cursor: "pointer", display: "flex", alignItems: "center", borderRadius: 6, fontSize: 14, gap: 6, transition: "background .2s" }} onMouseOver={e => (e.currentTarget as HTMLDivElement).style.background="#f5f5f5"} onMouseOut={e => (e.currentTarget as HTMLDivElement).style.background=""}>
|
||||
<Edit className="h-4 w-4 mr-2" />编辑
|
||||
<div
|
||||
onClick={() => {
|
||||
onEdit();
|
||||
setOpen(false);
|
||||
}}
|
||||
style={{
|
||||
padding: 8,
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
borderRadius: 6,
|
||||
fontSize: 14,
|
||||
gap: 6,
|
||||
transition: "background .2s",
|
||||
}}
|
||||
onMouseOver={(e) =>
|
||||
((e.currentTarget as HTMLDivElement).style.background = "#f5f5f5")
|
||||
}
|
||||
onMouseOut={(e) =>
|
||||
((e.currentTarget as HTMLDivElement).style.background = "")
|
||||
}
|
||||
>
|
||||
<Edit className="h-4 w-4 mr-2" />
|
||||
编辑
|
||||
</div>
|
||||
<div onClick={() => { onCopy(); setOpen(false); }} style={{ padding: 8, cursor: "pointer", display: "flex", alignItems: "center", borderRadius: 6, fontSize: 14, gap: 6, transition: "background .2s" }} onMouseOver={e => (e.currentTarget as HTMLDivElement).style.background="#f5f5f5"} onMouseOut={e => (e.currentTarget as HTMLDivElement).style.background=""}>
|
||||
<Copy className="h-4 w-4 mr-2" />复制
|
||||
<div
|
||||
onClick={() => {
|
||||
onCopy();
|
||||
setOpen(false);
|
||||
}}
|
||||
style={{
|
||||
padding: 8,
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
borderRadius: 6,
|
||||
fontSize: 14,
|
||||
gap: 6,
|
||||
transition: "background .2s",
|
||||
}}
|
||||
onMouseOver={(e) =>
|
||||
((e.currentTarget as HTMLDivElement).style.background = "#f5f5f5")
|
||||
}
|
||||
onMouseOut={(e) =>
|
||||
((e.currentTarget as HTMLDivElement).style.background = "")
|
||||
}
|
||||
>
|
||||
<Copy className="h-4 w-4 mr-2" />
|
||||
复制
|
||||
</div>
|
||||
<div onClick={() => { onDelete(); setOpen(false); }} style={{ padding: 8, cursor: "pointer", display: "flex", alignItems: "center", borderRadius: 6, fontSize: 14, gap: 6, color: "#e53e3e", transition: "background .2s" }} onMouseOver={e => (e.currentTarget as HTMLDivElement).style.background="#f5f5f5"} onMouseOut={e => (e.currentTarget as HTMLDivElement).style.background=""}>
|
||||
<Trash2 className="h-4 w-4 mr-2" />删除
|
||||
<div
|
||||
onClick={() => {
|
||||
onDelete();
|
||||
setOpen(false);
|
||||
}}
|
||||
style={{
|
||||
padding: 8,
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
borderRadius: 6,
|
||||
fontSize: 14,
|
||||
gap: 6,
|
||||
color: "#e53e3e",
|
||||
transition: "background .2s",
|
||||
}}
|
||||
onMouseOver={(e) =>
|
||||
((e.currentTarget as HTMLDivElement).style.background = "#f5f5f5")
|
||||
}
|
||||
onMouseOut={(e) =>
|
||||
((e.currentTarget as HTMLDivElement).style.background = "")
|
||||
}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" />
|
||||
删除
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -90,7 +188,7 @@ function CardMenu({ onView, onEdit, onCopy, onDelete }: CardMenuProps) {
|
||||
export default function MomentsSync() {
|
||||
const navigate = useNavigate();
|
||||
const { toast } = useToast();
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [tasks, setTasks] = useState<MomentsSyncTask[]>([]);
|
||||
|
||||
@@ -100,24 +198,24 @@ export default function MomentsSync() {
|
||||
try {
|
||||
const list = await fetchMomentsSyncTasks();
|
||||
// 确保数据字段与界面一致
|
||||
const mappedTasks = list.map(task => ({
|
||||
const mappedTasks = list.map((task) => ({
|
||||
...task,
|
||||
// 确保字段名称和格式与界面一致
|
||||
status: task.status || 2, // 默认为关闭状态
|
||||
deviceCount: task.deviceCount || 0,
|
||||
targetGroup: task.targetGroup || '默认人群',
|
||||
targetGroup: task.targetGroup || "默认人群",
|
||||
syncCount: task.todaySyncCount || task.syncCount || 0,
|
||||
creatorName: task.creatorName || '未知',
|
||||
lastSyncTime: task.lastSyncTime || '暂无',
|
||||
createTime: task.createTime || '未知',
|
||||
creatorName: task.creatorName || "未知",
|
||||
lastSyncTime: task.lastSyncTime || "暂无",
|
||||
createTime: task.createTime || "未知",
|
||||
syncInterval: task.syncInterval || 30,
|
||||
maxSyncPerDay: task.maxSyncPerDay || 100,
|
||||
timeRange: task.timeRange || { start: '08:00', end: '22:00' },
|
||||
contentTypes: task.contentTypes || ['text', 'image', 'video'],
|
||||
timeRange: task.timeRange || { start: "08:00", end: "22:00" },
|
||||
contentTypes: task.contentTypes || ["text", "image", "video"],
|
||||
targetTags: task.targetTags || [],
|
||||
syncMode: task.syncMode || 'auto',
|
||||
syncMode: task.syncMode || "auto",
|
||||
filterKeywords: task.filterKeywords || [],
|
||||
contentLib: task.config?.contentLibraryNames?.join(',') || '默认内容库'
|
||||
contentLib: task.config?.contentLibraryNames?.join(",") || "默认内容库",
|
||||
}));
|
||||
setTasks(mappedTasks);
|
||||
} catch (error) {
|
||||
@@ -137,17 +235,25 @@ export default function MomentsSync() {
|
||||
if (!taskToDelete) return;
|
||||
|
||||
if (!window.confirm(`确定要删除"${taskToDelete.name}"吗?`)) return;
|
||||
|
||||
|
||||
try {
|
||||
const response = await deleteMomentsSyncTask(id);
|
||||
if (response.code === 200) {
|
||||
toast({ title: "删除成功" });
|
||||
fetchTasks();
|
||||
} else {
|
||||
toast({ title: "删除失败", description: response.msg || "请稍后重试", variant: "destructive" });
|
||||
toast({
|
||||
title: "删除失败",
|
||||
description: response.msg || "请稍后重试",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
toast({ title: "删除失败", description: "请稍后重试", variant: "destructive" });
|
||||
toast({
|
||||
title: "删除失败",
|
||||
description: "请稍后重试",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -166,18 +272,26 @@ export default function MomentsSync() {
|
||||
toast({ title: "复制成功" });
|
||||
fetchTasks();
|
||||
} else {
|
||||
toast({ title: "复制失败", description: response.msg || "请稍后重试", variant: "destructive" });
|
||||
toast({
|
||||
title: "复制失败",
|
||||
description: response.msg || "请稍后重试",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
toast({ title: "复制失败", description: "请稍后重试", variant: "destructive" });
|
||||
toast({
|
||||
title: "复制失败",
|
||||
description: "请稍后重试",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const toggleTaskStatus = async (id: string, status: number) => {
|
||||
// 先更新本地状态
|
||||
const newStatus = (status === 1 ? 2 : 1) as 1 | 2;
|
||||
setTasks(prevTasks =>
|
||||
prevTasks.map(task =>
|
||||
setTasks((prevTasks) =>
|
||||
prevTasks.map((task) =>
|
||||
task.id === id ? { ...task, status: newStatus } : task
|
||||
)
|
||||
);
|
||||
@@ -189,40 +303,48 @@ export default function MomentsSync() {
|
||||
// 成功时不刷新列表,保持本地状态
|
||||
} else {
|
||||
// 请求失败,回退本地状态
|
||||
setTasks(prevTasks =>
|
||||
prevTasks.map(task =>
|
||||
setTasks((prevTasks) =>
|
||||
prevTasks.map((task) =>
|
||||
task.id === id ? { ...task, status: status as 1 | 2 } : task
|
||||
)
|
||||
);
|
||||
toast({ title: "操作失败", description: response.msg || "请稍后重试", variant: "destructive" });
|
||||
toast({
|
||||
title: "操作失败",
|
||||
description: response.msg || "请稍后重试",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
// 请求异常,回退本地状态
|
||||
setTasks(prevTasks =>
|
||||
prevTasks.map(task =>
|
||||
setTasks((prevTasks) =>
|
||||
prevTasks.map((task) =>
|
||||
task.id === id ? { ...task, status: status as 1 | 2 } : task
|
||||
)
|
||||
);
|
||||
toast({ title: "操作失败", description: "请稍后重试", variant: "destructive" });
|
||||
toast({
|
||||
title: "操作失败",
|
||||
description: "请稍后重试",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateNew = () => {
|
||||
navigate('/workspace/moments-sync/new');
|
||||
navigate("/workspace/moments-sync/new");
|
||||
};
|
||||
|
||||
const filteredTasks = tasks.filter((task) =>
|
||||
task.name.toLowerCase().includes(searchTerm.toLowerCase()),
|
||||
task.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
const getStatusText = (status: number) => {
|
||||
switch (status) {
|
||||
case 1:
|
||||
return '进行中';
|
||||
return "进行中";
|
||||
case 2:
|
||||
return '已暂停';
|
||||
return "已暂停";
|
||||
default:
|
||||
return '未知';
|
||||
return "未知";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -231,13 +353,18 @@ export default function MomentsSync() {
|
||||
<header className="sticky top-0 z-10 bg-white border-b">
|
||||
<div className="flex items-center justify-between p-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<Button variant="ghost" size="icon" onClick={() => navigate(-1)}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => navigate("/workspace")}
|
||||
>
|
||||
<ChevronLeft className="h-5 w-5" />
|
||||
</Button>
|
||||
<h1 className="text-lg font-medium">朋友圈同步</h1>
|
||||
</div>
|
||||
<Button onClick={handleCreateNew}>
|
||||
<Plus className="h-4 w-4 mr-2" />新建任务
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
新建任务
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
@@ -246,14 +373,19 @@ export default function MomentsSync() {
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="relative flex-1">
|
||||
<Search className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
|
||||
<Input
|
||||
placeholder="搜索任务名称"
|
||||
className="pl-9"
|
||||
<Input
|
||||
placeholder="搜索任务名称"
|
||||
className="pl-9"
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" onClick={fetchTasks} disabled={loading}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={fetchTasks}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<RefreshCw className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
@@ -267,8 +399,12 @@ export default function MomentsSync() {
|
||||
{filteredTasks.length === 0 ? (
|
||||
<Card className="p-8 text-center">
|
||||
<Share2 className="h-12 w-12 text-gray-300 mx-auto mb-3" />
|
||||
<p className="text-gray-500 text-lg font-medium mb-2">暂无同步任务</p>
|
||||
<p className="text-gray-400 text-sm mb-4">创建您的第一个朋友圈同步任务</p>
|
||||
<p className="text-gray-500 text-lg font-medium mb-2">
|
||||
暂无同步任务
|
||||
</p>
|
||||
<p className="text-gray-400 text-sm mb-4">
|
||||
创建您的第一个朋友圈同步任务
|
||||
</p>
|
||||
<Button onClick={handleCreateNew}>
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
创建第一个任务
|
||||
@@ -280,14 +416,20 @@ export default function MomentsSync() {
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<h3 className="font-medium">{task.name}</h3>
|
||||
<Badge variant={Number(task.status) === 1 ? "success" : "secondary"}>
|
||||
<Badge
|
||||
variant={
|
||||
Number(task.status) === 1 ? "success" : "secondary"
|
||||
}
|
||||
>
|
||||
{getStatusText(task.status)}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch
|
||||
checked={Number(task.status) === 1}
|
||||
onCheckedChange={() => toggleTaskStatus(task.id, Number(task.status))}
|
||||
onCheckedChange={() =>
|
||||
toggleTaskStatus(task.id, Number(task.status))
|
||||
}
|
||||
/>
|
||||
<CardMenu
|
||||
onView={() => handleView(task.id)}
|
||||
@@ -300,11 +442,14 @@ export default function MomentsSync() {
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 mb-4">
|
||||
<div className="text-sm text-gray-500">
|
||||
<div>推送设备:{task?.config?.devices.length||0} 个</div>
|
||||
<div>推送设备:{task?.config?.devices.length || 0} 个</div>
|
||||
<div className="flex">
|
||||
<span className="flex-shrink-0">内容库:</span>
|
||||
<span className="truncate" title={task.contentLib || '默认内容库'}>
|
||||
{task.contentLib || '默认内容库'}
|
||||
<span
|
||||
className="truncate"
|
||||
title={task.contentLib || "默认内容库"}
|
||||
>
|
||||
{task.contentLib || "默认内容库"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -328,4 +473,4 @@ export default function MomentsSync() {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import Layout from '@/components/Layout';
|
||||
import PageHeader from '@/components/PageHeader';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { RefreshCw, Search, RefreshCw as SyncIcon, Eye } from 'lucide-react';
|
||||
import { fetchMomentsSyncTasks, syncMoments, syncAllMoments, MomentsSyncTask } from '@/api/momentsSync';
|
||||
import { useToast } from '@/components/ui/toast';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Layout from "@/components/Layout";
|
||||
import PageHeader from "@/components/PageHeader";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { RefreshCw, Search, RefreshCw as SyncIcon, Eye } from "lucide-react";
|
||||
import {
|
||||
fetchMomentsSyncTasks,
|
||||
syncMoments,
|
||||
syncAllMoments,
|
||||
MomentsSyncTask,
|
||||
} from "@/api/momentsSync";
|
||||
import { useToast } from "@/components/ui/toast";
|
||||
|
||||
export default function MomentsSyncPage() {
|
||||
const navigate = useNavigate();
|
||||
const { toast } = useToast();
|
||||
const [tasks, setTasks] = useState<MomentsSyncTask[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [search, setSearch] = useState('');
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const fetchTasks = async () => {
|
||||
setLoading(true);
|
||||
@@ -24,44 +29,46 @@ export default function MomentsSyncPage() {
|
||||
const list = await fetchMomentsSyncTasks();
|
||||
setTasks(list);
|
||||
} catch {
|
||||
toast({ title: '获取任务失败', variant: 'destructive' });
|
||||
toast({ title: "获取任务失败", variant: "destructive" });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => { fetchTasks(); }, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
useEffect(() => {
|
||||
fetchTasks();
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const handleSearch = () => {
|
||||
fetchTasks();
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
setSearch('');
|
||||
setSearch("");
|
||||
fetchTasks();
|
||||
};
|
||||
|
||||
const handleSync = async (id: string) => {
|
||||
try {
|
||||
await syncMoments(id);
|
||||
toast({ title: '同步已发起' });
|
||||
toast({ title: "同步已发起" });
|
||||
fetchTasks();
|
||||
} catch {
|
||||
toast({ title: '同步失败', variant: 'destructive' });
|
||||
toast({ title: "同步失败", variant: "destructive" });
|
||||
}
|
||||
};
|
||||
|
||||
const handleSyncAll = async () => {
|
||||
try {
|
||||
await syncAllMoments();
|
||||
toast({ title: '全部同步已发起' });
|
||||
toast({ title: "全部同步已发起" });
|
||||
fetchTasks();
|
||||
} catch {
|
||||
toast({ title: '同步失败', variant: 'destructive' });
|
||||
toast({ title: "同步失败", variant: "destructive" });
|
||||
}
|
||||
};
|
||||
|
||||
const filteredTasks = tasks.filter(task =>
|
||||
const filteredTasks = tasks.filter((task) =>
|
||||
task.name.toLowerCase().includes(search.toLowerCase())
|
||||
);
|
||||
|
||||
@@ -77,15 +84,18 @@ export default function MomentsSyncPage() {
|
||||
placeholder="搜索任务名称"
|
||||
className="pl-9"
|
||||
value={search}
|
||||
onChange={e => setSearch(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter') handleSearch(); }}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") handleSearch();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" onClick={handleRefresh}>
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button onClick={handleSyncAll} variant="default" size="sm">
|
||||
<SyncIcon className="h-4 w-4 mr-1" />全部同步
|
||||
<SyncIcon className="h-4 w-4 mr-1" />
|
||||
全部同步
|
||||
</Button>
|
||||
</div>
|
||||
<div className="p-4 space-y-4">
|
||||
@@ -94,26 +104,45 @@ export default function MomentsSyncPage() {
|
||||
) : filteredTasks.length === 0 ? (
|
||||
<Card className="p-8 text-center">暂无任务</Card>
|
||||
) : (
|
||||
filteredTasks.map(task => (
|
||||
<Card key={task.id} className="p-4 flex flex-col md:flex-row md:items-center md:justify-between">
|
||||
filteredTasks.map((task) => (
|
||||
<Card
|
||||
key={task.id}
|
||||
className="p-4 flex flex-col md:flex-row md:items-center md:justify-between"
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center space-x-2 mb-2">
|
||||
<span className="font-medium text-base">{task.name}</span>
|
||||
<Badge variant={
|
||||
task.status === 1 ? 'success' : 'secondary'
|
||||
}>
|
||||
{task.status === 1 ? '进行中' : '已暂停'}
|
||||
<Badge
|
||||
variant={task.status === 1 ? "success" : "secondary"}
|
||||
>
|
||||
{task.status === 1 ? "进行中" : "已暂停"}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 mb-2">上次同步:{task.lastSyncTime || '无'}</div>
|
||||
<div className="text-xs text-gray-500 mb-2">已同步:{task.syncCount || 0} 条</div>
|
||||
<div className="text-xs text-gray-500 mb-2">
|
||||
上次同步:{task.lastSyncTime || "无"}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 mb-2">
|
||||
已同步:{task.syncCount || 0} 条
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 mt-2 md:mt-0">
|
||||
<Button size="sm" variant="outline" onClick={() => navigate(`/workspace/moments-sync/${task.id}`)}>
|
||||
<Eye className="h-4 w-4 mr-1" />查看
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() =>
|
||||
navigate(`/workspace/moments-sync/${task.id}`)
|
||||
}
|
||||
>
|
||||
<Eye className="h-4 w-4 mr-1" />
|
||||
查看
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => handleSync(task.id)}>
|
||||
<SyncIcon className="h-4 w-4 mr-1" />同步
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => handleSync(task.id)}
|
||||
>
|
||||
<SyncIcon className="h-4 w-4 mr-1" />
|
||||
同步
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -123,4 +152,4 @@ export default function MomentsSyncPage() {
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user