feat: 本次提交更新内容如下
样式和功能补齐
This commit is contained in:
@@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react';
|
|||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Search, RefreshCw, Loader2 } from 'lucide-react';
|
import { Search, RefreshCw, Loader2 } from 'lucide-react';
|
||||||
import { fetchContentLibraryList } from '@/api/content';
|
import { fetchContentLibraryList } from '@/api/content';
|
||||||
import { ContentLibrary } from '@/api/content';
|
import { ContentLibrary } from '@/api/content';
|
||||||
@@ -50,7 +50,7 @@ export function ContentLibrarySelectionDialog({
|
|||||||
fetchLibraries();
|
fetchLibraries();
|
||||||
setTempSelected(selectedLibraries);
|
setTempSelected(selectedLibraries);
|
||||||
}
|
}
|
||||||
}, [open, searchQuery, selectedLibraries, fetchLibraries]);
|
}, [open, selectedLibraries, fetchLibraries]);
|
||||||
|
|
||||||
const handleRefresh = () => {
|
const handleRefresh = () => {
|
||||||
fetchLibraries();
|
fetchLibraries();
|
||||||
@@ -86,7 +86,7 @@ export function ContentLibrarySelectionDialog({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={handleDialogOpenChange}>
|
<Dialog open={open} onOpenChange={handleDialogOpenChange}>
|
||||||
<DialogContent className="max-w-2xl max-h-[80vh] flex flex-col">
|
<DialogContent className="flex flex-col">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>选择内容库</DialogTitle>
|
<DialogTitle>选择内容库</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
@@ -136,17 +136,24 @@ export function ContentLibrarySelectionDialog({
|
|||||||
libraries.map((library) => (
|
libraries.map((library) => (
|
||||||
<label
|
<label
|
||||||
key={library.id}
|
key={library.id}
|
||||||
className="flex items-center justify-between p-4 rounded-lg border hover:bg-gray-50 cursor-pointer"
|
className="flex items-start space-x-3 p-4 rounded-lg hover:bg-gray-50 cursor-pointer border"
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-3 flex-1 min-w-0 pr-4">
|
<input
|
||||||
<Checkbox
|
type="checkbox"
|
||||||
checked={tempSelected.includes(library.id)}
|
checked={tempSelected.includes(library.id)}
|
||||||
onCheckedChange={() => handleLibraryToggle(library.id)}
|
onChange={() => handleLibraryToggle(library.id)}
|
||||||
/>
|
className="mt-1 w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 focus:ring-2"
|
||||||
<div className="min-w-0 flex-1">
|
/>
|
||||||
<div className="font-medium truncate mb-1">{library.name}</div>
|
<div className="flex-1">
|
||||||
<div className="text-sm text-gray-500 truncate mb-1">创建人:{library.creatorName}</div>
|
<div className="flex items-center justify-between">
|
||||||
<div className="text-sm text-gray-500 truncate">更新时间:{new Date(library.updateTime).toLocaleString()}</div>
|
<span className="font-medium">{library.name}</span>
|
||||||
|
<Badge variant="outline">
|
||||||
|
{library.sourceType === 1 ? '文本' : library.sourceType === 2 ? '图片' : '视频'}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-gray-500 mt-1">
|
||||||
|
<div>创建人: {library.creatorName || '-'}</div>
|
||||||
|
<div>更新时间: {new Date(library.updateTime).toLocaleString()}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ export default function MomentsSyncDetail() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-gray-600">创建人</span>
|
<span className="text-gray-600">创建人</span>
|
||||||
<span className="font-medium">{task.creator}</span>
|
<span className="font-medium">{task.creatorName}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export default function MomentsSync() {
|
|||||||
deviceCount: task.deviceCount || 0,
|
deviceCount: task.deviceCount || 0,
|
||||||
targetGroup: task.targetGroup || '默认人群',
|
targetGroup: task.targetGroup || '默认人群',
|
||||||
syncCount: task.todaySyncCount || task.syncCount || 0,
|
syncCount: task.todaySyncCount || task.syncCount || 0,
|
||||||
creator: task.creator || '未知',
|
creatorName: task.creatorName || '未知',
|
||||||
lastSyncTime: task.lastSyncTime || '暂无',
|
lastSyncTime: task.lastSyncTime || '暂无',
|
||||||
createTime: task.createTime || '未知',
|
createTime: task.createTime || '未知',
|
||||||
syncInterval: task.syncInterval || 30,
|
syncInterval: task.syncInterval || 30,
|
||||||
@@ -117,7 +117,7 @@ export default function MomentsSync() {
|
|||||||
targetTags: task.targetTags || [],
|
targetTags: task.targetTags || [],
|
||||||
syncMode: task.syncMode || 'auto',
|
syncMode: task.syncMode || 'auto',
|
||||||
filterKeywords: task.filterKeywords || [],
|
filterKeywords: task.filterKeywords || [],
|
||||||
contentLib: task.contentLib || '默认内容库'
|
contentLib: task.config?.contentLibraryNames?.join(',') || '默认内容库'
|
||||||
}));
|
}));
|
||||||
setTasks(mappedTasks);
|
setTasks(mappedTasks);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -301,11 +301,16 @@ export default function MomentsSync() {
|
|||||||
<div className="grid grid-cols-2 gap-4 mb-4">
|
<div className="grid grid-cols-2 gap-4 mb-4">
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-gray-500">
|
||||||
<div>推送设备:{task.deviceCount} 个</div>
|
<div>推送设备:{task.deviceCount} 个</div>
|
||||||
<div>内容库:{task.contentLib || '默认内容库'}</div>
|
<div className="flex">
|
||||||
|
<span className="flex-shrink-0">内容库:</span>
|
||||||
|
<span className="truncate" title={task.contentLib || '默认内容库'}>
|
||||||
|
{task.contentLib || '默认内容库'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-gray-500">
|
||||||
<div>已同步:{task.syncCount} 条</div>
|
<div>已同步:{task.syncCount} 条</div>
|
||||||
<div>创建人:{task.creator}</div>
|
<div>创建人:{task.creatorName}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -23,19 +23,38 @@ function StepIndicator({ currentStep }: StepIndicatorProps) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-between px-6 mb-8">
|
<div className="relative flex justify-between px-6 mb-8">
|
||||||
|
{/* 连线 - 背景线 */}
|
||||||
|
<div className="absolute top-5 left-0 right-0 h-[1px] bg-gray-200" style={{ width: '100%', zIndex: 0 }} />
|
||||||
|
|
||||||
|
{/* 连线 - 已完成线 */}
|
||||||
|
<div
|
||||||
|
className="absolute top-5 left-0 h-[1px] bg-blue-600 transition-all duration-300"
|
||||||
|
style={{
|
||||||
|
width: `${((currentStep - 1) / (steps.length - 1)) * 100}%`,
|
||||||
|
zIndex: 1
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 步骤圆圈 */}
|
||||||
{steps.map((step, index) => (
|
{steps.map((step, index) => (
|
||||||
<div key={step.id} className="flex flex-col items-center">
|
<div key={step.id} className="flex flex-col items-center relative z-10">
|
||||||
<div
|
<div
|
||||||
className={`w-10 h-10 rounded-full flex items-center justify-center mb-2 ${
|
className={`w-10 h-10 rounded-full flex items-center justify-center mb-2 ${
|
||||||
currentStep === index + 1
|
currentStep === index + 1
|
||||||
? "bg-blue-600 text-white"
|
? "bg-blue-600 text-white"
|
||||||
: "bg-white text-gray-400 border border-gray-200"
|
: index + 1 < currentStep
|
||||||
|
? "bg-blue-600 text-white"
|
||||||
|
: "bg-white text-gray-400 border border-gray-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{index + 1}
|
{index + 1}
|
||||||
</div>
|
</div>
|
||||||
<div className={`text-sm ${currentStep === index + 1 ? "text-blue-600" : "text-gray-400"}`}>
|
<div className={`text-sm ${
|
||||||
|
currentStep === index + 1 || index + 1 < currentStep
|
||||||
|
? "text-blue-600"
|
||||||
|
: "text-gray-400"
|
||||||
|
}`}>
|
||||||
{step.title}
|
{step.title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, ChangeEvent } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
ChevronLeft,
|
ChevronLeft,
|
||||||
@@ -92,7 +92,7 @@ function StepIndicator({ currentStep, steps }: StepIndicatorProps) {
|
|||||||
return (
|
return (
|
||||||
<div className="w-full mb-6 px-12">
|
<div className="w-full mb-6 px-12">
|
||||||
<Steps current={currentStep} layout="horizontal">
|
<Steps current={currentStep} layout="horizontal">
|
||||||
{steps.map((step, index) => (
|
{steps.map((step, index) => (
|
||||||
<StepItem
|
<StepItem
|
||||||
key={step.id}
|
key={step.id}
|
||||||
title={step.title}
|
title={step.title}
|
||||||
@@ -102,7 +102,7 @@ function StepIndicator({ currentStep, steps }: StepIndicatorProps) {
|
|||||||
index < currentStep ? 'finish' : 'default'
|
index < currentStep ? 'finish' : 'default'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Steps>
|
</Steps>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import React, { useState, useEffect, useRef } from 'react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
Plus,
|
Plus,
|
||||||
Filter,
|
|
||||||
Search,
|
Search,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
MoreVertical,
|
MoreVertical,
|
||||||
@@ -12,7 +11,6 @@ import {
|
|||||||
Pause,
|
Pause,
|
||||||
Play,
|
Play,
|
||||||
Users,
|
Users,
|
||||||
Share2,
|
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Card } from '@/components/ui/card';
|
import { Card } from '@/components/ui/card';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@@ -85,6 +83,8 @@ export default function TrafficDistribution() {
|
|||||||
navigate(`/workspace/traffic-distribution/${ruleId}`);
|
navigate(`/workspace/traffic-distribution/${ruleId}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 注释掉未使用的函数
|
||||||
|
/*
|
||||||
const handleCopy = async (ruleId: string) => {
|
const handleCopy = async (ruleId: string) => {
|
||||||
const ruleToCopy = tasks.find((rule) => rule.id === ruleId);
|
const ruleToCopy = tasks.find((rule) => rule.id === ruleId);
|
||||||
if (ruleToCopy) {
|
if (ruleToCopy) {
|
||||||
@@ -106,6 +106,7 @@ export default function TrafficDistribution() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
const toggleRuleStatus = async (ruleId: string) => {
|
const toggleRuleStatus = async (ruleId: string) => {
|
||||||
const rule = tasks.find((r) => r.id === ruleId);
|
const rule = tasks.find((r) => r.id === ruleId);
|
||||||
@@ -284,7 +285,7 @@ export default function TrafficDistribution() {
|
|||||||
// 初始加载和搜索
|
// 初始加载和搜索
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData(1, searchTerm);
|
fetchData(1, searchTerm);
|
||||||
}, []);
|
}, [searchTerm]); // 添加依赖项
|
||||||
|
|
||||||
// 处理搜索
|
// 处理搜索
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ export type ContentType = 'text' | 'image' | 'video' | 'link';
|
|||||||
// 同步模式
|
// 同步模式
|
||||||
export type SyncMode = 'auto' | 'manual';
|
export type SyncMode = 'auto' | 'manual';
|
||||||
|
|
||||||
|
// 配置信息
|
||||||
|
export interface MomentsSyncConfig {
|
||||||
|
contentLibraryNames: string[];
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
// 朋友圈同步任务
|
// 朋友圈同步任务
|
||||||
export interface MomentsSyncTask {
|
export interface MomentsSyncTask {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -17,7 +23,7 @@ export interface MomentsSyncTask {
|
|||||||
syncCount: number;
|
syncCount: number;
|
||||||
lastSyncTime: string;
|
lastSyncTime: string;
|
||||||
createTime: string;
|
createTime: string;
|
||||||
creator: string;
|
creatorName: string;
|
||||||
syncInterval: number;
|
syncInterval: number;
|
||||||
maxSyncPerDay: number;
|
maxSyncPerDay: number;
|
||||||
timeRange: { start: string; end: string };
|
timeRange: { start: string; end: string };
|
||||||
@@ -31,6 +37,7 @@ export interface MomentsSyncTask {
|
|||||||
todaySyncCount: number;
|
todaySyncCount: number;
|
||||||
totalSyncCount: number;
|
totalSyncCount: number;
|
||||||
updateTime: string;
|
updateTime: string;
|
||||||
|
config?: MomentsSyncConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建任务数据
|
// 创建任务数据
|
||||||
|
|||||||
Reference in New Issue
Block a user