feat(*): 创作配置 - 支持 Midjourney、多图保存与自定义公告
Co-authored-by: ddcat666 <26564566+ddcat666@users.noreply.github.com>
This commit is contained in:
1 parent
002a45f0c3
commit
853c7d2ce7
107 files changed
+9261
-408
No files matched your search
@@ -8,6 +8,8 @@ import { Switch } from "@/pages/admin/ui/controls";
|
||||
import { WelcomeSetting } from "@/pages/admin/settings/components/welcome-setting";
|
||||
import { SkinThemeEditor } from "@/pages/admin/settings/components/skin-theme-editor";
|
||||
import { CanvasAppearanceEditor } from "./components/canvas-appearance-editor";
|
||||
import { UpdateAnnouncementEditor } from "./components/update-announcement-editor";
|
||||
import { DEFAULT_UPDATE_ANNOUNCEMENT, normalizeUpdateAnnouncement, validateUpdateAnnouncement, type UpdateAnnouncement } from "@/lib/update-announcement";
|
||||
import { App, Button, Tabs, Form, Input } from "antd";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useBlocker } from "react-router";
|
||||
@@ -28,6 +30,7 @@ export default function AppearanceSettingsPage() {
|
||||
const [setting, setSetting] = useState<AdminAppearance | null>(null);
|
||||
const [brandName, setBrandName] = useState("");
|
||||
const [canvas, setCanvas] = useState<CanvasAppearance>(DEFAULT_CANVAS_APPEARANCE);
|
||||
const [updates, setUpdates] = useState<UpdateAnnouncement>(DEFAULT_UPDATE_ANNOUNCEMENT);
|
||||
const [canvasUploading, setCanvasUploading] = useState(false);
|
||||
const [brandSlug, setBrandSlug] = useState("");
|
||||
const [authHeroTitle, setAuthHeroTitle] = useState("");
|
||||
@@ -59,7 +62,10 @@ export default function AppearanceSettingsPage() {
|
||||
|
||||
const dirty =
|
||||
Boolean(setting) &&
|
||||
(JSON.stringify(canvas) !== JSON.stringify(setting?.canvas || DEFAULT_CANVAS_APPEARANCE) || canvasUploading || brandName.trim() !== setting?.brandName ||
|
||||
(JSON.stringify(updates) !== JSON.stringify(normalizeUpdateAnnouncement(setting?.updates)) ||
|
||||
JSON.stringify(canvas) !== JSON.stringify(setting?.canvas || DEFAULT_CANVAS_APPEARANCE) ||
|
||||
canvasUploading ||
|
||||
brandName.trim() !== setting?.brandName ||
|
||||
brandSlug.trim().toLocaleLowerCase() !== setting?.brandSlug ||
|
||||
normalizeDraftCopy(authHeroTitle) !== setting?.authHeroTitle ||
|
||||
normalizeDraftCopy(authHeroDescription) !== setting?.authHeroDescription ||
|
||||
@@ -83,6 +89,7 @@ export default function AppearanceSettingsPage() {
|
||||
setSetting({ ...value, skinThemes: themes, skinId: selectedID });
|
||||
setBrandName(value.brandName);
|
||||
setCanvas(value.canvas || DEFAULT_CANVAS_APPEARANCE);
|
||||
setUpdates(normalizeUpdateAnnouncement(value.updates));
|
||||
setBrandSlug(value.brandSlug);
|
||||
setAuthHeroTitle(value.authHeroTitle);
|
||||
setAuthHeroDescription(value.authHeroDescription);
|
||||
@@ -135,7 +142,7 @@ export default function AppearanceSettingsPage() {
|
||||
if (blocker.state !== "blocked") return;
|
||||
modal.confirm({
|
||||
title: "放弃站点及外观调整?",
|
||||
content: "当前品牌、画布 Agent、SEO、备案、皮肤或媒体配置尚未保存,离开后草稿会丢失。线上站点不会改变。",
|
||||
content: "当前品牌、画布 Agent、更新公告、SEO、备案、皮肤或媒体配置尚未保存,离开后草稿会丢失。线上站点不会改变。",
|
||||
okText: "放弃并离开",
|
||||
cancelText: "继续编辑",
|
||||
okButtonProps: { danger: true },
|
||||
@@ -192,6 +199,7 @@ export default function AppearanceSettingsPage() {
|
||||
const discardDraft = () => {
|
||||
if (!setting || saving || restoring || canvasUploading) return;
|
||||
setCanvas(setting.canvas || DEFAULT_CANVAS_APPEARANCE);
|
||||
setUpdates(normalizeUpdateAnnouncement(setting.updates));
|
||||
setBrandName(setting.brandName);
|
||||
setBrandSlug(setting.brandSlug);
|
||||
setAuthHeroTitle(setting.authHeroTitle);
|
||||
@@ -222,7 +230,7 @@ export default function AppearanceSettingsPage() {
|
||||
}
|
||||
modal.confirm({
|
||||
title: "放弃调整并重新读取?",
|
||||
content: "重新读取会丢弃当前品牌、画布 Agent、SEO、备案、皮肤和待上传文件。",
|
||||
content: "重新读取会丢弃当前品牌、画布 Agent、更新公告、SEO、备案、皮肤和待上传文件。",
|
||||
okText: "放弃并刷新",
|
||||
cancelText: "继续编辑",
|
||||
okButtonProps: { danger: true },
|
||||
@@ -234,7 +242,7 @@ export default function AppearanceSettingsPage() {
|
||||
if (!setting?.configured || saving || refreshing || restoring || canvasUploading) return;
|
||||
modal.confirm({
|
||||
title: "恢复影策默认品牌标识?",
|
||||
content: "品牌名称、英文标识、Logo、画布 Agent 名称/文案/形象、登录页文案、视频、封面、SEO、备案和皮肤主题会立即恢复为项目内置值。已上传文件仍保留在存储资源中,不会被删除。",
|
||||
content: "品牌名称、英文标识、Logo、画布 Agent 名称/文案/形象、更新公告、登录页文案、视频、封面、SEO、备案和皮肤主题会立即恢复为项目内置值;自定义公告会清空并关闭,展示原有更新日志。已上传文件仍保留在存储资源中,不会被删除。",
|
||||
okText: "恢复默认",
|
||||
cancelText: "取消",
|
||||
okButtonProps: { danger: true },
|
||||
@@ -261,6 +269,12 @@ export default function AppearanceSettingsPage() {
|
||||
|
||||
const save = async () => {
|
||||
if (!setting || saving || restoring || canvasUploading) return;
|
||||
const updatesError = validateUpdateAnnouncement(updates);
|
||||
if (updatesError) {
|
||||
setActiveTab("updates");
|
||||
message.error(updatesError);
|
||||
return;
|
||||
}
|
||||
if (![canvas.agentName, canvas.panelTitle, canvas.welcomeTitle, canvas.inputPlaceholder].every((text) => text.trim())) {
|
||||
setActiveTab("canvas");
|
||||
message.error("请填写助手名称、面板标题、欢迎标题和输入框提示");
|
||||
@@ -337,6 +351,7 @@ export default function AppearanceSettingsPage() {
|
||||
}
|
||||
const updated = await updateAdminAppearance({
|
||||
canvas,
|
||||
updates,
|
||||
brandName: nextBrandName,
|
||||
brandSlug: nextBrandSlug,
|
||||
authHeroTitle: nextAuthHeroTitle,
|
||||
@@ -445,7 +460,7 @@ export default function AppearanceSettingsPage() {
|
||||
<strong>{dirty ? "站点配置有调整待保存" : "站点及外观已与服务端同步"}</strong>
|
||||
<AdminStatusBadge label={dirty ? "尚未生效" : "服务端当前值"} tone={dirty ? "warning" : "neutral"} />
|
||||
</div>
|
||||
<p>{dirty ? "切换分类保留草稿;保存修改会一次应用品牌、登录页、SEO、备案和皮肤调整。" : "按分类管理站点配置;欢迎页开关独立即时保存,其余修改统一保存。"}</p>
|
||||
<p>{dirty ? "切换分类保留草稿;保存修改会一次应用品牌、登录页、更新公告、SEO、备案和皮肤调整。" : "按分类管理站点配置;欢迎页开关独立即时保存,其余修改统一保存。"}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="admin-appearance-command-actions">
|
||||
@@ -650,12 +665,7 @@ export default function AppearanceSettingsPage() {
|
||||
key: "welcome",
|
||||
label: "欢迎页",
|
||||
children: (
|
||||
<SettingsSectionCard
|
||||
className="admin-appearance-section"
|
||||
icon={<Globe2 className="size-4" aria-hidden="true" />}
|
||||
title="欢迎页"
|
||||
description="控制访客是否可以访问欢迎页,开关修改后立即保存。"
|
||||
>
|
||||
<SettingsSectionCard className="admin-appearance-section" icon={<Globe2 className="size-4" aria-hidden="true" />} title="欢迎页" description="控制访客是否可以访问欢迎页,开关修改后立即保存。">
|
||||
<div className="admin-appearance-section-form">
|
||||
<WelcomeSetting />
|
||||
</div>
|
||||
@@ -761,7 +771,8 @@ export default function AppearanceSettingsPage() {
|
||||
</SettingsSectionCard>
|
||||
),
|
||||
},
|
||||
{ key: "canvas", label: "画布配置", children: <CanvasAppearanceEditor value={canvas} onChange={setCanvas} disabled={saving || refreshing || restoring} onUploading={setCanvasUploading} /> },
|
||||
{ key: "canvas", label: "画布配置", children: <CanvasAppearanceEditor value={canvas} onChange={setCanvas} disabled={saving || refreshing || restoring || canvasUploading} onUploading={setCanvasUploading} /> },
|
||||
{ key: "updates", label: "更新公告", children: <UpdateAnnouncementEditor value={updates} onChange={setUpdates} disabled={saving || refreshing || restoring || canvasUploading} onUploading={setCanvasUploading} /> },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user