diff --git a/nkebao/src/pages/content/Content.tsx b/nkebao/src/pages/content/Content.tsx deleted file mode 100644 index 55e68abd..00000000 --- a/nkebao/src/pages/content/Content.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react"; -import PlaceholderPage from "@/components/PlaceholderPage"; - -const Content: React.FC = () => { - return ( - - ); -}; - -export default Content; diff --git a/nkebao/src/pages/content/NewContent.tsx b/nkebao/src/pages/content/NewContent.tsx deleted file mode 100644 index 3bd82288..00000000 --- a/nkebao/src/pages/content/NewContent.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from "react"; -import PlaceholderPage from "@/components/PlaceholderPage"; - -const NewContent: React.FC = () => { - return ; -}; - -export default NewContent; diff --git a/nkebao/src/pages/content/form/api.ts b/nkebao/src/pages/content/form/api.ts new file mode 100644 index 00000000..a0d86375 --- /dev/null +++ b/nkebao/src/pages/content/form/api.ts @@ -0,0 +1,29 @@ +import { get, post, put } from "@/api/request"; +import { + ApiResponse, + ContentLibrary, + CreateContentLibraryParams, + UpdateContentLibraryParams, +} from "./data"; + +// 获取内容库详情 +export async function getContentLibraryDetail( + id: string +): Promise> { + return get>(`/v1/content/library/${id}`); +} + +// 创建内容库 +export async function createContentLibrary( + params: CreateContentLibraryParams +): Promise> { + return post>("/v1/content/library", params); +} + +// 更新内容库 +export async function updateContentLibrary( + params: UpdateContentLibraryParams +): Promise> { + const { id, ...data } = params; + return put>(`/v1/content/library/${id}`, data); +} diff --git a/nkebao/src/pages/content/form/data.ts b/nkebao/src/pages/content/form/data.ts new file mode 100644 index 00000000..d0270043 --- /dev/null +++ b/nkebao/src/pages/content/form/data.ts @@ -0,0 +1,61 @@ +// 内容库表单数据类型定义 +export interface ContentLibrary { + id: string; + name: string; + sourceType: number; // 1=微信好友, 2=聊天群 + creatorName?: string; + updateTime: string; + status: number; // 0=未启用, 1=已启用 + itemCount?: number; + createTime: string; + sourceFriends?: string[]; + sourceGroups?: string[]; + keywordInclude?: string[]; + keywordExclude?: string[]; + aiPrompt?: string; + timeEnabled?: number; + timeStart?: string; + timeEnd?: string; + selectedFriends?: any[]; + selectedGroups?: any[]; + selectedGroupMembers?: WechatGroupMember[]; +} + +// 微信群成员 +export interface WechatGroupMember { + id: string; + nickname: string; + wechatId: string; + avatar: string; + gender?: "male" | "female"; + role?: "owner" | "admin" | "member"; + joinTime?: string; +} + +// API 响应类型 +export interface ApiResponse { + code: number; + msg: string; + data: T; +} + +// 创建内容库参数 +export interface CreateContentLibraryParams { + name: string; + sourceType: number; + sourceFriends?: string[]; + sourceGroups?: string[]; + keywordInclude?: string[]; + keywordExclude?: string[]; + aiPrompt?: string; + timeEnabled?: number; + timeStart?: string; + timeEnd?: string; +} + +// 更新内容库参数 +export interface UpdateContentLibraryParams + extends Partial { + id: string; + status?: number; +} diff --git a/nkebao/src/pages/content/form/index.module.scss b/nkebao/src/pages/content/form/index.module.scss new file mode 100644 index 00000000..c988b351 --- /dev/null +++ b/nkebao/src/pages/content/form/index.module.scss @@ -0,0 +1,116 @@ +.form-page { + padding: 16px; + background: #f5f5f5; + min-height: 100vh; +} + +.loading { + display: flex; + justify-content: center; + align-items: center; + padding: 40px 0; +} + +.form { + display: flex; + flex-direction: column; + gap: 16px; +} + +.form-card { + background: white; + border-radius: 8px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + border: none; + padding: 16px; +} + +.card-title { + font-size: 16px; + font-weight: 600; + color: #333; + margin-bottom: 16px; + padding-bottom: 8px; + border-bottom: 1px solid #f0f0f0; +} + +.textarea { + border-radius: 6px; + border: 1px solid #d9d9d9; + + &:focus { + border-color: #1677ff; + box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1); + } +} + +.time-settings { + display: flex; + gap: 16px; + margin-top: 16px; + padding-top: 16px; + border-top: 1px solid #f0f0f0; +} + +.time-picker { + width: 100%; + border-radius: 6px; + + &:focus { + border-color: #1677ff; + box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1); + } +} + +.form-actions { + display: flex; + gap: 12px; + padding: 16px; + background: white; + border-radius: 8px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + margin-top: 16px; +} + +.back-btn { + flex: 1; + border-radius: 6px; + border: 1px solid #d9d9d9; + + &:hover { + border-color: #1677ff; + color: #1677ff; + } +} + +.submit-btn { + flex: 1; + border-radius: 6px; +} + +// 覆盖 antd-mobile 的默认样式 +:global { + .adm-form-item { + margin-bottom: 16px; + } + + .adm-form-item-label { + font-size: 14px; + color: #333; + font-weight: 500; + } + + .adm-input { + border-radius: 6px; + border: 1px solid #d9d9d9; + + &:focus { + border-color: #1677ff; + box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1); + } + } + + .adm-switch { + --checked-color: #1677ff; + } +} diff --git a/nkebao/src/pages/content/form/index.tsx b/nkebao/src/pages/content/form/index.tsx new file mode 100644 index 00000000..d60f1819 --- /dev/null +++ b/nkebao/src/pages/content/form/index.tsx @@ -0,0 +1,331 @@ +import React, { useState, useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { + Button, + Toast, + SpinLoading, + Form, + Input, + Switch, + Card, + Space, +} from "antd-mobile"; +import { Input as AntdInput, Select, TimePicker } from "antd"; +import { + ArrowLeftOutlined, + SaveOutlined, + UserOutlined, + TeamOutlined, +} from "@ant-design/icons"; +import Layout from "@/components/Layout/Layout"; +import NavCommon from "@/components/NavCommon"; +import { + getContentLibraryDetail, + createContentLibrary, + updateContentLibrary, +} from "./api"; +import { ContentLibrary, CreateContentLibraryParams } from "./data"; +import style from "./index.module.scss"; + +const { Option } = Select; +const { TextArea } = AntdInput; + +const ContentLibraryForm: React.FC = () => { + const navigate = useNavigate(); + const { id } = useParams<{ id: string }>(); + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const [saving, setSaving] = useState(false); + const [library, setLibrary] = useState(null); + const [sourceType, setSourceType] = useState(1); + + const isEdit = !!id; + + // 获取内容库详情 + useEffect(() => { + if (isEdit && id) { + fetchLibraryDetail(); + } + }, [isEdit, id]); + + const fetchLibraryDetail = async () => { + setLoading(true); + try { + const response = await getContentLibraryDetail(id!); + if (response.code === 200 && response.data) { + setLibrary(response.data); + setSourceType(response.data.sourceType); + + // 填充表单数据 + form.setFieldsValue({ + name: response.data.name, + sourceType: response.data.sourceType, + keywordInclude: response.data.keywordInclude?.join(",") || "", + keywordExclude: response.data.keywordExclude?.join(",") || "", + aiPrompt: response.data.aiPrompt || "", + timeEnabled: response.data.timeEnabled === 1, + timeStart: response.data.timeStart || "09:00", + timeEnd: response.data.timeEnd || "18:00", + }); + } else { + Toast.show({ + content: response.msg || "获取内容库详情失败", + position: "top", + }); + } + } catch (error: any) { + console.error("获取内容库详情失败:", error); + Toast.show({ + content: error?.message || "请检查网络连接", + position: "top", + }); + } finally { + setLoading(false); + } + }; + + const handleSubmit = async (values: any) => { + setSaving(true); + try { + const params: CreateContentLibraryParams = { + name: values.name, + sourceType: values.sourceType, + keywordInclude: values.keywordInclude + ? values.keywordInclude + .split(",") + .map((k: string) => k.trim()) + .filter(Boolean) + : [], + keywordExclude: values.keywordExclude + ? values.keywordExclude + .split(",") + .map((k: string) => k.trim()) + .filter(Boolean) + : [], + aiPrompt: values.aiPrompt || "", + timeEnabled: values.timeEnabled ? 1 : 0, + timeStart: values.timeStart || "09:00", + timeEnd: values.timeEnd || "18:00", + }; + + let response; + if (isEdit) { + response = await updateContentLibrary({ + id: id!, + ...params, + }); + } else { + response = await createContentLibrary(params); + } + + if (response.code === 200) { + Toast.show({ + content: isEdit ? "更新成功" : "创建成功", + position: "top", + }); + navigate("/content"); + } else { + Toast.show({ + content: response.msg || (isEdit ? "更新失败" : "创建失败"), + position: "top", + }); + } + } catch (error: any) { + console.error("保存内容库失败:", error); + Toast.show({ + content: error?.message || "请检查网络连接", + position: "top", + }); + } finally { + setSaving(false); + } + }; + + const handleBack = () => { + navigate("/content"); + }; + + if (loading) { + return ( + } + > +
+ +
+
+ ); + } + + return ( + }> +
+
+ {/* 基本信息 */} + +
基本信息
+ + + + + + + + +
+ + {/* 关键词设置 */} + +
关键词设置
+ + +