From ac24853aa65cfd03cabb8f027d0552d5357f7720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=A1=E8=8B=A5?= Date: Sun, 25 Jan 2026 21:09:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=AE=A1=E7=90=86=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=85=8D=E8=B4=B9=E7=AB=A0=E8=8A=82=E5=92=8C?= =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 系统设置页新增免费章节管理(可动态添加/删除) 2. 新增小程序配置项(API域名、购买优惠、绑定天数等) 3. 前端从后端读取免费章节配置 4. 配置API支持新格式 --- app/admin/settings/page.tsx | 162 ++++++++++++++++++++++++++++++++- app/api/db/config/route.ts | 52 ++++++++++- miniprogram/pages/read/read.js | 16 ++++ 3 files changed, 228 insertions(+), 2 deletions(-) diff --git a/app/admin/settings/page.tsx b/app/admin/settings/page.tsx index c3480e5..2a2c5cf 100644 --- a/app/admin/settings/page.tsx +++ b/app/admin/settings/page.tsx @@ -8,8 +8,9 @@ import { Button } from "@/components/ui/button" import { Switch } from "@/components/ui/switch" import { Slider } from "@/components/ui/slider" import { Textarea } from "@/components/ui/textarea" +import { Badge } from "@/components/ui/badge" import { useStore } from "@/lib/store" -import { Save, Settings, Users, DollarSign, UserCircle, Calendar, MapPin, BookOpen } from "lucide-react" +import { Save, Settings, Users, DollarSign, UserCircle, Calendar, MapPin, BookOpen, Gift, X, Plus, Smartphone } from "lucide-react" export default function SettingsPage() { const { settings, updateSettings } = useStore() @@ -24,6 +25,36 @@ export default function SettingsPage() { }, }) const [isSaving, setIsSaving] = useState(false) + + // 免费章节配置 + const [freeChapters, setFreeChapters] = useState(['preface', 'epilogue', '1.1', 'appendix-1', 'appendix-2', 'appendix-3']) + const [newFreeChapter, setNewFreeChapter] = useState('') + + // 小程序配置 + const [mpConfig, setMpConfig] = useState({ + appId: 'wxb8bbb2b10dec74aa', + apiDomain: 'https://soul.quwanzhi.com', + buyerDiscount: 5, // 购买者优惠比例 + referralBindDays: 30, // 推荐绑定天数 + minWithdraw: 10, // 最低提现金额 + }) + + // 加载配置 + useEffect(() => { + const loadConfig = async () => { + try { + const res = await fetch('/api/db/config') + if (res.ok) { + const data = await res.json() + if (data.freeChapters) setFreeChapters(data.freeChapters) + if (data.mpConfig) setMpConfig(prev => ({ ...prev, ...data.mpConfig })) + } + } catch (e) { + console.log('Load config error:', e) + } + } + loadConfig() + }, []) useEffect(() => { setLocalSettings({ @@ -50,6 +81,13 @@ export default function SettingsPage() { body: JSON.stringify(localSettings) }) + // 保存免费章节和小程序配置 + await fetch('/api/db/config', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ freeChapters, mpConfig }) + }) + alert("设置已保存!") } catch (error) { console.error('Save settings error:', error) @@ -58,6 +96,19 @@ export default function SettingsPage() { setIsSaving(false) } } + + // 添加免费章节 + const addFreeChapter = () => { + if (newFreeChapter && !freeChapters.includes(newFreeChapter)) { + setFreeChapters([...freeChapters, newFreeChapter]) + setNewFreeChapter('') + } + } + + // 移除免费章节 + const removeFreeChapter = (chapter: string) => { + setFreeChapters(freeChapters.filter(c => c !== chapter)) + } return (
@@ -257,6 +308,115 @@ export default function SettingsPage() { + {/* 免费章节设置 */} + + + + + 免费章节 + + 设置哪些章节对所有用户免费开放 + + +
+ {freeChapters.map((chapter) => ( + + {chapter} + + + ))} +
+
+ setNewFreeChapter(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && addFreeChapter()} + /> + +
+

+ 常用ID: preface(序言), epilogue(尾声), appendix-1/2/3(附录), 1.1/1.2等(章节) +

+
+
+ + {/* 小程序配置 */} + + + + + 小程序配置 + + 微信小程序相关参数设置 + + +
+
+ + setMpConfig(prev => ({ ...prev, appId: e.target.value }))} + /> +
+
+ + setMpConfig(prev => ({ ...prev, apiDomain: e.target.value }))} + /> +
+
+
+
+ + setMpConfig(prev => ({ ...prev, buyerDiscount: Number(e.target.value) }))} + /> +
+
+ + setMpConfig(prev => ({ ...prev, referralBindDays: Number(e.target.value) }))} + /> +
+
+ + setMpConfig(prev => ({ ...prev, minWithdraw: Number(e.target.value) }))} + /> +
+
+
+
+ {/* 分销设置 */} diff --git a/app/api/db/config/route.ts b/app/api/db/config/route.ts index 49129b7..8590ea4 100644 --- a/app/api/db/config/route.ts +++ b/app/api/db/config/route.ts @@ -142,10 +142,28 @@ export async function GET(request: NextRequest) { } } + // 获取小程序配置 + let mpConfig = null + try { + mpConfig = await getConfig('mp_config') + } catch (e) {} + + // 提取前端需要的格式 + const bookConfig = allConfigs.book_config || DEFAULT_CONFIGS.book_config + return NextResponse.json({ success: true, configs: allConfigs, - sources + sources, + // 前端直接使用的格式 + freeChapters: bookConfig.freeSections || DEFAULT_CONFIGS.book_config.freeSections, + mpConfig: mpConfig || { + appId: 'wxb8bbb2b10dec74aa', + apiDomain: 'https://soul.quwanzhi.com', + buyerDiscount: 5, + referralBindDays: 30, + minWithdraw: 10 + } }) } catch (error) { @@ -159,10 +177,42 @@ export async function GET(request: NextRequest) { /** * POST - 保存配置到数据库 + * 支持两种格式: + * 1. { key, config } - 单个配置 + * 2. { freeChapters, mpConfig } - 批量配置 */ export async function POST(request: NextRequest) { try { const body = await request.json() + + // 支持批量配置格式 + if (body.freeChapters || body.mpConfig) { + let successCount = 0 + + // 保存免费章节配置 + if (body.freeChapters) { + const bookConfig = { + ...DEFAULT_CONFIGS.book_config, + freeSections: body.freeChapters + } + const success = await setConfig('book_config', bookConfig, '书籍配置-免费章节') + if (success) successCount++ + } + + // 保存小程序配置 + if (body.mpConfig) { + const success = await setConfig('mp_config', body.mpConfig, '小程序配置') + if (success) successCount++ + } + + return NextResponse.json({ + success: true, + message: `配置保存成功 (${successCount}项)`, + successCount + }) + } + + // 原有的单配置格式 const { key, config, description } = body if (!key || !config) { diff --git a/miniprogram/pages/read/read.js b/miniprogram/pages/read/read.js index cc698aa..5ad05f0 100644 --- a/miniprogram/pages/read/read.js +++ b/miniprogram/pages/read/read.js @@ -71,8 +71,24 @@ Page({ app.handleReferralCode({ query: { ref } }) } + // 加载免费章节配置 + this.loadFreeChaptersConfig() + this.initSection(id) }, + + // 从后端加载免费章节配置 + async loadFreeChaptersConfig() { + try { + const res = await app.request('/api/db/config') + if (res.success && res.freeChapters) { + this.setData({ freeIds: res.freeChapters }) + console.log('[Read] 加载免费章节配置:', res.freeChapters) + } + } catch (e) { + console.log('[Read] 使用默认免费章节配置') + } + }, onPageScroll(e) { // 计算阅读进度