feat:完成微信公众号的自动化工具

This commit is contained in:
Daniel
2026-04-01 14:21:10 +08:00
commit 124a5f0192
16 changed files with 675 additions and 0 deletions

74
app/static/app.js Normal file
View File

@@ -0,0 +1,74 @@
const $ = (id) => document.getElementById(id);
const statusEl = $("status");
function setStatus(msg, danger = false) {
statusEl.style.color = danger ? "#b42318" : "#0f5f3d";
statusEl.textContent = msg;
}
async function postJSON(url, body) {
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const data = await res.json();
if (!res.ok) throw new Error(data.detail || "请求失败");
return data;
}
$("rewriteBtn").addEventListener("click", async () => {
const sourceText = $("sourceText").value.trim();
if (sourceText.length < 20) {
setStatus("原始内容太短,至少 20 个字符", true);
return;
}
setStatus("AI 改写中...");
try {
const data = await postJSON("/api/rewrite", {
source_text: sourceText,
title_hint: $("titleHint").value,
tone: $("tone").value,
audience: $("audience").value,
keep_points: $("keepPoints").value,
avoid_words: $("avoidWords").value,
});
$("title").value = data.title || "";
$("summary").value = data.summary || "";
$("body").value = data.body_markdown || "";
setStatus("改写完成,可直接发布。");
} catch (e) {
setStatus(`改写失败: ${e.message}`, true);
}
});
$("wechatBtn").addEventListener("click", async () => {
setStatus("正在发布到公众号草稿箱...");
try {
const data = await postJSON("/api/publish/wechat", {
title: $("title").value,
summary: $("summary").value,
body_markdown: $("body").value,
});
if (!data.ok) throw new Error(data.detail);
setStatus("公众号草稿发布成功");
} catch (e) {
setStatus(`公众号发布失败: ${e.message}`, true);
}
});
$("imBtn").addEventListener("click", async () => {
setStatus("正在发送到 IM...");
try {
const data = await postJSON("/api/publish/im", {
title: $("title").value,
body_markdown: $("body").value,
});
if (!data.ok) throw new Error(data.detail);
setStatus("IM 发送成功");
} catch (e) {
setStatus(`IM 发送失败: ${e.message}`, true);
}
});

117
app/static/style.css Normal file
View File

@@ -0,0 +1,117 @@
:root {
--bg: #f3f7f5;
--panel: #ffffff;
--line: #d7e3dd;
--text: #1a3128;
--muted: #5e7a6f;
--accent: #18794e;
--accent-2: #0f5f3d;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
background: radial-gradient(circle at 10% 20%, #e6f4ec, transparent 35%),
radial-gradient(circle at 90% 80%, #dff0ff, transparent 30%),
var(--bg);
color: var(--text);
font-family: "PingFang SC", "Noto Sans SC", "Microsoft YaHei", sans-serif;
}
.layout {
max-width: 1280px;
margin: 24px auto;
padding: 0 16px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.panel {
background: var(--panel);
border: 1px solid var(--line);
border-radius: 14px;
padding: 18px;
box-shadow: 0 8px 24px rgba(32, 84, 55, 0.07);
}
h1,
h2 {
margin-top: 0;
}
.muted {
color: var(--muted);
margin-top: -6px;
}
label {
display: block;
margin-top: 10px;
margin-bottom: 6px;
font-size: 14px;
font-weight: 600;
}
input,
textarea,
button {
width: 100%;
border-radius: 10px;
border: 1px solid var(--line);
padding: 10px 12px;
font-size: 14px;
}
textarea {
resize: vertical;
line-height: 1.5;
}
button {
cursor: pointer;
margin-top: 12px;
font-weight: 700;
}
button:hover {
filter: brightness(0.98);
}
button.primary {
background: var(--accent);
color: #fff;
border-color: var(--accent);
}
button.primary:hover {
background: var(--accent-2);
}
.actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.grid2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.status {
min-height: 22px;
margin-top: 8px;
color: var(--accent-2);
font-weight: 600;
}
@media (max-width: 960px) {
.layout {
grid-template-columns: 1fr;
}
}