diff --git a/Cunkebao/dist/.vite/manifest.json b/Cunkebao/dist/.vite/manifest.json index 739932df..eae30d1e 100644 --- a/Cunkebao/dist/.vite/manifest.json +++ b/Cunkebao/dist/.vite/manifest.json @@ -1,9 +1,9 @@ { - "_charts-D0fT04H8.js": { - "file": "assets/charts-D0fT04H8.js", + "_charts-DHgoott5.js": { + "file": "assets/charts-DHgoott5.js", "name": "charts", "imports": [ - "_ui-qLeQLv1F.js", + "_ui-Upu1eBzw.js", "_vendor-2vc8h_ct.js" ] }, @@ -11,8 +11,8 @@ "file": "assets/ui-D0C0OGrH.css", "src": "_ui-D0C0OGrH.css" }, - "_ui-qLeQLv1F.js": { - "file": "assets/ui-qLeQLv1F.js", + "_ui-Upu1eBzw.js": { + "file": "assets/ui-Upu1eBzw.js", "name": "ui", "imports": [ "_vendor-2vc8h_ct.js" @@ -33,18 +33,18 @@ "name": "vendor" }, "index.html": { - "file": "assets/index-Bos-kh2O.js", + "file": "assets/index-Cqw-bDjj.js", "name": "index", "src": "index.html", "isEntry": true, "imports": [ "_vendor-2vc8h_ct.js", - "_ui-qLeQLv1F.js", + "_ui-Upu1eBzw.js", "_utils-6WF66_dS.js", - "_charts-D0fT04H8.js" + "_charts-DHgoott5.js" ], "css": [ - "assets/index-4EWIsBVv.css" + "assets/index-Ta4vyxDJ.css" ] } } \ No newline at end of file diff --git a/Cunkebao/dist/index.html b/Cunkebao/dist/index.html index dd832d12..1a1857e9 100644 --- a/Cunkebao/dist/index.html +++ b/Cunkebao/dist/index.html @@ -11,13 +11,13 @@ - + - + - + - +
diff --git a/Cunkebao/src/pages/mobile/workspace/auto-group/detail/index.tsx b/Cunkebao/src/pages/mobile/workspace/auto-group/detail/index.tsx index a0d88e7d..a82f5d73 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-group/detail/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/auto-group/detail/index.tsx @@ -1,17 +1,10 @@ import React, { useEffect, useState } from "react"; import { useParams, useNavigate } from "react-router-dom"; -import { - Card, - Button, - Toast, - ProgressBar, - Tag, - SpinLoading, -} from "antd-mobile"; +import { Card, Button, Toast, ProgressBar, Tag } from "antd-mobile"; import { TeamOutline, LeftOutline } from "antd-mobile-icons"; import { AlertOutlined } from "@ant-design/icons"; import Layout from "@/components/Layout/Layout"; -import MeauMobile from "@/components/MeauMobile/MeauMoible"; +import NavCommon from "@/components/NavCommon/index"; import style from "./index.module.scss"; interface GroupMember { @@ -280,37 +273,10 @@ const AutoGroupDetail: React.FC = () => { Toast.show({ content: "所有群组已创建完成" }); }; - if (loading) { - return ( - - -
建群详情
- - } - footer={} - loading={true} - > -
- - ); - } - if (!taskDetail) { return ( - -
建群详情
-
- } - footer={} + header={ navigate(-1)} />} > @@ -330,14 +296,12 @@ const AutoGroupDetail: React.FC = () => { return ( - -
{taskDetail.name} - 建群详情
- + navigate(-1)} + /> } - footer={} + loading={loading} >
diff --git a/Cunkebao/src/pages/mobile/workspace/auto-group/form/api.ts b/Cunkebao/src/pages/mobile/workspace/auto-group/form/api.ts index 811d1e56..68dc7135 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-group/form/api.ts +++ b/Cunkebao/src/pages/mobile/workspace/auto-group/form/api.ts @@ -1,11 +1,17 @@ import request from "@/api/request"; -// 新建自动建群任务 -export function createAutoGroup(data: any) { - return request("/api/auto-group/create", data, "POST"); -} +// 创建朋友圈同步任务 +export const createAutoGroup = (params: any) => + request("/v1/workbench/create", params, "POST"); -// 编辑自动建群任务 -export function updateAutoGroup(id: string, data: any) { - return request(`/api/auto-group/update/${id}`, data, "POST"); -} +// 更新朋友圈同步任务 +export const updateAutoGroup = (params: any) => + request("/v1/workbench/update", params, "POST"); + +// 获取朋友圈同步任务详情 +export const getAutoGroupDetail = (id: string) => + request("/v1/workbench/detail", { id }, "GET"); + +// 获取朋友圈同步任务列表 +export const getAutoGroupList = (params: any) => + request("/v1/workbench/list", params, "GET"); diff --git a/Cunkebao/src/pages/mobile/workspace/auto-group/form/index.module.scss b/Cunkebao/src/pages/mobile/workspace/auto-group/form/index.module.scss index 6a7bd15a..df8a4331 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-group/form/index.module.scss +++ b/Cunkebao/src/pages/mobile/workspace/auto-group/form/index.module.scss @@ -22,13 +22,4 @@ text-align: center; } -.timeRangeRow { - display: flex; - align-items: center; - gap: 8px; -} -.groupSizeRow { - display: flex; - align-items: center; - gap: 8px; -} + diff --git a/Cunkebao/src/pages/mobile/workspace/auto-group/form/index.tsx b/Cunkebao/src/pages/mobile/workspace/auto-group/form/index.tsx index 1e7dc78d..4b039b3a 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-group/form/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/auto-group/form/index.tsx @@ -1,45 +1,36 @@ import React, { useState, useEffect } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { - Form, - Input, - Button, - Toast, - Switch, - Selector, - TextArea, - NavBar, -} from "antd-mobile"; -import { ArrowLeftOutlined } from "@ant-design/icons"; +import { Form, Toast, TextArea } from "antd-mobile"; +import { Input, InputNumber, Button, Switch } from "antd"; import Layout from "@/components/Layout/Layout"; import style from "./index.module.scss"; import { createAutoGroup, updateAutoGroup } from "./api"; +import { AutoGroupFormData } from "./types"; +import DeviceSelection from "@/components/DeviceSelection/index"; +import NavCommon from "@/components/NavCommon/index"; +import dayjs from "dayjs"; +import { DeviceSelectionItem } from "@/components/DeviceSelection/data"; -const defaultForm = { +const defaultForm: AutoGroupFormData = { name: "", - deviceCount: 1, - targetFriends: 0, - createInterval: 300, - maxGroupsPerDay: 10, - timeRange: { start: "09:00", end: "21:00" }, - groupSize: { min: 20, max: 50 }, - targetTags: [], - groupNameTemplate: "VIP客户交流群{序号}", - groupDescription: "", + type: 4, + deveiceGroups: [], // 设备组 + deveiceGroupsOptions: [], // 设备组选项 + startTime: dayjs().format("HH:mm"), // 开始时间 (HH:mm) + endTime: dayjs().add(1, "hour").format("HH:mm"), // 结束时间 (HH:mm) + groupSizeMin: 20, // 群组最小人数 + groupSizeMax: 50, // 群组最大人数 + maxGroupsPerDay: 10, // 每日最大建群数 + groupNameTemplate: "VIP客户交流群{序号}", // 群名称模板 + groupDescription: "", // 群描述 + status: 1, // 是否启用 (1: 启用, 0: 禁用) }; -const tagOptions = [ - { label: "VIP客户", value: "VIP客户" }, - { label: "高价值", value: "高价值" }, - { label: "潜在客户", value: "潜在客户" }, - { label: "中意向", value: "中意向" }, -]; - const AutoGroupForm: React.FC = () => { const navigate = useNavigate(); const { id } = useParams(); const isEdit = Boolean(id); - const [form, setForm] = useState(defaultForm); + const [form, setForm] = useState(defaultForm); const [loading, setLoading] = useState(false); useEffect(() => { @@ -48,15 +39,15 @@ const AutoGroupForm: React.FC = () => { setForm({ ...defaultForm, name: "VIP客户建群", - deviceCount: 2, - targetFriends: 156, - createInterval: 300, + deveiceGroups: [], + startTime: dayjs().format("HH:mm"), + endTime: dayjs().add(1, "hour").format("HH:mm"), + groupSizeMin: 20, + groupSizeMax: 50, maxGroupsPerDay: 20, - timeRange: { start: "09:00", end: "21:00" }, - groupSize: { min: 20, max: 50 }, - targetTags: ["VIP客户", "高价值"], groupNameTemplate: "VIP客户交流群{序号}", groupDescription: "VIP客户专属交流群,提供优质服务", + status: 1, }); } }, [isEdit, id]); @@ -65,7 +56,7 @@ const AutoGroupForm: React.FC = () => { setLoading(true); try { if (isEdit) { - await updateAutoGroup(id as string, form); + await updateAutoGroup(form); Toast.show({ content: "编辑成功" }); } else { await createAutoGroup(form); @@ -79,25 +70,24 @@ const AutoGroupForm: React.FC = () => { } }; + const setTaskName = (val: string) => { + setForm((f: any) => ({ ...f, name: val })); + }; + const setDeviceGroups = (val: DeviceSelectionItem[]) => { + console.log(val); + setForm((f: any) => ({ + ...f, + deveiceGroups: val.map(item => item.id), + deveiceGroupsOptions: val, + })); + }; return ( - navigate(-1)} - /> -
- } - > - - {isEdit ? "编辑建群任务" : "新建建群任务"} - - + navigate(-1)} + /> } >
@@ -106,7 +96,7 @@ const AutoGroupForm: React.FC = () => { footer={ + + setForm((f: any) => ({ ...f, maxGroupsPerDay: val || 1 })) + } + placeholder="请输入最大建群数" + step={1} + style={{ flex: 1 }} + /> + +
+ + - setForm((f: any) => ({ ...f, maxGroupsPerDay: Number(val) })) - } - placeholder="请输入最大建群数" + type="time" + style={{ width: 120 }} + value={form.startTime || ""} + onChange={e => { + setForm((f: any) => ({ ...f, startTime: e.target.value })); + }} /> - -
- - setForm((f: any) => ({ - ...f, - timeRange: { ...f.timeRange, start: val }, - })) - } - placeholder="开始时间" - /> - - - - setForm((f: any) => ({ - ...f, - timeRange: { ...f.timeRange, end: val }, - })) - } - placeholder="结束时间" - /> -
-
- -
- - setForm((f: any) => ({ - ...f, - groupSize: { ...f.groupSize, min: Number(val) }, - })) - } - placeholder="最小人数" - /> - - - - setForm((f: any) => ({ - ...f, - groupSize: { ...f.groupSize, max: Number(val) }, - })) - } - placeholder="最大人数" - /> -
-
- - setForm((f: any) => ({ ...f, targetTags: val }))} + + { + setForm((f: any) => ({ ...f, endTime: e.target.value })); + }} /> + +
+ + { + const newValue = val || 1; + setForm((f: any) => ({ + ...f, + groupSizeMin: Math.min(newValue, f.groupSizeMax), + })); + }} + placeholder="请输入最小人数" + step={1} + style={{ flex: 1 }} + /> + +
+
+ +
+ + { + const newValue = val || 1; + setForm((f: any) => ({ + ...f, + groupSizeMax: Math.max(newValue, f.groupSizeMin), + })); + }} + placeholder="请输入最大人数" + step={1} + style={{ flex: 1 }} + /> + +
+
+ - setForm((f: any) => ({ ...f, groupNameTemplate: val })) + setForm((f: any) => ({ + ...f, + groupNameTemplate: val.target.value, + })) } placeholder="请输入群名称模板" /> @@ -242,6 +272,23 @@ const AutoGroupForm: React.FC = () => { showCount /> + +
+ 状态 + + setForm((f: any) => ({ ...f, status: checked ? 1 : 0 })) + } + /> +
+
diff --git a/Cunkebao/src/pages/mobile/workspace/auto-group/form/types.ts b/Cunkebao/src/pages/mobile/workspace/auto-group/form/types.ts new file mode 100644 index 00000000..82856afa --- /dev/null +++ b/Cunkebao/src/pages/mobile/workspace/auto-group/form/types.ts @@ -0,0 +1,53 @@ +import { DeviceSelectionItem } from "@/components/DeviceSelection/data"; +// 自动建群表单数据类型定义 +export interface AutoGroupFormData { + id?: string; // 任务ID + type: number; // 任务类型 + name: string; // 任务名称 + deveiceGroups: string[]; // 设备组 + deveiceGroupsOptions: DeviceSelectionItem[]; // 设备组选项 + startTime: string; // 开始时间 (YYYY-MM-DD HH:mm:ss) + endTime: string; // 结束时间 (YYYY-MM-DD HH:mm:ss) + groupSizeMin: number; // 群组最小人数 + groupSizeMax: number; // 群组最大人数 + maxGroupsPerDay: number; // 每日最大建群数 + groupNameTemplate: string; // 群名称模板 + groupDescription: string; // 群描述 + status: number; // 是否启用 (1: 启用, 0: 禁用) +} + +// 表单验证规则 +export const formValidationRules = { + name: [ + { required: true, message: "请输入任务名称" }, + { min: 2, max: 50, message: "任务名称长度应在2-50个字符之间" }, + ], + deveiceGroups: [ + { required: true, message: "请选择设备组" }, + { type: "array", min: 1, message: "至少选择一个设备组" }, + ], + startTime: [{ required: true, message: "请选择开始时间" }], + endTime: [{ required: true, message: "请选择结束时间" }], + groupSizeMin: [ + { required: true, message: "请输入群组最小人数" }, + { type: "number", min: 1, max: 500, message: "群组最小人数应在1-500之间" }, + ], + groupSizeMax: [ + { required: true, message: "请输入群组最大人数" }, + { type: "number", min: 1, max: 500, message: "群组最大人数应在1-500之间" }, + ], + maxGroupsPerDay: [ + { required: true, message: "请输入每日最大建群数" }, + { + type: "number", + min: 1, + max: 100, + message: "每日最大建群数应在1-100之间", + }, + ], + groupNameTemplate: [ + { required: true, message: "请输入群名称模板" }, + { min: 2, max: 100, message: "群名称模板长度应在2-100个字符之间" }, + ], + groupDescription: [{ max: 200, message: "群描述不能超过200个字符" }], +}; diff --git a/Cunkebao/src/pages/mobile/workspace/auto-group/list/index.tsx b/Cunkebao/src/pages/mobile/workspace/auto-group/list/index.tsx index 0d919b57..806a3553 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-group/list/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/auto-group/list/index.tsx @@ -1,7 +1,7 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { Button, Card, Popover, Toast } from "antd-mobile"; -import { Input, Switch } from "antd"; +import { Input, Switch, Pagination } from "antd"; import { MoreOutline, AddCircleOutline, @@ -14,7 +14,7 @@ import { PlusOutlined, SearchOutlined, } from "@ant-design/icons"; - +import { getAutoGroupList } from "../form/api"; import Layout from "@/components/Layout/Layout"; import style from "./index.module.scss"; import NavCommon from "@/components/NavCommon"; @@ -22,91 +22,92 @@ import NavCommon from "@/components/NavCommon"; interface GroupTask { id: string; name: string; - status: "running" | "paused" | "completed"; - deviceCount: number; - targetFriends: number; - createdGroups: number; - lastCreateTime: string; - createTime: string; - creator: string; - createInterval: number; - maxGroupsPerDay: number; - timeRange: { start: string; end: string }; - groupSize: { min: number; max: number }; - targetTags: string[]; - groupNameTemplate: string; - groupDescription: string; + status: number; // 1 开启, 0 关闭 + deviceCount?: number; + targetFriends?: number; + createdGroups?: number; + lastCreateTime?: string; + createTime?: string; + creator?: string; + createInterval?: number; + maxGroupsPerDay?: number; + timeRange?: { start: string; end: string }; + groupSize?: { min: number; max: number }; + targetTags?: string[]; + groupNameTemplate?: string; + groupDescription?: string; } -const mockTasks: GroupTask[] = [ - { - id: "1", - name: "VIP客户建群", - deviceCount: 2, - targetFriends: 156, - createdGroups: 12, - lastCreateTime: "2025-02-06 13:12:35", - createTime: "2024-11-20 19:04:14", - creator: "admin", - status: "running", - createInterval: 300, - maxGroupsPerDay: 20, - timeRange: { start: "09:00", end: "21:00" }, - groupSize: { min: 20, max: 50 }, - targetTags: ["VIP客户", "高价值"], - groupNameTemplate: "VIP客户交流群{序号}", - groupDescription: "VIP客户专属交流群,提供优质服务", - }, - { - id: "2", - name: "产品推广建群", - deviceCount: 1, - targetFriends: 89, - createdGroups: 8, - lastCreateTime: "2024-03-04 14:09:35", - createTime: "2024-03-04 14:29:04", - creator: "manager", - status: "paused", - createInterval: 600, - maxGroupsPerDay: 10, - timeRange: { start: "10:00", end: "20:00" }, - groupSize: { min: 15, max: 30 }, - targetTags: ["潜在客户", "中意向"], - groupNameTemplate: "产品推广群{序号}", - groupDescription: "产品推广交流群,了解最新产品信息", - }, -]; +// 初始空列表;真实数据由接口返回 +const mockTasks: GroupTask[] = []; -const getStatusColor = (status: string) => { +const getStatusColor = (status: number) => { switch (status) { - case "running": + case 1: return style.statusRunning; - case "paused": + case 0: return style.statusPaused; - case "completed": - return style.statusCompleted; default: return style.statusPaused; } }; -const getStatusText = (status: string) => { +const getStatusText = (status: number) => { switch (status) { - case "running": - return "进行中"; - case "paused": - return "已暂停"; - case "completed": - return "已完成"; + case 1: + return "开启"; + case 0: + return "关闭"; default: - return "未知"; + return "关闭"; } }; const AutoGroupList: React.FC = () => { const navigate = useNavigate(); const [searchTerm, setSearchTerm] = useState(""); - const [tasks, setTasks] = useState(mockTasks); + const [tasks, setTasks] = useState([]); + const [page, setPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [total, setTotal] = useState(0); + + const refreshTasks = async (p = page, ps = pageSize) => { + try { + const res: any = await getAutoGroupList({ type: 4, page: p, limit: ps }); + // 兼容不同返回结构 + const list = res?.list || res?.records || res?.data || []; + const totalCount = res?.total || res?.totalCount || list.length; + const normalized: GroupTask[] = (list as any[]).map(item => ({ + id: String(item.id), + name: item.name, + status: Number(item.status) === 1 ? 1 : 0, + deviceCount: Array.isArray(item.config?.devices) + ? item.config.devices.length + : 0, + maxGroupsPerDay: item.config?.maxGroupsPerDay ?? 0, + timeRange: { + start: item.config?.startTime ?? "-", + end: item.config?.endTime ?? "-", + }, + groupSize: { + min: item.config?.groupSizeMin ?? 0, + max: item.config?.groupSizeMax ?? 0, + }, + creator: item.creatorName ?? "", + createTime: item.createTime ?? "", + lastCreateTime: item.updateTime ?? "", + })); + setTasks(normalized); + setTotal(totalCount); + } catch (e) { + Toast.show({ content: "获取列表失败" }); + } + }; + + useEffect(() => { + refreshTasks(1, pageSize); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); const handleDelete = (taskId: string) => { const taskToDelete = tasks.find(task => task.id === taskId); @@ -144,7 +145,7 @@ const AutoGroupList: React.FC = () => { task.id === taskId ? { ...task, - status: task.status === "running" ? "paused" : "running", + status: task.status === 1 ? 0 : 1, } : task, ), @@ -187,7 +188,7 @@ const AutoGroupList: React.FC = () => {