同步
This commit is contained in:
@@ -1,26 +1,23 @@
|
||||
import React, { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Button, Card, ProgressBar, Popover, Toast, NavBar } from "antd-mobile";
|
||||
import { Button, Card, Popover, Toast } from "antd-mobile";
|
||||
import { Input, Switch } from "antd";
|
||||
import {
|
||||
MoreOutline,
|
||||
AddCircleOutline,
|
||||
UserAddOutline,
|
||||
ClockCircleOutline,
|
||||
TeamOutline,
|
||||
CalendarOutline,
|
||||
} from "antd-mobile-icons";
|
||||
|
||||
import {
|
||||
ReloadOutlined,
|
||||
SettingOutlined,
|
||||
PlusOutlined,
|
||||
ArrowLeftOutlined,
|
||||
SearchOutlined,
|
||||
} from "@ant-design/icons";
|
||||
|
||||
import Layout from "@/components/Layout/Layout";
|
||||
import style from "./index.module.scss";
|
||||
import NavCommon from "@/components/NavCommon";
|
||||
|
||||
interface GroupTask {
|
||||
id: string;
|
||||
@@ -167,25 +164,14 @@ const AutoGroupList: React.FC = () => {
|
||||
<Layout
|
||||
header={
|
||||
<>
|
||||
<NavBar
|
||||
back={null}
|
||||
style={{ background: "#fff" }}
|
||||
left={
|
||||
<div className="nav-title">
|
||||
<ArrowLeftOutlined
|
||||
twoToneColor="#1677ff"
|
||||
onClick={() => navigate(-1)}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
<NavCommon
|
||||
title="自动建群"
|
||||
right={
|
||||
<Button size="small" color="primary" onClick={handleCreateNew}>
|
||||
<PlusOutlined /> 新建任务
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<span className="nav-title">自动建群</span>
|
||||
</NavBar>
|
||||
/>
|
||||
{/* 搜索栏 */}
|
||||
<div className="search-bar">
|
||||
<div className="search-input-wrapper">
|
||||
|
||||
119
nkebao/src/pages/mobile/workspace/auto-like/list/data.ts
Normal file
119
nkebao/src/pages/mobile/workspace/auto-like/list/data.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
// 自动点赞任务状态
|
||||
export type LikeTaskStatus = 1 | 2; // 1: 开启, 2: 关闭
|
||||
|
||||
// 内容类型
|
||||
export type ContentType = "text" | "image" | "video" | "link";
|
||||
|
||||
// 设备信息
|
||||
export interface Device {
|
||||
id: string;
|
||||
name: string;
|
||||
status: "online" | "offline";
|
||||
lastActive: string;
|
||||
}
|
||||
|
||||
// 好友信息
|
||||
export interface Friend {
|
||||
id: string;
|
||||
nickname: string;
|
||||
wechatId: string;
|
||||
avatar: string;
|
||||
tags: string[];
|
||||
region: string;
|
||||
source: string;
|
||||
}
|
||||
|
||||
// 点赞记录
|
||||
export interface LikeRecord {
|
||||
id: string;
|
||||
workbenchId: string;
|
||||
momentsId: string;
|
||||
snsId: string;
|
||||
wechatAccountId: string;
|
||||
wechatFriendId: string;
|
||||
likeTime: string;
|
||||
content: string;
|
||||
resUrls: string[];
|
||||
momentTime: string;
|
||||
userName: string;
|
||||
operatorName: string;
|
||||
operatorAvatar: string;
|
||||
friendName: string;
|
||||
friendAvatar: string;
|
||||
}
|
||||
|
||||
// 自动点赞任务
|
||||
export interface LikeTask {
|
||||
id: string;
|
||||
name: string;
|
||||
status: LikeTaskStatus;
|
||||
deviceCount: number;
|
||||
targetGroup: string;
|
||||
likeCount: number;
|
||||
lastLikeTime: string;
|
||||
createTime: string;
|
||||
creator: string;
|
||||
likeInterval: number;
|
||||
maxLikesPerDay: number;
|
||||
timeRange: { start: string; end: string };
|
||||
contentTypes: ContentType[];
|
||||
targetTags: string[];
|
||||
devices: string[];
|
||||
friends: string[];
|
||||
friendMaxLikes: number;
|
||||
friendTags: string;
|
||||
enableFriendTags: boolean;
|
||||
todayLikeCount: number;
|
||||
totalLikeCount: number;
|
||||
updateTime: string;
|
||||
}
|
||||
|
||||
// 创建任务数据
|
||||
export interface CreateLikeTaskData {
|
||||
name: string;
|
||||
interval: number;
|
||||
maxLikes: number;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
contentTypes: ContentType[];
|
||||
devices: string[];
|
||||
friends?: string[];
|
||||
friendMaxLikes: number;
|
||||
friendTags?: string;
|
||||
enableFriendTags: boolean;
|
||||
targetTags: string[];
|
||||
}
|
||||
|
||||
// 更新任务数据
|
||||
export interface UpdateLikeTaskData extends CreateLikeTaskData {
|
||||
id: string;
|
||||
}
|
||||
|
||||
// 任务配置
|
||||
export interface TaskConfig {
|
||||
interval: number;
|
||||
maxLikes: number;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
contentTypes: ContentType[];
|
||||
devices: string[];
|
||||
friends: string[];
|
||||
friendMaxLikes: number;
|
||||
friendTags: string;
|
||||
enableFriendTags: boolean;
|
||||
}
|
||||
|
||||
// API响应类型
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
// 分页响应类型
|
||||
export interface PaginatedResponse<T> {
|
||||
list: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
MoreOutlined,
|
||||
LikeOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { ArrowLeftOutlined } from "@ant-design/icons";
|
||||
|
||||
import Layout from "@/components/Layout/Layout";
|
||||
import {
|
||||
@@ -23,7 +22,7 @@ import {
|
||||
toggleAutoLikeTask,
|
||||
copyAutoLikeTask,
|
||||
} from "./api";
|
||||
import { LikeTask } from "@/pages/workspace/auto-like/record/data";
|
||||
import { LikeTask } from "./data";
|
||||
import style from "./index.module.scss";
|
||||
|
||||
// 卡片菜单组件
|
||||
|
||||
@@ -1,37 +1,13 @@
|
||||
import request from "@/api/request";
|
||||
|
||||
export interface GroupPushTask {
|
||||
id: string;
|
||||
name: string;
|
||||
status: number; // 1: 运行中, 2: 已暂停
|
||||
deviceCount: number;
|
||||
targetGroups: string[];
|
||||
pushCount: number;
|
||||
successCount: number;
|
||||
lastPushTime: string;
|
||||
createTime: string;
|
||||
creator: string;
|
||||
pushInterval: number;
|
||||
maxPushPerDay: number;
|
||||
timeRange: { start: string; end: string };
|
||||
messageType: "text" | "image" | "video" | "link";
|
||||
messageContent: string;
|
||||
targetTags: string[];
|
||||
pushMode: "immediate" | "scheduled";
|
||||
scheduledTime?: string;
|
||||
}
|
||||
|
||||
interface ApiResponse<T = any> {
|
||||
code: number;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export async function fetchGroupPushTasks(): Promise<GroupPushTask[]> {
|
||||
const response = await request("/v1/workbench/list", { type: 3 }, "GET");
|
||||
if (Array.isArray(response)) return response;
|
||||
if (response && Array.isArray(response.data)) return response.data;
|
||||
return [];
|
||||
export async function fetchGroupPushTasks() {
|
||||
return request("/v1/workbench/list", { type: 3 }, "GET");
|
||||
}
|
||||
|
||||
export async function deleteGroupPushTask(id: string): Promise<ApiResponse> {
|
||||
|
||||
@@ -36,7 +36,6 @@ import {
|
||||
deleteGroupPushTask,
|
||||
toggleGroupPushTask,
|
||||
copyGroupPushTask,
|
||||
GroupPushTask,
|
||||
} from "./index.api";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
@@ -44,14 +43,14 @@ const GroupPush: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const [expandedTaskId, setExpandedTaskId] = useState<string | null>(null);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [tasks, setTasks] = useState<GroupPushTask[]>([]);
|
||||
const [tasks, setTasks] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const fetchTasks = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const list = await fetchGroupPushTasks();
|
||||
setTasks(list);
|
||||
const result = await fetchGroupPushTasks();
|
||||
setTasks(result.list);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -180,13 +179,7 @@ const GroupPush: React.FC = () => {
|
||||
allowClear
|
||||
size="large"
|
||||
/>
|
||||
|
||||
<Button
|
||||
className={styles["refresh-btn"]}
|
||||
size="small"
|
||||
onClick={fetchTasks}
|
||||
loading={loading}
|
||||
>
|
||||
<Button size="small" onClick={fetchTasks} loading={loading}>
|
||||
<ReloadOutlined />
|
||||
</Button>
|
||||
</div>
|
||||
@@ -228,39 +221,35 @@ const GroupPush: React.FC = () => {
|
||||
onChange={() => toggleTaskStatus(task.id)}
|
||||
/>
|
||||
<Dropdown
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
key="view"
|
||||
icon={<EyeOutlined />}
|
||||
onClick={() => handleView(task.id)}
|
||||
>
|
||||
查看
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key="edit"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => handleEdit(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>
|
||||
}
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
key: "view",
|
||||
icon: <EyeOutlined />,
|
||||
label: "查看",
|
||||
onClick: () => handleView(task.id),
|
||||
},
|
||||
{
|
||||
key: "edit",
|
||||
icon: <EditOutlined />,
|
||||
label: "编辑",
|
||||
onClick: () => handleEdit(task.id),
|
||||
},
|
||||
{
|
||||
key: "copy",
|
||||
icon: <CopyOutlined />,
|
||||
label: "复制",
|
||||
onClick: () => handleCopy(task.id),
|
||||
},
|
||||
{
|
||||
key: "delete",
|
||||
icon: <DeleteOutlined />,
|
||||
label: "删除",
|
||||
danger: true,
|
||||
onClick: () => handleDelete(task.id),
|
||||
},
|
||||
],
|
||||
}}
|
||||
trigger={["click"]}
|
||||
>
|
||||
<Button icon={<MoreOutlined />} />
|
||||
@@ -268,131 +257,21 @@ const GroupPush: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.taskInfoGrid}>
|
||||
<div>执行设备:{task.deviceCount} 个</div>
|
||||
<div>目标群组:{task.targetGroups.length} 个</div>
|
||||
<div>执行设备:{task.deviceCount || 1} 个</div>
|
||||
<div>目标群组:{task.config?.groups?.length || 0} 个</div>
|
||||
<div>
|
||||
推送成功:{task.successCount}/{task.pushCount}
|
||||
推送成功:{task.successCount || 0}/{task.pushCount || 0}
|
||||
</div>
|
||||
<div>创建人:{task.creator}</div>
|
||||
</div>
|
||||
<div className={styles.progressBlock}>
|
||||
<div className={styles.progressLabel}>推送成功率</div>
|
||||
<Progress
|
||||
percent={getSuccessRate(task.pushCount, task.successCount)}
|
||||
size="small"
|
||||
/>
|
||||
<div>创建人:{task.creatorName || task.creator}</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.taskFooter}>
|
||||
<div>
|
||||
<ClockCircleOutlined /> 上次推送:{task.lastPushTime}
|
||||
</div>
|
||||
<div>
|
||||
创建时间:{task.createTime}
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={
|
||||
expandedTaskId === task.id ? (
|
||||
<UpOutlined />
|
||||
) : (
|
||||
<DownOutlined />
|
||||
)
|
||||
}
|
||||
onClick={() => toggleExpand(task.id)}
|
||||
/>
|
||||
<ClockCircleOutlined /> 上次推送:
|
||||
{task.config?.lastPushTime || "暂无"}
|
||||
</div>
|
||||
<div>创建时间:{task.createTime}</div>
|
||||
</div>
|
||||
{expandedTaskId === task.id && (
|
||||
<div className={styles.expandedPanel}>
|
||||
<div className={styles.expandedGrid}>
|
||||
<div>
|
||||
<SettingOutlined /> <b>基本设置</b>
|
||||
<div>推送间隔:{task.pushInterval} 秒</div>
|
||||
<div>每日最大推送数:{task.maxPushPerDay} 条</div>
|
||||
<div>
|
||||
执行时间段:{task.timeRange.start} -{" "}
|
||||
{task.timeRange.end}
|
||||
</div>
|
||||
<div>
|
||||
推送模式:
|
||||
{task.pushMode === "immediate"
|
||||
? "立即推送"
|
||||
: "定时推送"}
|
||||
</div>
|
||||
{task.scheduledTime && (
|
||||
<div>定时时间:{task.scheduledTime}</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<TeamOutlined /> <b>目标群组</b>
|
||||
<div
|
||||
style={{ display: "flex", flexWrap: "wrap", gap: 4 }}
|
||||
>
|
||||
{task.targetGroups.map(group => (
|
||||
<Badge
|
||||
key={group}
|
||||
color="blue"
|
||||
text={group}
|
||||
style={{ background: "#f0f5ff", marginRight: 4 }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<MessageOutlined /> <b>消息内容</b>
|
||||
<div>
|
||||
消息类型:{getMessageTypeText(task.messageType)}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
background: "#f5f5f5",
|
||||
padding: 8,
|
||||
borderRadius: 4,
|
||||
marginTop: 4,
|
||||
}}
|
||||
>
|
||||
{task.messageContent}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<CalendarOutlined /> <b>执行进度</b>
|
||||
<div>
|
||||
今日已推送:{task.pushCount} / {task.maxPushPerDay}
|
||||
</div>
|
||||
<Progress
|
||||
percent={Math.round(
|
||||
(task.pushCount / task.maxPushPerDay) * 100,
|
||||
)}
|
||||
size="small"
|
||||
/>
|
||||
{task.targetTags.length > 0 && (
|
||||
<div style={{ marginTop: 8 }}>
|
||||
<div>目标标签:</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
{task.targetTags.map(tag => (
|
||||
<Badge
|
||||
key={tag}
|
||||
color="purple"
|
||||
text={tag}
|
||||
style={{
|
||||
background: "#f9f0ff",
|
||||
marginRight: 4,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
))
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user