diff --git a/Cunkebao/src/pages/mobile/mine/content/materials/list/api.ts b/Cunkebao/src/pages/mobile/mine/content/materials/list/api.ts index 6037391f..e1d6edea 100644 --- a/Cunkebao/src/pages/mobile/mine/content/materials/list/api.ts +++ b/Cunkebao/src/pages/mobile/mine/content/materials/list/api.ts @@ -3,6 +3,8 @@ import { GetContentItemListParams, CreateContentItemParams, UpdateContentItemParams, + AIRewriteParams, + ReplaceContentParams, } from "./data"; // 获取素材列表 @@ -35,3 +37,13 @@ export function deleteContentItem(id: string) { export function getContentLibraryDetail(id: string) { return request("/v1/content/library/detail", { id }, "GET"); } + +// AI改写内容 +export function aiRewriteContent(params: AIRewriteParams) { + return request("/v1/content/library/aiEditContent", params, "GET"); +} + +// 替换原内容 +export function replaceContent(params: ReplaceContentParams) { + return request("/v1/content/library/aiEditContent", params, "POST"); +} diff --git a/Cunkebao/src/pages/mobile/mine/content/materials/list/data.ts b/Cunkebao/src/pages/mobile/mine/content/materials/list/data.ts index b2bc51ab..4217465e 100644 --- a/Cunkebao/src/pages/mobile/mine/content/materials/list/data.ts +++ b/Cunkebao/src/pages/mobile/mine/content/materials/list/data.ts @@ -104,3 +104,15 @@ export interface UpdateContentItemParams extends Partial { id: string; } + +// AI改写参数 +export interface AIRewriteParams { + id: string; + aiPrompt: string; +} + +// 替换内容参数 +export interface ReplaceContentParams { + id: string; + content: string; +} diff --git a/Cunkebao/src/pages/mobile/mine/content/materials/list/index.module.scss b/Cunkebao/src/pages/mobile/mine/content/materials/list/index.module.scss index 666b75ad..1d5b5666 100644 --- a/Cunkebao/src/pages/mobile/mine/content/materials/list/index.module.scss +++ b/Cunkebao/src/pages/mobile/mine/content/materials/list/index.module.scss @@ -613,3 +613,145 @@ line-height: 1.6; } } + +// AI改写弹框样式 +.ai-popup-content { + padding: 20px; + max-height: 80vh; + overflow-y: auto; + background: #f9fbfd; + + .ai-popup-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20px; + padding-bottom: 12px; + border-bottom: 1px solid #e8f4ff; + + h3 { + font-size: 18px; + font-weight: 600; + color: #1677ff; + margin: 0; + display: flex; + align-items: center; + + &::before { + content: ''; + display: inline-block; + width: 4px; + height: 18px; + background: #1677ff; + margin-right: 8px; + border-radius: 2px; + } + } + } + + .ai-form { + .ai-form-item { + margin-bottom: 20px; + + .ai-form-label { + font-size: 15px; + font-weight: 500; + color: #333; + margin-bottom: 6px; + display: flex; + align-items: center; + + &::before { + content: ''; + display: inline-block; + width: 3px; + height: 14px; + background: #1677ff; + margin-right: 6px; + border-radius: 2px; + } + } + + .ai-result-description { + font-size: 12px; + color: #999; + margin-bottom: 10px; + } + } + + .ai-submit { + margin: 24px 0; + + button { + height: 44px; + font-size: 16px; + border-radius: 8px; + box-shadow: 0 2px 6px rgba(22, 119, 255, 0.2); + } + } + + .ai-result-box { + background: #ffffff; + border: 1px solid #e0f0ff; + border-radius: 8px; + padding: 16px; + min-height: 150px; + max-height: 300px; + overflow-y: auto; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + + .ai-loading { + display: flex; + justify-content: center; + align-items: center; + height: 120px; + } + + .ai-result-content { + font-size: 15px; + line-height: 1.8; + color: #333; + white-space: pre-wrap; + padding: 4px; + } + + .ai-result-placeholder { + color: #999; + text-align: center; + padding: 30px 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + .placeholder-icon { + font-size: 28px; + margin-bottom: 10px; + } + + .placeholder-text { + font-size: 14px; + color: #999; + } + } + } + + .ai-replace-action { + margin-top: 20px; + + button { + height: 44px; + font-size: 16px; + border-radius: 8px; + background: #52c41a; + border-color: #52c41a; + box-shadow: 0 2px 6px rgba(82, 196, 26, 0.2); + + &:hover, &:focus { + background: #73d13d; + border-color: #73d13d; + } + } + } + } +} diff --git a/Cunkebao/src/pages/mobile/mine/content/materials/list/index.tsx b/Cunkebao/src/pages/mobile/mine/content/materials/list/index.tsx index db963f0b..e05012a0 100644 --- a/Cunkebao/src/pages/mobile/mine/content/materials/list/index.tsx +++ b/Cunkebao/src/pages/mobile/mine/content/materials/list/index.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useCallback } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { Toast, SpinLoading, Dialog, Card } from "antd-mobile"; -import { Input, Pagination, Button } from "antd"; +import { Toast, SpinLoading, Dialog, Card, Popup, TextArea } from "antd-mobile"; +import { Input, Pagination, Button, Spin } from "antd"; import { PlusOutlined, SearchOutlined, @@ -18,7 +18,7 @@ import { } from "@ant-design/icons"; import Layout from "@/components/Layout/Layout"; import NavCommon from "@/components/NavCommon"; -import { getContentItemList, deleteContentItem } from "./api"; +import { getContentItemList, deleteContentItem, aiRewriteContent, replaceContent } from "./api"; import { ContentItem } from "./data"; import style from "./index.module.scss"; @@ -42,6 +42,14 @@ const MaterialsList: React.FC = () => { const [total, setTotal] = useState(0); const pageSize = 20; + // AI改写相关状态 + const [showAIRewritePopup, setShowAIRewritePopup] = useState(false); + const [currentMaterial, setCurrentMaterial] = useState(null); + const [aiPrompt, setAiPrompt] = useState(""); + const [aiResult, setAiResult] = useState(""); + const [aiLoading, setAiLoading] = useState(false); + const [replaceLoading, setReplaceLoading] = useState(false); + // 获取素材列表 const fetchMaterials = useCallback(async () => { if (!id) return; @@ -104,9 +112,75 @@ const MaterialsList: React.FC = () => { } }; - const handleView = (materialId: number) => { - // 可以跳转到素材详情页面或显示弹窗 - console.log("查看素材:", materialId); + const handleAIRewrite = (material: ContentItem) => { + setCurrentMaterial(material); + setAiPrompt("重写这条朋友圈 要求: 1、原本的字数和意思不要修改超过10% 2、出现品牌名或个人名字就去除 3、适当的换行及加些表情点缀"); + setAiResult(""); + setShowAIRewritePopup(true); + }; + + const handleSubmitAIRewrite = async () => { + if (!currentMaterial) return; + + try { + setAiLoading(true); + const response = await aiRewriteContent({ + id: currentMaterial.id.toString(), + aiPrompt: aiPrompt + }); + + setAiResult(response.contentAfter || "暂无改写结果"); + + // 可以在这里显示原内容和改写后内容的对比 + console.log("原内容:", response.contentFront); + console.log("改写后内容:", response.contentAfter); + } catch (error) { + console.error("AI改写失败:", error); + Toast.show({ + content: "AI改写失败,请重试", + position: "top", + }); + } finally { + setAiLoading(false); + } + }; + + const handleReplaceContent = async () => { + if (!currentMaterial || !aiResult) return; + + try { + setReplaceLoading(true); + await replaceContent({ + id: currentMaterial.id.toString(), + content: aiResult + }); + + Toast.show({ + content: "内容已成功替换", + position: "top", + }); + + // 刷新素材列表 + fetchMaterials(); + + // 关闭弹窗 + closeAIRewritePopup(); + } catch (error) { + console.error("替换内容失败:", error); + Toast.show({ + content: "替换内容失败,请重试", + position: "top", + }); + } finally { + setReplaceLoading(false); + } + }; + + const closeAIRewritePopup = () => { + setShowAIRewritePopup(false); + setCurrentMaterial(null); + setAiPrompt(""); + setAiResult(""); }; const handleRefresh = () => { @@ -381,7 +455,7 @@ const MaterialsList: React.FC = () => { 编辑 + + +
+ {/* 提示词输入区 */} +
+
提示词
+
+