290 lines
11 KiB
TypeScript
290 lines
11 KiB
TypeScript
|
|
import { useState } from "react";
|
|||
|
|
import {
|
|||
|
|
AppstoreOutlined,
|
|||
|
|
CopyOutlined,
|
|||
|
|
EditOutlined,
|
|||
|
|
FileTextOutlined,
|
|||
|
|
FireOutlined,
|
|||
|
|
GlobalOutlined,
|
|||
|
|
MessageOutlined,
|
|||
|
|
SmileOutlined,
|
|||
|
|
ThunderboltOutlined,
|
|||
|
|
} from "@ant-design/icons";
|
|||
|
|
|
|||
|
|
export type CopywritingType =
|
|||
|
|
| "self-media"
|
|||
|
|
| "universal"
|
|||
|
|
| "original"
|
|||
|
|
| "imitate"
|
|||
|
|
| "wechat"
|
|||
|
|
| "crossborder"
|
|||
|
|
| "emoji"
|
|||
|
|
| "more";
|
|||
|
|
|
|||
|
|
interface CopywritingTypeOption {
|
|||
|
|
key: CopywritingType;
|
|||
|
|
label: string;
|
|||
|
|
icon: React.ReactNode;
|
|||
|
|
description: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const copywritingTypes: CopywritingTypeOption[] = [
|
|||
|
|
{ key: "self-media", label: "自媒体文案", icon: <MessageOutlined />, description: "小红书/抖音/公众号风格" },
|
|||
|
|
{ key: "universal", label: "万能写作", icon: <EditOutlined />, description: "通用场景长文短句" },
|
|||
|
|
{ key: "original", label: "一键原创", icon: <ThunderboltOutlined />, description: "快速改写去重" },
|
|||
|
|
{ key: "imitate", label: "文案仿写", icon: <CopyOutlined />, description: "参照爆款风格重写" },
|
|||
|
|
{ key: "wechat", label: "微信营销文案", icon: <FileTextOutlined />, description: "朋友圈/社群转化文案" },
|
|||
|
|
{ key: "crossborder", label: "跨境商品文案", icon: <GlobalOutlined />, description: "Amazon/Temu 卖点描述" },
|
|||
|
|
{ key: "emoji", label: "文案加Emoji", icon: <SmileOutlined />, description: "自动插入表情符号" },
|
|||
|
|
{ key: "more", label: "更多场景", icon: <AppstoreOutlined />, description: "持续更新中" },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
const wordCountOptions = ["不限", "100字", "300字", "500字", "800字"];
|
|||
|
|
|
|||
|
|
const exampleResults: Record<CopywritingType, Array<{ title: string; body: string; points: string[] }>> = {
|
|||
|
|
"self-media": [
|
|||
|
|
{
|
|||
|
|
title: "超值干发神器,吸水力 MAX!",
|
|||
|
|
body: "家人们,我发现了一款干发帽,双层加厚吸水力超强!而且只要个位数就能到手啊!",
|
|||
|
|
points: [
|
|||
|
|
"超强吸水力:这款干发帽采用微纤维材质,轻轻一裹,水分立马被吸走,头发快速告别湿漉漉。",
|
|||
|
|
"柔软亲肤:触感超级柔软,对皮肤和头发都是温柔的抚摸,不会有摩擦伤害哦。",
|
|||
|
|
"加厚设计:比普通干发帽更厚实,吸水效果自然更胜一筹,长发妹子的福音!",
|
|||
|
|
"方便携带:轻巧不占空间,不论是去健身房还是旅行,携带都毫无负担。",
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
universal: [
|
|||
|
|
{
|
|||
|
|
title: "直接抄作业!科学的减重方法必试!",
|
|||
|
|
body: "姐妹们冲鸭!有很多科学有效的方式可以帮助我们实现理想体重,今天就来分享一下必试的方法!",
|
|||
|
|
points: [
|
|||
|
|
"快乐有氧运动:科学的减重方式,通过有氧运动如慢跑、游泳等,能够促进脂肪燃烧,让身体更健康!",
|
|||
|
|
"均衡饮食规划:摄入足够的蛋白质、蔬果以及谷物,避免过多的高糖和高脂食物,帮助达到减重目标!",
|
|||
|
|
"科学计算热量:了解自己每日所需的卡路里摄入量,合理安排每餐的热量搭配,控制总摄入量。",
|
|||
|
|
"坚持低强度运动:逐渐增加日常活动量,如步行、瑜伽等,通过持续的轻度运动,加速代谢!",
|
|||
|
|
"合理休息调节:不要忽视睡眠的重要性,保证每晚充足的睡眠时间,帮助恢复体力和新陈代谢。",
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
original: [
|
|||
|
|
{
|
|||
|
|
title: "原创种草|这款干发帽真的值得入!",
|
|||
|
|
body: "洗完头最烦的就是湿哒哒滴水?试试这条双层加厚干发帽,吸水速度真的惊艳到我。",
|
|||
|
|
points: [
|
|||
|
|
"加厚材质,吸水更快更彻底",
|
|||
|
|
"柔软不勒头,长发短发都能用",
|
|||
|
|
"轻便好收纳,差旅党必备",
|
|||
|
|
"性价比超高,入手不亏",
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
imitate: [
|
|||
|
|
{
|
|||
|
|
title: "仿写爆款|让头发速干的小心机",
|
|||
|
|
body: "姐妹们有没有发现,最近超火的干发帽真的太好用了!轻轻一裹,几分钟头发就半干了。",
|
|||
|
|
points: [
|
|||
|
|
"双层加厚,吸水力翻倍",
|
|||
|
|
"柔软亲肤,不伤发质",
|
|||
|
|
"小巧便携,出门也能带",
|
|||
|
|
"颜值在线,多色可选",
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
wechat: [
|
|||
|
|
{
|
|||
|
|
title: "朋友圈文案|个位数到手的干发神器",
|
|||
|
|
body: "今天必须给大家安利这个干发帽!双层加厚,吸水超强,个位数就能到手,真的不冲吗?",
|
|||
|
|
points: [
|
|||
|
|
"微纤维材质,轻柔速干",
|
|||
|
|
"加厚设计,吸水更彻底",
|
|||
|
|
"小巧便携,旅行出差都能带",
|
|||
|
|
"限时好价,手慢无",
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
crossborder: [
|
|||
|
|
{
|
|||
|
|
title: "Amazon Listing|Super Absorbent Hair Turban",
|
|||
|
|
body: "Made with ultra-soft microfiber, this double-layer hair turban dries hair quickly while protecting delicate strands.",
|
|||
|
|
points: [
|
|||
|
|
"Double-layer microfiber for maximum absorbency",
|
|||
|
|
"Gentle on hair and skin, no frizz or breakage",
|
|||
|
|
"Lightweight and travel-friendly design",
|
|||
|
|
"Secure button closure stays in place",
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
emoji: [
|
|||
|
|
{
|
|||
|
|
title: "✨个位数到手的干发神器,吸水力 MAX!",
|
|||
|
|
body: "家人们👋,我发现了一款超棒的干发帽💧,双层加厚吸水力超强!而且只要个位数就能到手啊🛒!",
|
|||
|
|
points: [
|
|||
|
|
"💦 超强吸水力:微纤维材质,轻轻一裹水分吸走",
|
|||
|
|
"☁️ 柔软亲肤:触感温柔,不伤头发和皮肤",
|
|||
|
|
"🎒 方便携带:轻巧不占空间,旅行健身都能带",
|
|||
|
|
"💰 超值价格:个位数到手,性价比拉满",
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
more: [
|
|||
|
|
{
|
|||
|
|
title: "更多场景示例",
|
|||
|
|
body: "选择左侧具体文案类型即可生成对应场景内容,更多场景持续更新中。",
|
|||
|
|
points: ["选择合适的文案类型", "填写内容需求", "选择生成字数", "点击开始生成"],
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export interface EcommerceCopywritingPanelProps {
|
|||
|
|
onClose: () => void;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default function EcommerceCopywritingPanel({ onClose }: EcommerceCopywritingPanelProps) {
|
|||
|
|
const [selectedType, setSelectedType] = useState<CopywritingType>("self-media");
|
|||
|
|
const [requirement, setRequirement] = useState("");
|
|||
|
|
const [wordCount, setWordCount] = useState("不限");
|
|||
|
|
const [loading, setLoading] = useState(false);
|
|||
|
|
const [results, setResults] = useState<typeof exampleResults["self-media"]>([]);
|
|||
|
|
|
|||
|
|
const handleGenerate = () => {
|
|||
|
|
setLoading(true);
|
|||
|
|
setResults([]);
|
|||
|
|
// 模拟生成延迟
|
|||
|
|
window.setTimeout(() => {
|
|||
|
|
setResults(exampleResults[selectedType]);
|
|||
|
|
setLoading(false);
|
|||
|
|
}, 1200);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const selectedTypeLabel = copywritingTypes.find((item) => item.key === selectedType)?.label ?? "文案";
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<main className="ecom-copywriting-page ecom-tool-page-enter" aria-label="一键文案">
|
|||
|
|
<div className="ecom-copywriting-body">
|
|||
|
|
<aside className="ecom-copywriting-panel" aria-label="文案设置">
|
|||
|
|
<header className="ecom-copywriting-panel-head">
|
|||
|
|
<strong className="ecom-copywriting-page-title">一键文案</strong>
|
|||
|
|
<button type="button" className="ecom-copywriting-back" onClick={onClose}>
|
|||
|
|
首页
|
|||
|
|
</button>
|
|||
|
|
<button type="button" className="ecom-copywriting-back" onClick={onClose}>
|
|||
|
|
上一页
|
|||
|
|
</button>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<section className="ecom-copywriting-section">
|
|||
|
|
<strong className="ecom-copywriting-section-title">选择文案类型</strong>
|
|||
|
|
<div className="ecom-copywriting-type-grid">
|
|||
|
|
{copywritingTypes.map((item) => (
|
|||
|
|
<button
|
|||
|
|
key={item.key}
|
|||
|
|
type="button"
|
|||
|
|
className={`ecom-copywriting-type-card${selectedType === item.key ? " is-active" : ""}`}
|
|||
|
|
onClick={() => setSelectedType(item.key)}
|
|||
|
|
>
|
|||
|
|
<span className="ecom-copywriting-type-icon" aria-hidden="true">
|
|||
|
|
{item.icon}
|
|||
|
|
</span>
|
|||
|
|
<span className="ecom-copywriting-type-label">{item.label}</span>
|
|||
|
|
<span className="ecom-copywriting-type-desc">{item.description}</span>
|
|||
|
|
</button>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section className="ecom-copywriting-section">
|
|||
|
|
<strong className="ecom-copywriting-section-title">内容需求</strong>
|
|||
|
|
<textarea
|
|||
|
|
className="ecom-copywriting-textarea"
|
|||
|
|
value={requirement}
|
|||
|
|
onChange={(event) => setRequirement(event.target.value)}
|
|||
|
|
placeholder="例如:主题、核心卖点、适用人群、期望场景等"
|
|||
|
|
rows={5}
|
|||
|
|
/>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section className="ecom-copywriting-section">
|
|||
|
|
<strong className="ecom-copywriting-section-title">生成字数</strong>
|
|||
|
|
<div className="ecom-copywriting-wordcount">
|
|||
|
|
{wordCountOptions.map((item) => (
|
|||
|
|
<button
|
|||
|
|
key={item}
|
|||
|
|
type="button"
|
|||
|
|
className={wordCount === item ? "is-active" : ""}
|
|||
|
|
onClick={() => setWordCount(item)}
|
|||
|
|
>
|
|||
|
|
{item}
|
|||
|
|
</button>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<button
|
|||
|
|
type="button"
|
|||
|
|
className="ecom-copywriting-generate"
|
|||
|
|
onClick={handleGenerate}
|
|||
|
|
disabled={loading}
|
|||
|
|
>
|
|||
|
|
{loading ? (
|
|||
|
|
<>
|
|||
|
|
<span className="ecom-copywriting-spinner" />
|
|||
|
|
生成中…
|
|||
|
|
</>
|
|||
|
|
) : (
|
|||
|
|
<>
|
|||
|
|
<ThunderboltOutlined />
|
|||
|
|
开始生成
|
|||
|
|
</>
|
|||
|
|
)}
|
|||
|
|
</button>
|
|||
|
|
</aside>
|
|||
|
|
|
|||
|
|
<section className="ecom-copywriting-stage" aria-label="生成文案预览">
|
|||
|
|
<header className="ecom-copywriting-preview-head">
|
|||
|
|
<h1>生成文案</h1>
|
|||
|
|
<p>
|
|||
|
|
基于 <span>{selectedTypeLabel}</span> 风格,AI 为你生成高转化文案。
|
|||
|
|
</p>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<div className="ecom-copywriting-results">
|
|||
|
|
{results.length === 0 && !loading ? (
|
|||
|
|
<div className="ecom-copywriting-empty">
|
|||
|
|
<FileTextOutlined />
|
|||
|
|
<strong>等待生成</strong>
|
|||
|
|
<em>填写需求后点击「开始生成」即可查看文案结果</em>
|
|||
|
|
</div>
|
|||
|
|
) : null}
|
|||
|
|
|
|||
|
|
{loading ? (
|
|||
|
|
<div className="ecom-copywriting-loading">
|
|||
|
|
<span className="ecom-copywriting-spinner" />
|
|||
|
|
<span>AI 正在生成文案,请稍候…</span>
|
|||
|
|
</div>
|
|||
|
|
) : null}
|
|||
|
|
|
|||
|
|
{results.map((item, index) => (
|
|||
|
|
<article key={index} className="ecom-copywriting-result-card">
|
|||
|
|
<header>
|
|||
|
|
<span>示例 {index + 1}</span>
|
|||
|
|
<strong>{item.title}</strong>
|
|||
|
|
</header>
|
|||
|
|
<p className="ecom-copywriting-result-body">{item.body}</p>
|
|||
|
|
<ul className="ecom-copywriting-result-points">
|
|||
|
|
{item.points.map((point, pointIndex) => (
|
|||
|
|
<li key={pointIndex}>
|
|||
|
|
<span>{pointIndex + 1}</span>
|
|||
|
|
{point}
|
|||
|
|
</li>
|
|||
|
|
))}
|
|||
|
|
</ul>
|
|||
|
|
</article>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
</div>
|
|||
|
|
</main>
|
|||
|
|
);
|
|||
|
|
}
|