选择的处理下

This commit is contained in:
笔记本里的永平
2025-07-17 09:59:54 +08:00
parent 42ba2590f7
commit 43e873f83a
3 changed files with 341 additions and 166 deletions

View File

@@ -41,18 +41,11 @@ export default function DeviceSelection({
const [statusFilter, setStatusFilter] = useState("all"); const [statusFilter, setStatusFilter] = useState("all");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
// 当弹窗打开时获取设备列表 // 获取设备列表支持keyword
useEffect(() => { const fetchDevices = async (keyword: string = "") => {
if (dialogOpen) {
fetchDevices();
}
}, [dialogOpen]);
// 获取设备列表
const fetchDevices = async () => {
setLoading(true); setLoading(true);
try { try {
const res = await fetchDeviceList(1, 100); const res = await fetchDeviceList(1, 100, keyword.trim() || undefined);
if (res && res.data && Array.isArray(res.data.list)) { if (res && res.data && Array.isArray(res.data.list)) {
setDevices( setDevices(
res.data.list.map((d) => ({ res.data.list.map((d) => ({
@@ -71,19 +64,29 @@ export default function DeviceSelection({
} }
}; };
// 过滤设备 // 打开弹窗时获取设备列表
const filteredDevices = devices.filter((device) => { const openDialog = () => {
const matchesSearch = setSearchQuery("");
device.name.toLowerCase().includes(searchQuery.toLowerCase()) || setDialogOpen(true);
device.imei.toLowerCase().includes(searchQuery.toLowerCase()) || fetchDevices("");
device.wechatId.toLowerCase().includes(searchQuery.toLowerCase()); };
// 搜索防抖
useEffect(() => {
if (!dialogOpen) return;
const timer = setTimeout(() => {
fetchDevices(searchQuery);
}, 500);
return () => clearTimeout(timer);
}, [searchQuery, dialogOpen]);
// 过滤设备(只保留状态过滤)
const filteredDevices = devices.filter((device) => {
const matchesStatus = const matchesStatus =
statusFilter === "all" || statusFilter === "all" ||
(statusFilter === "online" && device.status === "online") || (statusFilter === "online" && device.status === "online") ||
(statusFilter === "offline" && device.status === "offline"); (statusFilter === "offline" && device.status === "offline");
return matchesStatus;
return matchesSearch && matchesStatus;
}); });
// 处理设备选择 // 处理设备选择
@@ -110,7 +113,7 @@ export default function DeviceSelection({
placeholder={placeholder} placeholder={placeholder}
className="pl-10 h-14 rounded-xl border-gray-200 text-base" className="pl-10 h-14 rounded-xl border-gray-200 text-base"
readOnly readOnly
onClick={() => setDialogOpen(true)} onClick={openDialog}
value={getDisplayText()} value={getDisplayText()}
/> />
</div> </div>

View File

@@ -42,62 +42,74 @@ export function DeviceSelectionDialog({
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [devices, setDevices] = useState<Device[]>([]); const [devices, setDevices] = useState<Device[]>([]);
// 获取设备列表 // 获取设备列表支持keyword
const fetchDevices = useCallback(async () => { const fetchDevices = useCallback(
setLoading(true); async (keyword: string = "") => {
try { setLoading(true);
const response = await fetchDeviceList(1, 100, searchQuery); try {
if (response.code === 200 && response.data) { const response = await fetchDeviceList(
// 转换服务端数据格式为组件需要的格式 1,
const convertedDevices: Device[] = response.data.list.map( 100,
(serverDevice: ServerDevice) => ({ keyword.trim() || undefined
id: serverDevice.id.toString(),
name: serverDevice.memo || `设备 ${serverDevice.id}`,
imei: serverDevice.imei,
wxid: serverDevice.wechatId || "",
status: serverDevice.alive === 1 ? "online" : "offline",
usedInPlans: 0, // 这个字段需要从其他API获取
nickname: serverDevice.nickname || "",
})
); );
setDevices(convertedDevices); if (response.code === 200 && response.data) {
} else { // 转换服务端数据格式为组件需要的格式
const convertedDevices: Device[] = response.data.list.map(
(serverDevice: ServerDevice) => ({
id: serverDevice.id.toString(),
name: serverDevice.memo || `设备 ${serverDevice.id}`,
imei: serverDevice.imei,
wxid: serverDevice.wechatId || "",
status: serverDevice.alive === 1 ? "online" : "offline",
usedInPlans: 0, // 这个字段需要从其他API获取
nickname: serverDevice.nickname || "",
})
);
setDevices(convertedDevices);
} else {
toast({
title: "获取设备列表失败",
description: response.msg,
variant: "destructive",
});
}
} catch (error) {
console.error("获取设备列表失败:", error);
toast({ toast({
title: "获取设备列表失败", title: "获取设备列表失败",
description: response.msg, description: "请检查网络连接",
variant: "destructive", variant: "destructive",
}); });
} finally {
setLoading(false);
} }
} catch (error) { },
console.error("获取设备列表失败:", error); [toast]
toast({ );
title: "获取设备列表失败",
description: "请检查网络连接",
variant: "destructive",
});
} finally {
setLoading(false);
}
}, [searchQuery, toast]);
// 打开弹窗时获取设备列表
useEffect(() => { useEffect(() => {
if (open) { if (open) {
fetchDevices(); fetchDevices("");
} }
}, [open, searchQuery, fetchDevices]); }, [open, fetchDevices]);
// 搜索防抖
useEffect(() => {
if (!open) return;
const timer = setTimeout(() => {
fetchDevices(searchQuery);
}, 500);
return () => clearTimeout(timer);
}, [searchQuery, open, fetchDevices]);
// 过滤设备(只保留状态过滤)
const filteredDevices = devices.filter((device) => { const filteredDevices = devices.filter((device) => {
const matchesSearch =
device.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
device.imei.toLowerCase().includes(searchQuery.toLowerCase()) ||
device.wxid.toLowerCase().includes(searchQuery.toLowerCase());
const matchesStatus = const matchesStatus =
statusFilter === "all" || statusFilter === "all" ||
(statusFilter === "online" && device.status === "online") || (statusFilter === "online" && device.status === "online") ||
(statusFilter === "offline" && device.status === "offline"); (statusFilter === "offline" && device.status === "offline");
return matchesStatus;
return matchesSearch && matchesStatus;
}); });
const handleDeviceSelect = (deviceId: string) => { const handleDeviceSelect = (deviceId: string) => {
@@ -137,7 +149,7 @@ export function DeviceSelectionDialog({
<Button <Button
variant="outline" variant="outline"
size="icon" size="icon"
onClick={fetchDevices} onClick={() => fetchDevices(searchQuery)}
disabled={loading} disabled={loading}
> >
{loading ? ( {loading ? (

View File

@@ -1,25 +1,33 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from "react";
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from "react-router-dom";
import Layout from '@/components/Layout'; import Layout from "@/components/Layout";
import UnifiedHeader from '@/components/UnifiedHeader'; import UnifiedHeader from "@/components/UnifiedHeader";
import { Input } from '@/components/ui/input'; import { Input } from "@/components/ui/input";
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from "@/components/ui/textarea";
import { Switch } from '@/components/ui/switch'; import { Switch } from "@/components/ui/switch";
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'; import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { Card } from '@/components/ui/card'; import { Card } from "@/components/ui/card";
import { Collapse, CollapsePanel ,Button} from 'tdesign-mobile-react'; import { Collapse, CollapsePanel, Button } from "tdesign-mobile-react";
import { toast } from '@/components/ui/toast'; import { toast } from "@/components/ui/toast";
import FriendSelection from '@/components/FriendSelection'; import FriendSelection from "@/components/FriendSelection";
import GroupSelection from '@/components/GroupSelection'; import GroupSelection from "@/components/GroupSelection";
import { get, post } from '@/api/request'; import { get, post } from "@/api/request";
// TODO: 引入微信好友/群组选择器、日期选择器等组件 // TODO: 引入微信好友/群组选择器、日期选择器等组件
interface WechatFriend { id: string; nickname: string; avatar: string; } interface WechatFriend {
interface WechatGroup { id: string; name: string; avatar: string; } id: string;
nickname: string;
avatar: string;
}
interface WechatGroup {
id: string;
name: string;
avatar: string;
}
interface ContentLibraryForm { interface ContentLibraryForm {
name: string; name: string;
sourceType: 'friends' | 'groups'; sourceType: "friends" | "groups";
keywordsInclude: string; keywordsInclude: string;
keywordsExclude: string; keywordsExclude: string;
startDate: string; startDate: string;
@@ -36,19 +44,21 @@ export default function NewContentLibraryPage() {
const { id } = useParams(); const { id } = useParams();
const isEdit = !!id; const isEdit = !!id;
const [form, setForm] = useState<ContentLibraryForm>({ const [form, setForm] = useState<ContentLibraryForm>({
name: '', name: "",
sourceType: 'friends', sourceType: "friends",
keywordsInclude: '', keywordsInclude: "",
keywordsExclude: '', keywordsExclude: "",
startDate: '', startDate: "",
endDate: '', endDate: "",
selectedFriends: [], selectedFriends: [],
selectedGroups: [], selectedGroups: [],
useAI: false, useAI: false,
aiPrompt: '', aiPrompt: "",
enabled: true, enabled: true,
}); });
const [selectedFriendObjs, setSelectedFriendObjs] = useState<WechatFriend[]>([]); const [selectedFriendObjs, setSelectedFriendObjs] = useState<WechatFriend[]>(
[]
);
const [selectedGroupObjs, setSelectedGroupObjs] = useState<WechatGroup[]>([]); const [selectedGroupObjs, setSelectedGroupObjs] = useState<WechatGroup[]>([]);
const [isFriendSelectorOpen, setIsFriendSelectorOpen] = useState(false); const [isFriendSelectorOpen, setIsFriendSelectorOpen] = useState(false);
const [isGroupSelectorOpen, setIsGroupSelectorOpen] = useState(false); const [isGroupSelectorOpen, setIsGroupSelectorOpen] = useState(false);
@@ -62,31 +72,66 @@ export default function NewContentLibraryPage() {
const data = res.data; const data = res.data;
// 时间戳转YYYY-MM-DD // 时间戳转YYYY-MM-DD
const formatDate = (val: number) => { const formatDate = (val: number) => {
if (!val || val === 0 || typeof val !== 'number' || isNaN(val) || val < 1000000000) return ''; if (
!val ||
val === 0 ||
typeof val !== "number" ||
isNaN(val) ||
val < 1000000000
)
return "";
try { try {
const d = new Date(val * 1000); const d = new Date(val * 1000);
if (isNaN(d.getTime())) return ''; if (isNaN(d.getTime())) return "";
return d.toISOString().slice(0, 10); return d.toISOString().slice(0, 10);
} catch { } catch {
return ''; return "";
} }
}; };
setForm(f => ({ setForm((f) => ({
...f, ...f,
name: data.name || '', name: data.name || "",
sourceType: data.sourceType === 1 ? 'friends' : 'groups', sourceType: data.sourceType === 1 ? "friends" : "groups",
keywordsInclude: (data.keywordInclude || []).join(','), keywordsInclude: (data.keywordInclude || []).join(","),
keywordsExclude: (data.keywordExclude || []).join(','), keywordsExclude: (data.keywordExclude || []).join(","),
startDate: formatDate(data.timeStart), startDate: formatDate(data.timeStart),
endDate: formatDate(data.timeEnd), endDate: formatDate(data.timeEnd),
selectedFriends: (data.selectedFriends || data.sourceFriends || []).map((fid: number | string) => ({ id: String(fid), nickname: String(fid), avatar: '' })), selectedFriends: (
selectedGroups: (data.sourceGroups || []).map((gid: number | string) => ({ id: String(gid), name: String(gid), avatar: '' })), data.selectedFriends ||
data.sourceFriends ||
[]
).map((fid: number | string) => ({
id: String(fid),
nickname: String(fid),
avatar: "",
})),
selectedGroups: (data.sourceGroups || []).map(
(gid: number | string) => ({
id: String(gid),
name: String(gid),
avatar: "",
})
),
useAI: data.aiEnabled === 1, useAI: data.aiEnabled === 1,
aiPrompt: data.aiPrompt || '', aiPrompt: data.aiPrompt || "",
enabled: data.status === 1, enabled: data.status === 1,
})); }));
setSelectedFriendObjs((data.selectedFriends || data.sourceFriends || []).map((fid: number | string) => ({ id: String(fid), nickname: String(fid), avatar: '' }))); setSelectedFriendObjs(
setSelectedGroupObjs((data.sourceGroups || []).map((gid: number | string) => ({ id: String(gid), name: String(gid), avatar: '' }))); (data.selectedFriends || data.sourceFriends || []).map(
(fid: number | string) => ({
id: String(fid),
nickname: String(fid),
avatar: "",
})
)
);
setSelectedGroupObjs(
(data.sourceGroups || []).map((gid: number | string) => ({
id: String(gid),
name: String(gid),
avatar: "",
}))
);
} }
})(); })();
} }
@@ -100,27 +145,44 @@ export default function NewContentLibraryPage() {
const payload = { const payload = {
id: isEdit ? id : undefined, id: isEdit ? id : undefined,
name: form.name, name: form.name,
sourceType: form.sourceType === 'friends' ? 1 : 2, sourceType: form.sourceType === "friends" ? 1 : 2,
friends: form.selectedFriends.map(f => Number(f.id)), friends: form.selectedFriends.map((f) => Number(f.id)),
groups: form.selectedGroups.map(g => Number(g.id)), groups: form.selectedGroups.map((g) => Number(g.id)),
groupMembers: {}, groupMembers: {},
keywordInclude: form.keywordsInclude ? form.keywordsInclude.split(',').map(s => s.trim()).filter(Boolean) : [], keywordInclude: form.keywordsInclude
keywordExclude: form.keywordsExclude ? form.keywordsExclude.split(',').map(s => s.trim()).filter(Boolean) : [], ? form.keywordsInclude
.split(",")
.map((s) => s.trim())
.filter(Boolean)
: [],
keywordExclude: form.keywordsExclude
? form.keywordsExclude
.split(",")
.map((s) => s.trim())
.filter(Boolean)
: [],
aiPrompt: form.aiPrompt, aiPrompt: form.aiPrompt,
timeEnabled: form.startDate || form.endDate ? 1 : 0, timeEnabled: form.startDate || form.endDate ? 1 : 0,
startTime: form.startDate || '', startTime: form.startDate || "",
endTime: form.endDate || '', endTime: form.endDate || "",
status: form.enabled ? 1 : 0 status: form.enabled ? 1 : 0,
}; };
if (isEdit) { if (isEdit) {
await post('/v1/content/library/update', payload); await post("/v1/content/library/update", payload);
} else { } else {
await post('/v1/content/library/create', payload); await post("/v1/content/library/create", payload);
} }
toast({ title: isEdit ? '保存成功' : '创建成功', description: '内容库已保存' }); toast({
navigate('/content'); title: isEdit ? "保存成功" : "创建成功",
description: "内容库已保存",
});
navigate("/content");
} catch (error) { } catch (error) {
toast({ title: isEdit ? '保存失败' : '创建失败', description: '保存内容库失败', variant: 'destructive' }); toast({
title: isEdit ? "保存失败" : "创建失败",
description: "保存内容库失败",
variant: "destructive",
});
} finally { } finally {
setIsSubmitting(false); setIsSubmitting(false);
} }
@@ -128,66 +190,114 @@ export default function NewContentLibraryPage() {
return ( return (
<Layout <Layout
header={<UnifiedHeader title={isEdit ? "编辑内容库" : "新建内容库"} showBack onBack={() => navigate(-1)} />} header={
<UnifiedHeader
title={isEdit ? "编辑内容库" : "新建内容库"}
showBack
onBack={() => navigate(-1)}
/>
}
footer={ footer={
<div className="p-4"> <div className="p-4">
<Button theme="primary" block onClick={handleSave} disabled={isSubmitting || !form.name} > <Button
{isSubmitting ? (isEdit ? '保存中...' : '创建中...') : (isEdit ? '保存' : '创建内容库')} theme="primary"
</Button> block
</div> onClick={handleSave}
disabled={isSubmitting || !form.name}
>
{isSubmitting
? isEdit
? "保存中..."
: "创建中..."
: isEdit
? "保存"
: "创建内容库"}
</Button>
</div>
} }
> >
<div className="flex-1 bg-gray-50 min-h-screen pb-16"> <div className="flex-1 bg-gray-50 ">
<div className="p-4 space-y-4 max-w-lg mx-auto"> <div className="p-4 space-y-4 max-w-lg mx-auto">
<Card className="p-4"> <Card className="p-4">
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<label className="block font-medium mb-1"> <span className="text-red-500">*</span></label> <label className="block font-medium mb-1">
<span className="text-red-500">*</span>
</label>
<Input <Input
value={form.name} value={form.name}
onChange={e => setForm(f => ({ ...f, name: e.target.value }))} onChange={(e) =>
setForm((f) => ({ ...f, name: e.target.value }))
}
placeholder="请输入内容库名称" placeholder="请输入内容库名称"
required required
/> />
</div> </div>
<div> <div>
<label className="block font-medium mb-1"></label> <label className="block font-medium mb-1"></label>
<Tabs value={form.sourceType} onValueChange={val => setForm(f => ({ ...f, sourceType: val as 'friends' | 'groups' }))}> <Tabs
value={form.sourceType}
onValueChange={(val) =>
setForm((f) => ({
...f,
sourceType: val as "friends" | "groups",
}))
}
>
<TabsList className="grid w-full grid-cols-2"> <TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="friends"></TabsTrigger> <TabsTrigger value="friends"></TabsTrigger>
<TabsTrigger value="groups"></TabsTrigger> <TabsTrigger value="groups"></TabsTrigger>
</TabsList> </TabsList>
<TabsContent value="friends"> <TabsContent value="friends">
<FriendSelection <FriendSelection
selectedFriends={form.selectedFriends.map(f => f.id)} selectedFriends={form.selectedFriends.map((f) => f.id)}
onSelect={ids => setForm(f => ({ onSelect={(ids) =>
...f, setForm((f) => ({
selectedFriends: ids.map(id => ({ id, nickname: id, avatar: '' })) ...f,
}))} selectedFriends: ids.map((id) => ({
id,
nickname: id,
avatar: "",
})),
}))
}
onSelectDetail={setSelectedFriendObjs} onSelectDetail={setSelectedFriendObjs}
enableDeviceFilter={false} enableDeviceFilter={false}
placeholder="选择微信好友" placeholder="选择微信好友"
/> />
{selectedFriendObjs.length > 0 && ( {selectedFriendObjs.length > 0 && (
<div className="mt-2 space-y-2"> <div className="mt-2 space-y-2">
{selectedFriendObjs.map(friend => ( {selectedFriendObjs.map((friend) => (
<div key={friend.id} className="flex items-center justify-between bg-gray-100 p-2 rounded-md"> <div
key={friend.id}
className="flex items-center justify-between bg-gray-100 p-2 rounded-md"
>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{friend.avatar ? ( {friend.avatar ? (
<img src={friend.avatar} alt={friend.nickname} className="w-8 h-8 rounded-full object-cover" /> <img
src={friend.avatar}
alt={friend.nickname}
className="w-8 h-8 rounded-full object-cover"
/>
) : ( ) : (
<div className="w-8 h-8 rounded-full bg-gray-300 flex items-center justify-center text-white text-sm">{friend.nickname?.charAt(0) || '友'}</div> <div className="w-8 h-8 rounded-full bg-gray-300 flex items-center justify-center text-white text-sm">
{friend.nickname?.charAt(0) || "友"}
</div>
)} )}
<span>{friend.nickname}</span> <span>{friend.nickname}</span>
</div> </div>
<button <button
className="text-gray-400 hover:text-red-500 ml-2" className="text-gray-400 hover:text-red-500 ml-2"
onClick={() => { onClick={() => {
setForm(f => ({ setForm((f) => ({
...f, ...f,
selectedFriends: f.selectedFriends.filter(frd => frd.id !== friend.id) selectedFriends: f.selectedFriends.filter(
(frd) => frd.id !== friend.id
),
})); }));
setSelectedFriendObjs(objs => objs.filter(frd => frd.id !== friend.id)); setSelectedFriendObjs((objs) =>
objs.filter((frd) => frd.id !== friend.id)
);
}} }}
title="移除" title="移除"
> >
@@ -200,37 +310,54 @@ export default function NewContentLibraryPage() {
</TabsContent> </TabsContent>
<TabsContent value="groups"> <TabsContent value="groups">
<GroupSelection <GroupSelection
selectedGroups={form.selectedGroups.map(g => g.id)} selectedGroups={form.selectedGroups.map((g) => g.id)}
onSelect={ids => setForm(f => ({ onSelect={(ids) =>
...f, setForm((f) => ({
selectedGroups: ids.map(id => { ...f,
const old = f.selectedGroups.find(g => g.id === id); selectedGroups: ids.map((id) => {
return old || { id, name: id, avatar: '' }; const old = f.selectedGroups.find(
}) (g) => g.id === id
}))} );
return old || { id, name: id, avatar: "" };
}),
}))
}
onSelectDetail={setSelectedGroupObjs} onSelectDetail={setSelectedGroupObjs}
placeholder="选择群聊" placeholder="选择群聊"
/> />
{selectedGroupObjs.length > 0 && ( {selectedGroupObjs.length > 0 && (
<div className="mt-2 space-y-2"> <div className="mt-2 space-y-2">
{selectedGroupObjs.map(group => ( {selectedGroupObjs.map((group) => (
<div key={group.id} className="flex items-center justify-between bg-gray-100 p-2 rounded-md"> <div
key={group.id}
className="flex items-center justify-between bg-gray-100 p-2 rounded-md"
>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{group.avatar ? ( {group.avatar ? (
<img src={group.avatar} alt={group.name} className="w-8 h-8 rounded-full object-cover" /> <img
src={group.avatar}
alt={group.name}
className="w-8 h-8 rounded-full object-cover"
/>
) : ( ) : (
<div className="w-8 h-8 rounded-full bg-gray-300 flex items-center justify-center text-white text-sm">{group.name?.charAt(0) || '群'}</div> <div className="w-8 h-8 rounded-full bg-gray-300 flex items-center justify-center text-white text-sm">
{group.name?.charAt(0) || "群"}
</div>
)} )}
<span>{group.name}</span> <span>{group.name}</span>
</div> </div>
<button <button
className="text-gray-400 hover:text-red-500 ml-2" className="text-gray-400 hover:text-red-500 ml-2"
onClick={() => { onClick={() => {
setForm(f => ({ setForm((f) => ({
...f, ...f,
selectedGroups: f.selectedGroups.filter(grp => grp.id !== group.id) selectedGroups: f.selectedGroups.filter(
(grp) => grp.id !== group.id
),
})); }));
setSelectedGroupObjs(objs => objs.filter(grp => grp.id !== group.id)); setSelectedGroupObjs((objs) =>
objs.filter((grp) => grp.id !== group.id)
);
}} }}
title="移除" title="移除"
> >
@@ -247,18 +374,32 @@ export default function NewContentLibraryPage() {
<CollapsePanel header="关键字设置" value="keywords"> <CollapsePanel header="关键字设置" value="keywords">
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<label className="block font-medium mb-1"></label> <label className="block font-medium mb-1">
</label>
<Textarea <Textarea
value={form.keywordsInclude} value={form.keywordsInclude}
onChange={e => setForm(f => ({ ...f, keywordsInclude: e.target.value }))} onChange={(e) =>
setForm((f) => ({
...f,
keywordsInclude: e.target.value,
}))
}
placeholder="如果设置了关键字,系统只会采集含有关键字的内容。多个关键字,用半角的','隔开。" placeholder="如果设置了关键字,系统只会采集含有关键字的内容。多个关键字,用半角的','隔开。"
/> />
</div> </div>
<div> <div>
<label className="block font-medium mb-1"></label> <label className="block font-medium mb-1">
</label>
<Textarea <Textarea
value={form.keywordsExclude} value={form.keywordsExclude}
onChange={e => setForm(f => ({ ...f, keywordsExclude: e.target.value }))} onChange={(e) =>
setForm((f) => ({
...f,
keywordsExclude: e.target.value,
}))
}
placeholder="排除含有这些关键字的内容。多个关键字,用半角的','隔开。" placeholder="排除含有这些关键字的内容。多个关键字,用半角的','隔开。"
/> />
</div> </div>
@@ -269,17 +410,26 @@ export default function NewContentLibraryPage() {
<div> <div>
<label className="block font-medium">AI</label> <label className="block font-medium">AI</label>
</div> </div>
<div className='w-10'> <div className="w-10">
<Switch checked={form.useAI} onCheckedChange={checked => setForm(f => ({ ...f, useAI: checked }))} /> <Switch
checked={form.useAI}
onCheckedChange={(checked) =>
setForm((f) => ({ ...f, useAI: checked }))
}
/>
</div> </div>
</div> </div>
<p className="text-sm text-gray-500 mt-1 ">AI之后AI重新生成内容</p> <p className="text-sm text-gray-500 mt-1 ">
AI之后AI重新生成内容
</p>
{form.useAI && ( {form.useAI && (
<div> <div>
<label className="block font-medium mb-1">AI </label> <label className="block font-medium mb-1">AI </label>
<Textarea <Textarea
value={form.aiPrompt} value={form.aiPrompt}
onChange={e => setForm(f => ({ ...f, aiPrompt: e.target.value }))} onChange={(e) =>
setForm((f) => ({ ...f, aiPrompt: e.target.value }))
}
placeholder="请输入 AI 提示词" placeholder="请输入 AI 提示词"
/> />
</div> </div>
@@ -287,31 +437,41 @@ export default function NewContentLibraryPage() {
<div> <div>
<label className="block font-medium mb-2"></label> <label className="block font-medium mb-2"></label>
{/* TODO: 替换为TDesign日期范围选择器 */} {/* TODO: 替换为TDesign日期范围选择器 */}
<div className='flex mb-2' style={{ justifyContent: 'space-between' }}> <div
<label className='text-sm w-20 '></label> className="flex mb-2"
style={{ justifyContent: "space-between" }}
>
<label className="text-sm w-20 "></label>
<Input <Input
type="date" type="date"
value={form.startDate} value={form.startDate}
onChange={e => setForm(f => ({ ...f, startDate: e.target.value }))} onChange={(e) =>
setForm((f) => ({ ...f, startDate: e.target.value }))
}
className="inline-block w-1/2 " className="inline-block w-1/2 "
/> />
</div> </div>
<div className='flex '> <div className="flex ">
<label className='text-sm w-20' ></label> <label className="text-sm w-20"></label>
<Input <Input
type="date" type="date"
value={form.endDate} value={form.endDate}
onChange={e => setForm(f => ({ ...f, endDate: e.target.value }))} onChange={(e) =>
setForm((f) => ({ ...f, endDate: e.target.value }))
}
className="inline-block w-1/2" className="inline-block w-1/2"
/> />
</div> </div>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<label className="block font-medium mb-1"></label> <label className="block font-medium mb-1"></label>
<Switch checked={form.enabled} onCheckedChange={checked => setForm(f => ({ ...f, enabled: checked }))} /> <Switch
checked={form.enabled}
onCheckedChange={(checked) =>
setForm((f) => ({ ...f, enabled: checked }))
}
/>
</div> </div>
</div> </div>
</Card> </Card>
</div> </div>
@@ -319,4 +479,4 @@ export default function NewContentLibraryPage() {
</div> </div>
</Layout> </Layout>
); );
} }