feat: 本次提交更新内容如下
样式调整
This commit is contained in:
@@ -82,13 +82,12 @@ const Scene: React.FC = () => {
|
|||||||
<Layout
|
<Layout
|
||||||
header={
|
header={
|
||||||
<NavBar back={null} style={{ background: "#fff" }}>
|
<NavBar back={null} style={{ background: "#fff" }}>
|
||||||
<div className={style["nav-title"]}>场景获客</div>
|
<div className="nav-title">场景获客</div>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleNewPlan}
|
onClick={handleNewPlan}
|
||||||
className={style["new-plan-btn"]}
|
className="new-plan-btn"
|
||||||
style={{ marginLeft: "auto" }}
|
|
||||||
>
|
>
|
||||||
<PlusOutlined /> 新建计划
|
<PlusOutlined /> 新建计划
|
||||||
</Button>
|
</Button>
|
||||||
@@ -113,21 +112,19 @@ const Scene: React.FC = () => {
|
|||||||
<NavBar
|
<NavBar
|
||||||
back={null}
|
back={null}
|
||||||
style={{ background: "#fff" }}
|
style={{ background: "#fff" }}
|
||||||
left={<div className={style["nav-title"]}>场景获客</div>}
|
left={<div className="nav-title">场景获客</div>}
|
||||||
right={
|
right={
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleNewPlan}
|
onClick={handleNewPlan}
|
||||||
className={style["new-plan-btn"]}
|
className="new-plan-btn"
|
||||||
style={{ marginLeft: "auto" }}
|
|
||||||
>
|
>
|
||||||
<PlusOutlined /> 新建计划
|
<PlusOutlined /> 新建计划
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
></NavBar>
|
></NavBar>
|
||||||
}
|
}
|
||||||
footer={<MeauMobile />}
|
|
||||||
>
|
>
|
||||||
<div className={style["scene-page"]}>
|
<div className={style["scene-page"]}>
|
||||||
<div className={style["scenarios-grid"]}>
|
<div className={style["scenarios-grid"]}>
|
||||||
|
|||||||
@@ -2,18 +2,6 @@
|
|||||||
padding:0 16px;
|
padding:0 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-title {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-plan-btn {
|
|
||||||
font-size: 14px;
|
|
||||||
height: 32px;
|
|
||||||
padding: 0 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -356,8 +356,8 @@ const ScenarioList: React.FC = () => {
|
|||||||
back={null}
|
back={null}
|
||||||
style={{ background: "#fff" }}
|
style={{ background: "#fff" }}
|
||||||
left={
|
left={
|
||||||
<div className={style["nav-title"]}>
|
<div className="nav-title">
|
||||||
<span style={{ verticalAlign: "middle" }}>
|
<span className="nav-back-btn">
|
||||||
<LeftOutline onClick={() => navigate(-1)} fontSize={24} />
|
<LeftOutline onClick={() => navigate(-1)} fontSize={24} />
|
||||||
</span>
|
</span>
|
||||||
{scenarioName}
|
{scenarioName}
|
||||||
@@ -368,7 +368,7 @@ const ScenarioList: React.FC = () => {
|
|||||||
size="small"
|
size="small"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleCreateNewPlan}
|
onClick={handleCreateNewPlan}
|
||||||
className={style["new-plan-btn"]}
|
className="new-plan-btn"
|
||||||
>
|
>
|
||||||
<PlusOutlined /> 新建计划
|
<PlusOutlined /> 新建计划
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -248,41 +248,36 @@ const NewPlan: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<Layout
|
<Layout
|
||||||
header={
|
header={
|
||||||
<NavBar
|
<>
|
||||||
back={null}
|
<NavBar
|
||||||
style={{ background: "#fff" }}
|
back={null}
|
||||||
left={
|
style={{ background: "#fff" }}
|
||||||
<div className={style["nav-title"]}>
|
left={
|
||||||
{isEdit ? "编辑计划" : "新建计划"}
|
<div className="nav-title">
|
||||||
</div>
|
<span className="nav-back-btn">
|
||||||
}
|
<LeftOutline onClick={() => navigate(-1)} fontSize={24} />
|
||||||
right={
|
</span>
|
||||||
<Button
|
{isEdit ? "编辑计划" : "新建计划"}
|
||||||
size="small"
|
</div>
|
||||||
onClick={() => navigate(-1)}
|
}
|
||||||
className={style["back-btn"]}
|
/>
|
||||||
>
|
|
||||||
<LeftOutline />
|
{/* 步骤指示器 */}
|
||||||
</Button>
|
<div className={style["steps-container"]}>
|
||||||
}
|
<Steps current={currentStep - 1}>
|
||||||
/>
|
{steps.map((step) => (
|
||||||
|
<Steps.Step
|
||||||
|
key={step.id}
|
||||||
|
title={step.title}
|
||||||
|
description={step.subtitle}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Steps>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
footer={<MeauMobile />}
|
|
||||||
>
|
>
|
||||||
<div className={style["new-plan-page"]}>
|
<div className={style["new-plan-page"]}>
|
||||||
{/* 步骤指示器 */}
|
|
||||||
<div className={style["steps-container"]}>
|
|
||||||
<Steps current={currentStep - 1}>
|
|
||||||
{steps.map((step) => (
|
|
||||||
<Steps.Step
|
|
||||||
key={step.id}
|
|
||||||
title={step.title}
|
|
||||||
description={step.subtitle}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Steps>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 步骤内容 */}
|
{/* 步骤内容 */}
|
||||||
<div className={style["step-content"]}>{renderStepContent()}</div>
|
<div className={style["step-content"]}>{renderStepContent()}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
.new-plan-page {
|
.new-plan-page {
|
||||||
background: #f5f5f5;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-title {
|
.nav-title {
|
||||||
@@ -31,10 +29,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.steps-container {
|
.steps-container {
|
||||||
background: white;
|
background: #ffffff;
|
||||||
padding: 20px 16px;
|
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-content {
|
.step-content {
|
||||||
|
|||||||
@@ -1,3 +1,149 @@
|
|||||||
.autoGroupDetail {
|
.autoGroupDetail {
|
||||||
// 这里写详情页样式
|
padding: 16px 0 80px 0;
|
||||||
|
background: #f7f8fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerBar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 48px;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #222;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoCard {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
|
||||||
|
border: none;
|
||||||
|
background: #fff;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.infoGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.infoTitle {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1677ff;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.infoItem {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #444;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progressSection {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.progressCard {
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
|
||||||
|
border: none;
|
||||||
|
background: #fff;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.progressHeader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.groupList {
|
||||||
|
margin-top: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.groupCard {
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
|
||||||
|
border: none;
|
||||||
|
background: #fff;
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
.groupHeader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.memberGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.memberItem {
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #333;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.warnText {
|
||||||
|
color: #faad14;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.successText {
|
||||||
|
color: #389e0d;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.successAlert {
|
||||||
|
color: #389e0d;
|
||||||
|
background: #f6ffed;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 0;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.emptyCard {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 40px 0;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
.emptyTitle {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #888;
|
||||||
|
margin: 12px 0 4px 0;
|
||||||
|
}
|
||||||
|
.emptyDesc {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #bbb;
|
||||||
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,384 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { useParams, useNavigate } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
Button,
|
||||||
|
Toast,
|
||||||
|
ProgressBar,
|
||||||
|
Tag,
|
||||||
|
SpinLoading,
|
||||||
|
} 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 style from "./index.module.scss";
|
||||||
|
|
||||||
|
interface GroupMember {
|
||||||
|
id: string;
|
||||||
|
nickname: string;
|
||||||
|
wechatId: string;
|
||||||
|
tags: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Group {
|
||||||
|
id: string;
|
||||||
|
members: GroupMember[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GroupTaskDetail {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
status: "preparing" | "creating" | "completed" | "paused";
|
||||||
|
totalGroups: number;
|
||||||
|
currentGroupIndex: number;
|
||||||
|
groups: Group[];
|
||||||
|
createTime: string;
|
||||||
|
lastUpdateTime: string;
|
||||||
|
creator: string;
|
||||||
|
deviceCount: number;
|
||||||
|
targetFriends: number;
|
||||||
|
groupSize: { min: number; max: number };
|
||||||
|
timeRange: { start: string; end: string };
|
||||||
|
targetTags: string[];
|
||||||
|
groupNameTemplate: string;
|
||||||
|
groupDescription: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockTaskDetail: GroupTaskDetail = {
|
||||||
|
id: "1",
|
||||||
|
name: "VIP客户建群",
|
||||||
|
status: "creating",
|
||||||
|
totalGroups: 5,
|
||||||
|
currentGroupIndex: 2,
|
||||||
|
groups: Array.from({ length: 5 }).map((_, index) => ({
|
||||||
|
id: `group-${index}`,
|
||||||
|
members: Array.from({ length: Math.floor(Math.random() * 10) + 30 }).map(
|
||||||
|
(_, mIndex) => ({
|
||||||
|
id: `member-${index}-${mIndex}`,
|
||||||
|
nickname: `用户${mIndex + 1}`,
|
||||||
|
wechatId: `wx_${mIndex}`,
|
||||||
|
tags: [`标签${(mIndex % 3) + 1}`],
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
createTime: "2024-11-20 19:04:14",
|
||||||
|
lastUpdateTime: "2025-02-06 13:12:35",
|
||||||
|
creator: "admin",
|
||||||
|
deviceCount: 2,
|
||||||
|
targetFriends: 156,
|
||||||
|
groupSize: { min: 20, max: 50 },
|
||||||
|
timeRange: { start: "09:00", end: "21:00" },
|
||||||
|
targetTags: ["VIP客户", "高价值"],
|
||||||
|
groupNameTemplate: "VIP客户交流群{序号}",
|
||||||
|
groupDescription: "VIP客户专属交流群,提供优质服务",
|
||||||
|
};
|
||||||
|
|
||||||
|
const GroupPreview: React.FC<{
|
||||||
|
groupIndex: number;
|
||||||
|
members: GroupMember[];
|
||||||
|
isCreating: boolean;
|
||||||
|
isCompleted: boolean;
|
||||||
|
onRetry?: () => void;
|
||||||
|
}> = ({ groupIndex, members, isCreating, isCompleted, onRetry }) => {
|
||||||
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
const targetSize = 38;
|
||||||
|
return (
|
||||||
|
<Card className={style.groupCard}>
|
||||||
|
<div className={style.groupHeader}>
|
||||||
|
<div>
|
||||||
|
群 {groupIndex + 1}
|
||||||
|
<Tag
|
||||||
|
color={isCompleted ? "success" : isCreating ? "warning" : "default"}
|
||||||
|
style={{ marginLeft: 8 }}
|
||||||
|
>
|
||||||
|
{isCompleted ? "已完成" : isCreating ? "创建中" : "等待中"}
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
<div style={{ color: "#888", fontSize: 12 }}>
|
||||||
|
<TeamOutline style={{ marginRight: 4 }} />
|
||||||
|
{members.length}/{targetSize}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{isCreating && !isCompleted && (
|
||||||
|
<ProgressBar
|
||||||
|
percent={Math.round((members.length / targetSize) * 100)}
|
||||||
|
style={{ margin: "8px 0" }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{expanded ? (
|
||||||
|
<>
|
||||||
|
<div className={style.memberGrid}>
|
||||||
|
{members.map((member) => (
|
||||||
|
<div key={member.id} className={style.memberItem}>
|
||||||
|
<span>{member.nickname}</span>
|
||||||
|
{member.tags.length > 0 && (
|
||||||
|
<Tag color="primary" style={{ marginLeft: 4 }}>
|
||||||
|
{member.tags[0]}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
size="mini"
|
||||||
|
fill="none"
|
||||||
|
block
|
||||||
|
onClick={() => setExpanded(false)}
|
||||||
|
style={{ marginTop: 8 }}
|
||||||
|
>
|
||||||
|
收起
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
size="mini"
|
||||||
|
fill="none"
|
||||||
|
block
|
||||||
|
onClick={() => setExpanded(true)}
|
||||||
|
style={{ marginTop: 8 }}
|
||||||
|
>
|
||||||
|
查看成员 ({members.length})
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{!isCompleted && members.length < targetSize && (
|
||||||
|
<div className={style.warnText}>
|
||||||
|
<AlertOutlined style={{ marginRight: 4 }} />
|
||||||
|
群人数不足{targetSize}人
|
||||||
|
{onRetry && (
|
||||||
|
<Button
|
||||||
|
size="mini"
|
||||||
|
fill="none"
|
||||||
|
color="primary"
|
||||||
|
style={{ marginLeft: 8 }}
|
||||||
|
onClick={onRetry}
|
||||||
|
>
|
||||||
|
继续拉人
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isCompleted && <div className={style.successText}>群创建完成</div>}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const GroupCreationProgress: React.FC<{
|
||||||
|
taskDetail: GroupTaskDetail;
|
||||||
|
onComplete: () => void;
|
||||||
|
}> = ({ taskDetail, onComplete }) => {
|
||||||
|
const [groups, setGroups] = useState<Group[]>(taskDetail.groups);
|
||||||
|
const [currentGroupIndex, setCurrentGroupIndex] = useState(
|
||||||
|
taskDetail.currentGroupIndex
|
||||||
|
);
|
||||||
|
const [status, setStatus] = useState<GroupTaskDetail["status"]>(
|
||||||
|
taskDetail.status
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (status === "creating" && currentGroupIndex < groups.length) {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
if (currentGroupIndex === groups.length - 1) {
|
||||||
|
setStatus("completed");
|
||||||
|
onComplete();
|
||||||
|
} else {
|
||||||
|
setCurrentGroupIndex((prev) => prev + 1);
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}
|
||||||
|
}, [status, currentGroupIndex, groups.length, onComplete]);
|
||||||
|
|
||||||
|
const handleRetryGroup = (groupIndex: number) => {
|
||||||
|
setGroups((prev) =>
|
||||||
|
prev.map((group, index) => {
|
||||||
|
if (index === groupIndex) {
|
||||||
|
return {
|
||||||
|
...group,
|
||||||
|
members: [
|
||||||
|
...group.members,
|
||||||
|
{
|
||||||
|
id: `retry-member-${Date.now()}`,
|
||||||
|
nickname: `补充用户${group.members.length + 1}`,
|
||||||
|
wechatId: `wx_retry_${Date.now()}`,
|
||||||
|
tags: ["新加入"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={style.progressSection}>
|
||||||
|
<Card className={style.progressCard}>
|
||||||
|
<div className={style.progressHeader}>
|
||||||
|
<div>
|
||||||
|
建群进度
|
||||||
|
<Tag
|
||||||
|
color={
|
||||||
|
status === "completed"
|
||||||
|
? "success"
|
||||||
|
: status === "creating"
|
||||||
|
? "warning"
|
||||||
|
: "default"
|
||||||
|
}
|
||||||
|
style={{ marginLeft: 8 }}
|
||||||
|
>
|
||||||
|
{status === "preparing"
|
||||||
|
? "准备中"
|
||||||
|
: status === "creating"
|
||||||
|
? "创建中"
|
||||||
|
: "已完成"}
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
<div style={{ color: "#888", fontSize: 12 }}>
|
||||||
|
{currentGroupIndex + 1}/{groups.length}组
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ProgressBar
|
||||||
|
percent={Math.round(((currentGroupIndex + 1) / groups.length) * 100)}
|
||||||
|
style={{ marginTop: 8 }}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
<div className={style.groupList}>
|
||||||
|
{groups.map((group, index) => (
|
||||||
|
<GroupPreview
|
||||||
|
key={group.id}
|
||||||
|
groupIndex={index}
|
||||||
|
members={group.members}
|
||||||
|
isCreating={status === "creating" && index === currentGroupIndex}
|
||||||
|
isCompleted={status === "completed" || index < currentGroupIndex}
|
||||||
|
onRetry={() => handleRetryGroup(index)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{status === "completed" && (
|
||||||
|
<div className={style.successAlert}>所有群组已创建完成</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const AutoGroupDetail: React.FC = () => {
|
const AutoGroupDetail: React.FC = () => {
|
||||||
return <div>自动建群详情页</div>;
|
const { id } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [taskDetail, setTaskDetail] = useState<GroupTaskDetail | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setTaskDetail(mockTaskDetail);
|
||||||
|
setLoading(false);
|
||||||
|
}, 800);
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
const handleComplete = () => {
|
||||||
|
Toast.show({ content: "所有群组已创建完成" });
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Layout
|
||||||
|
header={
|
||||||
|
<div className={style.headerBar}>
|
||||||
|
<Button fill="none" size="small" onClick={() => navigate(-1)}>
|
||||||
|
<LeftOutline />
|
||||||
|
</Button>
|
||||||
|
<div className={style.title}>建群详情</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
footer={<MeauMobile />}
|
||||||
|
loading={true}
|
||||||
|
>
|
||||||
|
<div style={{ minHeight: 300 }} />
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!taskDetail) {
|
||||||
|
return (
|
||||||
|
<Layout
|
||||||
|
header={
|
||||||
|
<div className={style.headerBar}>
|
||||||
|
<Button fill="none" size="small" onClick={() => navigate(-1)}>
|
||||||
|
<LeftOutline />
|
||||||
|
</Button>
|
||||||
|
<div className={style.title}>建群详情</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
footer={<MeauMobile />}
|
||||||
|
>
|
||||||
|
<Card className={style.emptyCard}>
|
||||||
|
<AlertOutlined style={{ fontSize: 48, color: "#ccc" }} />
|
||||||
|
<div className={style.emptyTitle}>任务不存在</div>
|
||||||
|
<div className={style.emptyDesc}>请检查任务ID是否正确</div>
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
onClick={() => navigate("/workspace/auto-group")}
|
||||||
|
>
|
||||||
|
返回列表
|
||||||
|
</Button>
|
||||||
|
</Card>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout
|
||||||
|
header={
|
||||||
|
<div className={style.headerBar}>
|
||||||
|
<Button fill="none" size="small" onClick={() => navigate(-1)}>
|
||||||
|
<LeftOutline />
|
||||||
|
</Button>
|
||||||
|
<div className={style.title}>{taskDetail.name} - 建群详情</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
footer={<MeauMobile />}
|
||||||
|
>
|
||||||
|
<div className={style.autoGroupDetail}>
|
||||||
|
<Card className={style.infoCard}>
|
||||||
|
<div className={style.infoGrid}>
|
||||||
|
<div>
|
||||||
|
<div className={style.infoTitle}>基本信息</div>
|
||||||
|
<div className={style.infoItem}>任务名称:{taskDetail.name}</div>
|
||||||
|
<div className={style.infoItem}>
|
||||||
|
创建时间:{taskDetail.createTime}
|
||||||
|
</div>
|
||||||
|
<div className={style.infoItem}>创建人:{taskDetail.creator}</div>
|
||||||
|
<div className={style.infoItem}>
|
||||||
|
执行设备:{taskDetail.deviceCount} 个
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className={style.infoTitle}>建群配置</div>
|
||||||
|
<div className={style.infoItem}>
|
||||||
|
群组规模:{taskDetail.groupSize.min}-{taskDetail.groupSize.max}{" "}
|
||||||
|
人
|
||||||
|
</div>
|
||||||
|
<div className={style.infoItem}>
|
||||||
|
执行时间:{taskDetail.timeRange.start} -{" "}
|
||||||
|
{taskDetail.timeRange.end}
|
||||||
|
</div>
|
||||||
|
<div className={style.infoItem}>
|
||||||
|
目标标签:{taskDetail.targetTags.join(", ")}
|
||||||
|
</div>
|
||||||
|
<div className={style.infoItem}>
|
||||||
|
群名称模板:{taskDetail.groupNameTemplate}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
<GroupCreationProgress
|
||||||
|
taskDetail={taskDetail}
|
||||||
|
onComplete={handleComplete}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AutoGroupDetail;
|
export default AutoGroupDetail;
|
||||||
|
|||||||
@@ -1,3 +1,34 @@
|
|||||||
.autoGroupForm {
|
.autoGroupForm {
|
||||||
// 这里写新建/编辑页样式
|
padding: 10px;
|
||||||
|
background: #f7f8fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerBar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 48px;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #222;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeRangeRow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.groupSizeRow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,245 @@
|
|||||||
import React from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
Button,
|
||||||
|
Toast,
|
||||||
|
Switch,
|
||||||
|
Selector,
|
||||||
|
TextArea,
|
||||||
|
} from "antd-mobile";
|
||||||
|
import { LeftOutline } from "antd-mobile-icons";
|
||||||
|
import Layout from "@/components/Layout/Layout";
|
||||||
|
import MeauMobile from "@/components/MeauMobile/MeauMoible";
|
||||||
|
import style from "./index.module.scss";
|
||||||
|
import { createAutoGroup, updateAutoGroup } from "./api";
|
||||||
|
|
||||||
|
const defaultForm = {
|
||||||
|
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: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
const tagOptions = [
|
||||||
|
{ label: "VIP客户", value: "VIP客户" },
|
||||||
|
{ label: "高价值", value: "高价值" },
|
||||||
|
{ label: "潜在客户", value: "潜在客户" },
|
||||||
|
{ label: "中意向", value: "中意向" },
|
||||||
|
];
|
||||||
|
|
||||||
const AutoGroupForm: React.FC = () => {
|
const AutoGroupForm: React.FC = () => {
|
||||||
return <div>自动建群新建/编辑页</div>;
|
const navigate = useNavigate();
|
||||||
|
const { id } = useParams();
|
||||||
|
const isEdit = Boolean(id);
|
||||||
|
const [form, setForm] = useState<any>(defaultForm);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEdit) {
|
||||||
|
// 这里应请求详情接口,回填表单,演示用mock
|
||||||
|
setForm({
|
||||||
|
...defaultForm,
|
||||||
|
name: "VIP客户建群",
|
||||||
|
deviceCount: 2,
|
||||||
|
targetFriends: 156,
|
||||||
|
createInterval: 300,
|
||||||
|
maxGroupsPerDay: 20,
|
||||||
|
timeRange: { start: "09:00", end: "21:00" },
|
||||||
|
groupSize: { min: 20, max: 50 },
|
||||||
|
targetTags: ["VIP客户", "高价值"],
|
||||||
|
groupNameTemplate: "VIP客户交流群{序号}",
|
||||||
|
groupDescription: "VIP客户专属交流群,提供优质服务",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isEdit, id]);
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
if (isEdit) {
|
||||||
|
await updateAutoGroup(id as string, form);
|
||||||
|
Toast.show({ content: "编辑成功" });
|
||||||
|
} else {
|
||||||
|
await createAutoGroup(form);
|
||||||
|
Toast.show({ content: "创建成功" });
|
||||||
|
}
|
||||||
|
navigate("/workspace/auto-group");
|
||||||
|
} catch (e) {
|
||||||
|
Toast.show({ content: "提交失败" });
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout
|
||||||
|
header={
|
||||||
|
<div className={style.headerBar}>
|
||||||
|
<Button fill="none" size="small" onClick={() => navigate(-1)}>
|
||||||
|
<LeftOutline />
|
||||||
|
</Button>
|
||||||
|
<div className={style.title}>
|
||||||
|
{isEdit ? "编辑建群任务" : "新建建群任务"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className={style.autoGroupForm}>
|
||||||
|
<Form
|
||||||
|
layout="vertical"
|
||||||
|
footer={
|
||||||
|
<Button
|
||||||
|
block
|
||||||
|
color="primary"
|
||||||
|
loading={loading}
|
||||||
|
onClick={handleSubmit}
|
||||||
|
>
|
||||||
|
{isEdit ? "保存修改" : "创建任务"}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Form.Item label="任务名称" name="name" required>
|
||||||
|
<Input
|
||||||
|
value={form.name}
|
||||||
|
onChange={(val) => setForm((f: any) => ({ ...f, name: val }))}
|
||||||
|
placeholder="请输入任务名称"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="执行设备数量" name="deviceCount" required>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={form.deviceCount}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({ ...f, deviceCount: Number(val) }))
|
||||||
|
}
|
||||||
|
placeholder="请输入设备数量"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="目标好友数" name="targetFriends" required>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={form.targetFriends}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({ ...f, targetFriends: Number(val) }))
|
||||||
|
}
|
||||||
|
placeholder="请输入目标好友数"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="建群间隔(秒)" name="createInterval" required>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={form.createInterval}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({ ...f, createInterval: Number(val) }))
|
||||||
|
}
|
||||||
|
placeholder="请输入建群间隔"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="每日最大建群数" name="maxGroupsPerDay" required>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={form.maxGroupsPerDay}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({ ...f, maxGroupsPerDay: Number(val) }))
|
||||||
|
}
|
||||||
|
placeholder="请输入最大建群数"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="执行时间段" name="timeRange" required>
|
||||||
|
<div className={style.timeRangeRow}>
|
||||||
|
<Input
|
||||||
|
value={form.timeRange.start}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({
|
||||||
|
...f,
|
||||||
|
timeRange: { ...f.timeRange, start: val },
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder="开始时间"
|
||||||
|
/>
|
||||||
|
<span style={{ margin: "0 8px" }}>-</span>
|
||||||
|
<Input
|
||||||
|
value={form.timeRange.end}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({
|
||||||
|
...f,
|
||||||
|
timeRange: { ...f.timeRange, end: val },
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder="结束时间"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="群组规模" name="groupSize" required>
|
||||||
|
<div className={style.groupSizeRow}>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={form.groupSize.min}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({
|
||||||
|
...f,
|
||||||
|
groupSize: { ...f.groupSize, min: Number(val) },
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder="最小人数"
|
||||||
|
/>
|
||||||
|
<span style={{ margin: "0 8px" }}>-</span>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={form.groupSize.max}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({
|
||||||
|
...f,
|
||||||
|
groupSize: { ...f.groupSize, max: Number(val) },
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder="最大人数"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="目标标签" name="targetTags">
|
||||||
|
<Selector
|
||||||
|
options={tagOptions}
|
||||||
|
multiple
|
||||||
|
value={form.targetTags}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({ ...f, targetTags: val }))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="群名称模板" name="groupNameTemplate" required>
|
||||||
|
<Input
|
||||||
|
value={form.groupNameTemplate}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({ ...f, groupNameTemplate: val }))
|
||||||
|
}
|
||||||
|
placeholder="请输入群名称模板"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="群描述" name="groupDescription">
|
||||||
|
<TextArea
|
||||||
|
value={form.groupDescription}
|
||||||
|
onChange={(val) =>
|
||||||
|
setForm((f: any) => ({ ...f, groupDescription: val }))
|
||||||
|
}
|
||||||
|
placeholder="请输入群描述"
|
||||||
|
rows={3}
|
||||||
|
maxLength={100}
|
||||||
|
showCount
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AutoGroupForm;
|
export default AutoGroupForm;
|
||||||
|
|||||||
@@ -1,3 +1,203 @@
|
|||||||
.autoGroupList {
|
.autoGroupList {
|
||||||
// 这里写列表页样式
|
padding: 16px 0 80px 0;
|
||||||
|
background: #f7f8fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerBar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 16px;
|
||||||
|
height: 48px;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchBar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 16px 0 16px;
|
||||||
|
background: #fff;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskList {
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskCard {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
|
||||||
|
border: none;
|
||||||
|
background: #fff;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskHeader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskTitle {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusRunning {
|
||||||
|
background: #e6f7e6;
|
||||||
|
color: #389e0d;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
.statusPaused {
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #888;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
.statusCompleted {
|
||||||
|
background: #e6f4ff;
|
||||||
|
color: #1677ff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskInfoGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 8px 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.infoLabel {
|
||||||
|
color: #888;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.infoValue {
|
||||||
|
color: #222;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskFooter {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
padding-top: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.footerLeft {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.footerRight {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expandPanel {
|
||||||
|
margin-top: 16px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px dashed #e0e0e0;
|
||||||
|
}
|
||||||
|
.expandGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.expandTitle {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: #1677ff;
|
||||||
|
}
|
||||||
|
.expandInfo {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #444;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.expandTags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.tag {
|
||||||
|
background: #f0f5ff;
|
||||||
|
color: #1677ff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuItem {
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #222;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
.menuItem:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.menuItemDanger {
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #e53e3e;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
.menuItemDanger:hover {
|
||||||
|
background: #fff1f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emptyCard {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 40px 0;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
.emptyTitle {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #888;
|
||||||
|
margin: 12px 0 4px 0;
|
||||||
|
}
|
||||||
|
.emptyDesc {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #bbb;
|
||||||
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,6 @@ const AutoGroupList: React.FC = () => {
|
|||||||
placeholder="搜索任务名称"
|
placeholder="搜索任务名称"
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(val) => setSearchTerm(val)}
|
onChange={(val) => setSearchTerm(val)}
|
||||||
prefix={<SearchOutline />}
|
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
<Button size="small" fill="outline" style={{ marginLeft: 8 }}>
|
<Button size="small" fill="outline" style={{ marginLeft: 8 }}>
|
||||||
|
|||||||
@@ -123,12 +123,46 @@ input, textarea {
|
|||||||
body, input, textarea, select, button {
|
body, input, textarea, select, button {
|
||||||
touch-action: manipulation;
|
touch-action: manipulation;
|
||||||
}
|
}
|
||||||
//导航左右结构的样式
|
// 导航栏样式
|
||||||
|
.nav-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-text {
|
||||||
|
color: var(--primary-color);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-back-btn{
|
||||||
|
color: #333;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-left {
|
.nav-left {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-right {
|
.nav-right {
|
||||||
|
margin-left: 4px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.new-plan-btn {
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
height: 32px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
border: none;
|
||||||
|
box-shadow: 0 2px 8px var(--primary-shadow);
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(1px);
|
||||||
|
box-shadow: 0 1px 4px var(--primary-shadow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user