diff --git a/core/backend/apps/ai/creation_presets.py b/core/backend/apps/ai/creation_presets.py index 855598c..1a689bc 100644 --- a/core/backend/apps/ai/creation_presets.py +++ b/core/backend/apps/ai/creation_presets.py @@ -64,6 +64,9 @@ IMAGE_PRESETS: dict[str, str] = { "黑金高级": "黑金奢华商业摄影,深黑背景,金色高光,低调曝光,高对比度,强烈明暗塑形,精准轮廓光,金属反射质感,高级镜面反射,深邃黑位,暖金色点缀,低饱和、精致、克制、奢华,高端广告摄影质感。", "冷峻科技": "现代科技商业摄影,冷灰蓝色调,低饱和,高级冷色温,干净硬朗的光线,精准边缘光,金属与玻璃质感清晰,适度高对比,深灰阴影,简洁现代,锐利清晰但不过度数字化,真实产品摄影质感,理性、专业、克制,避免科幻全息、机器人和过度AI视觉元素。", "赛博朋克": "赛博朋克摄影风格,蓝紫与洋红霓虹色调,高饱和霓虹光,强烈冷暖色彩碰撞,高对比,深黑阴影,彩色轮廓光,霓虹反射,局部RGB光效,未来都市视觉语言,强烈视觉冲击,暗部层次丰富,真实摄影质感,科技感与潮流感结合,避免雨天效果。", + "日系手绘动画": "经典日系手绘动画电影质感,柔和自然配色,清新青绿与天空蓝色调,温暖阳光,细腻手绘线条,水彩与赛璐璐结合质感,柔和阴影,自然光影,丰富植物细节,轻微纸张与颜料肌理,童话般自然环境,宁静治愈,清新、温暖、诗意、生活感,具有传统二维动画电影质感,避免3D塑料感、过度数字化和强烈锐化。", + "国风水墨": "中国传统水墨画风格,黑白灰墨色体系,淡青与赭石少量点染,水墨晕染,浓淡干湿变化,焦墨、淡墨与泼墨结合,宣纸自然肌理,山水皴法,虚实相生,大面积留白,云雾朦胧,柔和层次,写意而不过度抽象,空灵、含蓄、诗意、东方禅意,强调墨韵与意境,避免高饱和、现代摄影感和西式油画质感。", + "新中式": "现代新中式东方美学,传统中国元素与现代极简设计融合,黑白灰、原木色、墨绿与低饱和暖色体系,大面积留白,克制高级配色,简洁几何构图,中式格栅、山石、竹、松、水景等东方元素适度点缀,柔和自然光,细腻材质,现代空间感与传统意境结合,宋式审美,安静、雅致、克制、高级,商业视觉质感,避免大红大金、复杂雕花和俗艳传统元素。", } # 来源于「图片创作预设.docx」的统一生成收束。用户界面只展示预设标题; diff --git a/core/backend/apps/ai/test_creation_agent.py b/core/backend/apps/ai/test_creation_agent.py index 68cace6..c08bc65 100644 --- a/core/backend/apps/ai/test_creation_agent.py +++ b/core/backend/apps/ai/test_creation_agent.py @@ -1310,12 +1310,20 @@ class PresetGuidanceTests(CreationAgentBaseTests): self.assertIn("避免过度HDR", prompt) self.assertEqual(apply_image_preset_prompt("电影感", prompt), prompt) + def test_new_image_preset_style_is_added_to_the_actual_image_prompt(self): + from .creation_presets import apply_image_preset_prompt + + prompt = apply_image_preset_prompt("国风水墨", "画一只白瓷茶杯") + self.assertIn("【图片风格预设】国风水墨", prompt) + self.assertIn("中国传统水墨画风格", prompt) + self.assertIn("避免高饱和、现代摄影感", prompt) + def test_every_frontend_preset_has_guidance(self): - """前端 9 个视频 + 9 个图片预设都要有拍法,漏一个就等于那张卡是摆设。""" + """前端 9 个视频 + 12 个图片预设都要有拍法,漏一个就等于那张卡是摆设。""" from .creation_presets import IMAGE_PRESETS, VIDEO_PRESETS self.assertEqual(len(VIDEO_PRESETS), 9) - self.assertEqual(len(IMAGE_PRESETS), 9) + self.assertEqual(len(IMAGE_PRESETS), 12) self.assertTrue(all(text.strip() for text in {**VIDEO_PRESETS, **IMAGE_PRESETS}.values())) diff --git a/core/frontend/_verify-1100.png b/core/frontend/_verify-1100.png new file mode 100644 index 0000000..a14225a Binary files /dev/null and b/core/frontend/_verify-1100.png differ diff --git a/core/frontend/_verify-420.png b/core/frontend/_verify-420.png new file mode 100644 index 0000000..a25cd23 Binary files /dev/null and b/core/frontend/_verify-420.png differ diff --git a/core/frontend/_verify-700.png b/core/frontend/_verify-700.png new file mode 100644 index 0000000..54206b2 Binary files /dev/null and b/core/frontend/_verify-700.png differ diff --git a/core/frontend/public/assets/image-presets/chinese-ink-wash.png b/core/frontend/public/assets/image-presets/chinese-ink-wash.png new file mode 100644 index 0000000..6dca9d3 Binary files /dev/null and b/core/frontend/public/assets/image-presets/chinese-ink-wash.png differ diff --git a/core/frontend/public/assets/image-presets/japanese-hand-drawn-anime.png b/core/frontend/public/assets/image-presets/japanese-hand-drawn-anime.png new file mode 100644 index 0000000..535c5cf Binary files /dev/null and b/core/frontend/public/assets/image-presets/japanese-hand-drawn-anime.png differ diff --git a/core/frontend/public/assets/image-presets/neo-chinese.png b/core/frontend/public/assets/image-presets/neo-chinese.png new file mode 100644 index 0000000..128b87f Binary files /dev/null and b/core/frontend/public/assets/image-presets/neo-chinese.png differ diff --git a/core/frontend/src/login-page.css b/core/frontend/src/login-page.css index 609e4aa..4c7fc86 100644 --- a/core/frontend/src/login-page.css +++ b/core/frontend/src/login-page.css @@ -156,9 +156,11 @@ .login-page .login-form-panel { position: relative; z-index: auto; - overflow: hidden; + overflow: auto; display: grid; - place-items: center; + align-content: safe center; + justify-items: center; + gap: 16px; padding: clamp(48px, 6vw, 106px); background: transparent; } @@ -203,7 +205,8 @@ position: relative; z-index: 2; width: min(100%, 520px); - height: 548px; + height: auto; + min-height: 0; padding: 44px 46px 38px; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.28); @@ -452,11 +455,12 @@ .login-page .login-submit { height: 54px; + min-width: 0; + width: 100%; display: flex; align-items: center; justify-content: center; gap: 10px; - margin-top: 2px; border: 0; border-radius: 11px; color: #fff; @@ -478,51 +482,130 @@ filter: saturate(0.85); } .login-page .login-submit:disabled svg { animation: login-spin 800ms linear infinite; } -.login-page .login-submit svg { width: 17px; height: 17px; } +.login-page .login-submit svg { width: 17px; height: 17px; flex: 0 0 auto; } -.login-page .login-extras { - position: absolute; - z-index: 2; - left: 50%; - bottom: 28px; - width: min(calc(100% - 48px), 520px); - display: grid; - gap: 10px; - color: rgba(255, 255, 255, 0.48); - font-size: 12px; - transform: translateX(-50%); -} .login-page .login-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; + min-width: 0; + color: rgba(255, 255, 255, 0.48); + font-size: 12px; } .login-page .login-row label { display: inline-flex; align-items: center; gap: 8px; + min-width: 0; cursor: pointer; } .login-page .login-row input[type="checkbox"] { width: 14px; height: 14px; + flex: 0 0 auto; accent-color: #7da1ff; } .login-page .login-row a, .login-page .login-switch a { color: rgba(183, 204, 255, 0.88); text-decoration: none; + white-space: nowrap; } .login-page .login-row a:hover, .login-page .login-switch a:hover { text-decoration: underline; } +/* 三入口操作条:同宽收进卡片,小屏改纵向避免撑破 */ +.login-page .login-actions { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 1fr); + align-items: stretch; + gap: 0; + min-width: 0; + width: 100%; + max-width: 100%; + overflow: hidden; + border-radius: 11px; + background: linear-gradient(135deg, #002d9f, #001d70 76%); + box-shadow: 0 14px 30px rgba(0, 25, 102, 0.32); +} +.login-page .login-actions .login-submit { + margin-top: 0; + border-radius: 0; + background: transparent; + box-shadow: none; +} +.login-page .login-actions .login-submit:hover:not(:disabled) { + transform: none; + filter: brightness(1.08); + box-shadow: none; +} +.login-page .login-action-alt { + min-width: 0; + height: 54px; + padding: 0 8px; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + border: 0; + border-radius: 0; + color: rgba(255, 255, 255, 0.88); + background: transparent; + font: inherit; + font-size: 12px; + line-height: 1.2; + cursor: pointer; +} +.login-page .login-action-alt + .login-submit, +.login-page .login-submit + .login-action-alt { + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.16); +} +.login-page .login-action-alt span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.login-page .login-action-alt:hover { background: rgba(255, 255, 255, 0.08); } +.login-page .login-action-alt svg { width: 14px; height: 14px; flex: 0 0 auto; } + +.login-page .login-switch { + margin: 18px 0 0; + text-align: center; + color: rgba(255, 255, 255, 0.48); + font-size: 12px; +} + +.login-page .login-card-footer { + display: flex; + align-items: center; + justify-content: center; + gap: 7px; + margin-top: 14px; + color: rgba(255, 255, 255, 0.54); + font-size: 10px; +} +.login-page .login-card-footer svg { width: 13px; height: 13px; } + +/* 注册页仍可能引用旧 extras 容器,保留文档流兜底 */ +.login-page .login-extras { + position: static; + z-index: 2; + width: min(100%, 520px); + display: grid; + gap: 10px; + color: rgba(255, 255, 255, 0.48); + font-size: 12px; + transform: none; +} .login-page .login-sso { display: grid; - grid-template-columns: 1fr 1fr; + grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; + min-width: 0; } .login-page .login-sso button { + min-width: 0; height: 36px; display: inline-flex; align-items: center; @@ -537,24 +620,7 @@ cursor: pointer; } .login-page .login-sso button:hover { background: rgba(255, 255, 255, 0.08); } -.login-page .login-sso svg { width: 14px; height: 14px; } - -.login-page .login-switch { - text-align: center; - color: rgba(255, 255, 255, 0.48); - font-size: 12px; -} - -.login-page .login-card-footer { - display: flex; - align-items: center; - justify-content: center; - gap: 7px; - margin-top: 26px; - color: rgba(255, 255, 255, 0.54); - font-size: 10px; -} -.login-page .login-card-footer svg { width: 13px; height: 13px; } +.login-page .login-sso svg { width: 14px; height: 14px; flex: 0 0 auto; } .login-page .login-note { margin: 0; @@ -649,6 +715,9 @@ } .login-page .login-visual { display: none; } .login-page .login-form-panel { + align-content: start; + justify-items: center; + gap: 16px; overflow: auto; padding: 32px 20px 28px; } @@ -674,6 +743,70 @@ position: static; width: min(100%, 480px); transform: none; - margin-top: 16px; + margin-top: 0; + } + .login-page .login-card-heading { margin-bottom: 28px; } + .login-page .login-form { gap: 14px; } +} + +/* 窄屏:主登录在上,两侧入口两列在下 */ +@media (max-width: 560px) { + .login-page .login-form-panel { + padding: 24px 14px 20px; + } + .login-page .login-card { + width: min(100%, 480px); + padding: 28px 16px 22px; + } + .login-page .login-actions { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; + background: transparent; + box-shadow: none; + overflow: visible; + } + .login-page .login-actions .login-submit { + grid-column: 1 / -1; + order: -1; + border-radius: 11px; + background: linear-gradient(135deg, #002d9f, #001d70 76%); + box-shadow: 0 14px 30px rgba(0, 25, 102, 0.32); + } + .login-page .login-actions .login-submit:hover:not(:disabled) { + transform: translateY(-2px); + box-shadow: 0 18px 36px rgba(0, 23, 94, 0.4); + filter: brightness(1.06); + } + .login-page .login-action-alt, + .login-page .login-action-alt + .login-submit, + .login-page .login-submit + .login-action-alt { + box-shadow: none; + } + .login-page .login-action-alt { + height: 44px; + border: 1px solid rgba(255, 255, 255, 0.14); + border-radius: 10px; + background: rgba(255, 255, 255, 0.045); + } + .login-page .login-row { + flex-wrap: wrap; + gap: 8px 12px; } } + +/* 矮屏:顶部对齐可滚动,避免辅助入口与主按钮重叠 */ +@media (max-height: 800px) { + .login-page .login-form-panel { + align-content: start; + gap: 16px; + overflow-y: auto; + padding-top: 28px; + padding-bottom: 24px; + } + .login-page .login-card { + height: auto; + min-height: 0; + } + .login-page .login-card-heading { margin-bottom: 24px; } + .login-page .login-form { gap: 14px; } +} diff --git a/core/frontend/src/routes/auth-screen.tsx b/core/frontend/src/routes/auth-screen.tsx index 5921046..bd7c43c 100644 --- a/core/frontend/src/routes/auth-screen.tsx +++ b/core/frontend/src/routes/auth-screen.tsx @@ -552,32 +552,30 @@ export function AuthScreen({
{error || "账号或密码不正确,请重新输入。"}
- + +