chore(ui): sync latest manual canvas and settings updates
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-22 16:38:54 +08:00
parent c6c6c3f7bb
commit 9c4e51d3fd
5 changed files with 141 additions and 76 deletions

View File

@ -2316,7 +2316,11 @@ export function AdminSettingsClient() {
{/* 用户管理 */}
<TabsContent value="users" className="mt-6">
<Card>
<CardContent className="pt-6">
<CardHeader>
<CardTitle className="text-xl">用户管理</CardTitle>
<CardDescription>管理所有注册用户及其权限与积分</CardDescription>
</CardHeader>
<CardContent>
{/* 搜索框和同步按钮 */}
<div className="mb-4 flex flex-col sm:flex-row gap-3 sm:items-center sm:justify-between">
<Input
@ -2750,7 +2754,7 @@ export function AdminSettingsClient() {
{/* 图片详情弹窗 */}
<Dialog open={!!selectedImage} onOpenChange={(open) => !open && setSelectedImage(null)}>
<DialogContent className="max-w-2xl">
<DialogContent className="max-w-3xl max-h-[85vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
{selectedImage?.recordType === "video" ? "视频详情" : "图片详情"}
@ -2801,7 +2805,13 @@ export function AdminSettingsClient() {
</div>
<div>
<Label className="text-muted-foreground">模型</Label>
<p>{selectedImage.modelId || "未知"}</p>
<p>
{analyticsData?.modelDetailStats?.find(
(s) => s.modelId === selectedImage.modelId
)?.modelName ||
selectedImage.modelId ||
"未知"}
</p>
</div>
{selectedImage.recordType !== "video" ? (
<div>
@ -3382,7 +3392,11 @@ export function AdminSettingsClient() {
{/* 网站设置 */}
<TabsContent value="site" className="mt-6">
<Card>
<CardContent className="space-y-6 pt-6">
<CardHeader>
<CardTitle className="text-xl">网站基本设置</CardTitle>
<CardDescription>配置网站名称、LOGO、功能开关等</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="space-y-2">
<Label htmlFor="siteName">网站名称</Label>
<Input
@ -5427,7 +5441,11 @@ export function AdminSettingsClient() {
<TabsContent value="questions" className="mt-6">
<Card>
<CardContent className="space-y-4 pt-6">
<CardHeader>
<CardTitle className="text-xl">快捷短语</CardTitle>
<CardDescription>配置聊天输入框下方的预设快捷提问</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{questions.map((q, index) => (
<div key={index} className="flex gap-2">
<Input
@ -5458,7 +5476,11 @@ export function AdminSettingsClient() {
{/* 认证设置 */}
<TabsContent value="auth" className="mt-6">
<Card>
<CardContent className="space-y-6 pt-6">
<CardHeader>
<CardTitle className="text-xl">登录认证</CardTitle>
<CardDescription>配置开放注册、钉钉登录与Google登录</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="flex items-center justify-between">
<div className="space-y-0.5">
<Label>开放注册</Label>
@ -5673,7 +5695,11 @@ export function AdminSettingsClient() {
{/* 系统通知设置 */}
<TabsContent value="notification" className="mt-6">
<Card>
<CardContent className="space-y-6 pt-6">
<CardHeader>
<CardTitle className="text-xl">系统通知</CardTitle>
<CardDescription>发布全站公告通知,用户进入系统时可见</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="flex items-center gap-2">
<Switch
id="notification-enabled"
@ -6525,49 +6551,63 @@ export function AdminSettingsClient() {
{/* 抠图API配置 */}
<Card>
<CardHeader>
<CardTitle>抠图API配置</CardTitle>
<CardTitle className="text-xl">抠图API配置</CardTitle>
<CardDescription>
配置背景移除API,用于画图标注功能中的抠图处理。支持自部署RMBG、PhotoRoom和AOS云服务。
</CardDescription>
</CardHeader>
<CardContent className="space-y-6 pt-6">
{/* 服务提供商选择 */}
<div className="space-y-2">
<div className="space-y-3">
<Label>抠图服务提供商</Label>
<div className="flex gap-4">
<label className="flex items-center gap-2 cursor-pointer">
<input
type="radio"
name="rmbgProvider"
value="rmbg"
checked={rmbgConfig.provider === "rmbg"}
onChange={() => setRmbgConfig({ ...rmbgConfig, provider: "rmbg" })}
className="w-4 h-4"
/>
<span className="text-sm">RMBG-2.0 (自部署)</span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<input
type="radio"
name="rmbgProvider"
value="photoroom"
checked={rmbgConfig.provider === "photoroom"}
onChange={() => setRmbgConfig({ ...rmbgConfig, provider: "photoroom" })}
className="w-4 h-4"
/>
<span className="text-sm">PhotoRoom (云服务)</span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<input
type="radio"
name="rmbgProvider"
value="aoscdn"
checked={rmbgConfig.provider === "aoscdn"}
onChange={() => setRmbgConfig({ ...rmbgConfig, provider: "aoscdn" })}
className="w-4 h-4"
/>
<span className="text-sm">AOS Segmentation (云服务)</span>
</label>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div
className={`relative flex cursor-pointer items-center gap-3 rounded-lg border p-4 transition-all hover:bg-accent ${
rmbgConfig.provider === "rmbg" ? "border-primary bg-accent ring-1 ring-primary" : ""
}`}
onClick={() => setRmbgConfig({ ...rmbgConfig, provider: "rmbg" })}
>
<div className={`flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-primary ${
rmbgConfig.provider === "rmbg" ? "bg-primary text-primary-foreground" : "bg-transparent"
}`}>
{rmbgConfig.provider === "rmbg" && <Check className="h-3 w-3" />}
</div>
<div className="space-y-1">
<p className="text-sm font-medium leading-none">RMBG-2.0 (自部署)</p>
</div>
</div>
<div
className={`relative flex cursor-pointer items-center gap-3 rounded-lg border p-4 transition-all hover:bg-accent ${
rmbgConfig.provider === "photoroom" ? "border-primary bg-accent ring-1 ring-primary" : ""
}`}
onClick={() => setRmbgConfig({ ...rmbgConfig, provider: "photoroom" })}
>
<div className={`flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-primary ${
rmbgConfig.provider === "photoroom" ? "bg-primary text-primary-foreground" : "bg-transparent"
}`}>
{rmbgConfig.provider === "photoroom" && <Check className="h-3 w-3" />}
</div>
<div className="space-y-1">
<p className="text-sm font-medium leading-none">PhotoRoom (云服务)</p>
</div>
</div>
<div
className={`relative flex cursor-pointer items-center gap-3 rounded-lg border p-4 transition-all hover:bg-accent ${
rmbgConfig.provider === "aoscdn" ? "border-primary bg-accent ring-1 ring-primary" : ""
}`}
onClick={() => setRmbgConfig({ ...rmbgConfig, provider: "aoscdn" })}
>
<div className={`flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-primary ${
rmbgConfig.provider === "aoscdn" ? "bg-primary text-primary-foreground" : "bg-transparent"
}`}>
{rmbgConfig.provider === "aoscdn" && <Check className="h-3 w-3" />}
</div>
<div className="space-y-1">
<p className="text-sm font-medium leading-none">AOS Segmentation</p>
</div>
</div>
</div>
</div>
@ -6710,10 +6750,15 @@ export function AdminSettingsClient() {
关闭时保持原图尺寸,开启时按主体区域裁剪。
</div>
</div>
<Switch
checked={rmbgConfig.aosCrop}
onCheckedChange={(checked) => setRmbgConfig({ ...rmbgConfig, aosCrop: checked })}
/>
<div className="flex items-center gap-2">
<Switch
checked={rmbgConfig.aosCrop}
onCheckedChange={(checked) => setRmbgConfig({ ...rmbgConfig, aosCrop: checked })}
/>
<span className="text-sm font-medium text-muted-foreground min-w-[3rem]">
{rmbgConfig.aosCrop ? "已开启" : "已关闭"}
</span>
</div>
</div>
<div className="rounded-lg border border-indigo-200 bg-indigo-50 p-4 space-y-2">
<div className="text-sm font-medium text-indigo-900">AOS 说明</div>
@ -6735,7 +6780,7 @@ export function AdminSettingsClient() {
{/* 变清晰API配置 */}
<Card>
<CardHeader>
<CardTitle>变清晰API配置</CardTitle>
<CardTitle className="text-xl">变清晰API配置</CardTitle>
<CardDescription>
配置图片变清晰API,用于画图标注功能中的图片增强处理。支持主API和备用API切换。
</CardDescription>
@ -6749,10 +6794,15 @@ export function AdminSettingsClient() {
启用后将使用Real-ESRGAN本地模型进行图片增强,效果更好
</div>
</div>
<Switch
checked={enhanceConfig.useBackupApi}
onCheckedChange={(checked) => setEnhanceConfig({ ...enhanceConfig, useBackupApi: checked })}
/>
<div className="flex items-center gap-2">
<Switch
checked={enhanceConfig.useBackupApi}
onCheckedChange={(checked) => setEnhanceConfig({ ...enhanceConfig, useBackupApi: checked })}
/>
<span className="text-sm font-medium text-muted-foreground min-w-[3rem]">
{enhanceConfig.useBackupApi ? "已开启" : "已关闭"}
</span>
</div>
</div>
{/* 主API配置 */}
@ -6930,7 +6980,7 @@ export function AdminSettingsClient() {
{/* 图像拓展API配置 */}
<Card>
<CardHeader>
<CardTitle>图像拓展API配置</CardTitle>
<CardTitle className="text-xl">图像拓展API配置</CardTitle>
<CardDescription>
配置阿里云Dashscope图像拓展API,用于画图标注功能中的图像智能扩展处理
</CardDescription>
@ -7003,7 +7053,7 @@ export function AdminSettingsClient() {
{/* 去水印API配置 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CardTitle className="flex items-center gap-2 text-xl">
<svg className="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z" />
<line x1="4" y1="4" x2="20" y2="20" />
@ -7046,7 +7096,7 @@ export function AdminSettingsClient() {
{/* 角度编辑API配置 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CardTitle className="flex items-center gap-2 text-xl">
<Move3D className="h-5 w-5" />
角度编辑API配置
</CardTitle>
@ -7063,10 +7113,15 @@ export function AdminSettingsClient() {
开启后用户可在图片编辑器中使用角度编辑功能
</div>
</div>
<Switch
checked={angleEditConfig.enabled}
onCheckedChange={(checked) => setAngleEditConfig({ ...angleEditConfig, enabled: checked })}
/>
<div className="flex items-center gap-2">
<Switch
checked={angleEditConfig.enabled}
onCheckedChange={(checked) => setAngleEditConfig({ ...angleEditConfig, enabled: checked })}
/>
<span className="text-sm font-medium text-muted-foreground min-w-[3rem]">
{angleEditConfig.enabled ? "已开启" : "已关闭"}
</span>
</div>
</div>
<Separator />
@ -7205,7 +7260,7 @@ export function AdminSettingsClient() {
{/* 实时画布API配置 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CardTitle className="flex items-center gap-2 text-xl">
<Paintbrush className="h-5 w-5" />
实时画布配置
</CardTitle>
@ -7221,12 +7276,17 @@ export function AdminSettingsClient() {
关闭后前端“实时画布”入口仍可显示,但会提示服务未启用。
</div>
</div>
<Switch
checked={realtimeCanvasConfig.enabled}
onCheckedChange={(checked) =>
setRealtimeCanvasConfig({ ...realtimeCanvasConfig, enabled: checked })
}
/>
<div className="flex items-center gap-2">
<Switch
checked={realtimeCanvasConfig.enabled}
onCheckedChange={(checked) =>
setRealtimeCanvasConfig({ ...realtimeCanvasConfig, enabled: checked })
}
/>
<span className="text-sm font-medium text-muted-foreground min-w-[3rem]">
{realtimeCanvasConfig.enabled ? "已开启" : "已关闭"}
</span>
</div>
</div>
<div className="space-y-2">
@ -7391,7 +7451,7 @@ export function AdminSettingsClient() {
{/* 详情替换配置 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CardTitle className="flex items-center gap-2 text-xl">
<Sparkles className="h-5 w-5" />
详情替换配置
</CardTitle>
@ -7408,10 +7468,15 @@ export function AdminSettingsClient() {
开启后用户可在图片编辑器中使用详情替换功能
</div>
</div>
<Switch
checked={sceneFusionConfig.enabled}
onCheckedChange={(checked) => setSceneFusionConfig({ ...sceneFusionConfig, enabled: checked })}
/>
<div className="flex items-center gap-2">
<Switch
checked={sceneFusionConfig.enabled}
onCheckedChange={(checked) => setSceneFusionConfig({ ...sceneFusionConfig, enabled: checked })}
/>
<span className="text-sm font-medium text-muted-foreground min-w-[3rem]">
{sceneFusionConfig.enabled ? "已开启" : "已关闭"}
</span>
</div>
</div>
{/* 默认提示词 */}

View File

@ -5397,7 +5397,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
}, [activeSessionTitle, projectTitle]);
return (
<div className="relative flex h-full min-h-0 flex-col bg-background/50 backdrop-blur-sm">
<div className="relative flex h-full min-h-0 flex-col bg-background">
{/* 全局遮罩提示 - 当处于画布选图模式时显示 */}
{detailSlotPickerIndex !== null && (
<div className="absolute inset-0 z-50 flex flex-col items-center justify-center bg-background/80 backdrop-blur-sm animate-in fade-in duration-200">
@ -6052,7 +6052,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
)}
{/* 底部输入区域 - 混合输入(图片标签+文字可自由混合) */}
<div className="p-4 bg-background/80 backdrop-blur-md border-t">
<div className="p-4 bg-background border-t">
<div
className="relative flex flex-col bg-card rounded-3xl border transition-all duration-200 focus-within:border-primary/50 focus-within:bg-background"
data-canvas-chat-input-anchor="true"

View File

@ -99,7 +99,7 @@ export function CanvasFileList({ open, onOpenChange, currentId }: CanvasFileList
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-md max-h-[80vh] flex flex-col p-0 gap-0 overflow-hidden bg-background/90 backdrop-blur-md">
<DialogContent className="max-w-md max-h-[80vh] flex flex-col p-0 gap-0 overflow-hidden bg-background">
<DialogHeader className="p-4 border-b">
<div className="flex items-center justify-between">
<DialogTitle>已生成文件列表</DialogTitle>

View File

@ -956,7 +956,7 @@ export function RealtimeCanvasDialog({
</DialogHeader>
{/* Top Header - Minimal */}
<div className="absolute left-0 right-0 top-0 z-50 flex h-14 items-center justify-start px-6 bg-gradient-to-b from-black/20 to-transparent pointer-events-none">
<div className="pointer-events-auto flex items-center gap-3 rounded-full bg-background/80 backdrop-blur-md px-4 py-1.5 border border-border/50 shadow-sm">
<div className="pointer-events-auto flex items-center gap-3 rounded-full bg-background px-4 py-1.5 border border-border/50 shadow-sm">
<span className="font-semibold text-sm">Realtime Canvas</span>
<div className="h-4 w-[1px] bg-border" />
<span className={cn("flex items-center gap-1.5 text-xs font-medium", statusBadge.className, "bg-transparent p-0")}>

View File

@ -45,7 +45,7 @@ const DialogContent = forwardRef<
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<DialogPrimitive.Close className="absolute right-4 top-4 z-[100] rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>