Skip to content

Commit 8d26b9c

Browse files
committed
feat(config-assistant): 优化配置助手体验,实现自动配置与响应式UI
当用户已存在有效API配置时,助手将自动使用该配置,无需手动确认。 同时,对助手界面进行了全面的响应式修复: - 提高了z-index层级,避免被其他面板遮挡。 - 在移动端设备上,弹窗将全屏显示,输入表单会自动换行,避免内容溢出。 - 优化了消息气泡的文本换行,防止长文本破坏布局。
1 parent a8394d7 commit 8d26b9c

2 files changed

Lines changed: 117 additions & 10 deletions

File tree

components/features/Settings/ApiConfigAssistant.tsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,25 @@ export default function ApiConfigAssistant({ onClose, currentSettings, onApply }
3838
}, [messages]);
3939

4040
// Auto-fill from existing configs
41+
const autoConfigured = useRef(false);
4142
useEffect(() => {
43+
if (autoConfigured.current) return;
4244
const mainConfig = currentSettings.configs?.find((c) => c.id === currentSettings.activeConfigId);
43-
if (mainConfig?.baseUrl && mainConfig?.apiKey && !configReady) {
45+
if (mainConfig?.baseUrl && mainConfig?.apiKey) {
4446
setAssistantBaseUrl(mainConfig.baseUrl.replace(/\/+$/, ''));
4547
setAssistantApiKey(mainConfig.apiKey);
4648
setAssistantModel(mainConfig.model || '');
47-
// Don't auto-close panel — let user verify
49+
setConfigReady(true);
50+
setShowConfigPanel(false);
51+
autoConfigured.current = true;
52+
// Post a system message to inform user
53+
setMessages((prev) => [
54+
...prev,
55+
{
56+
role: 'assistant',
57+
content: `已自动使用当前配置:${mainConfig.名称 || '未命名'}${mainConfig.baseUrl.replace(/\/+$/, '')})\n如需更换助手后端,请点击右上角齿轮图标。`,
58+
},
59+
]);
4860
}
4961
}, [currentSettings]);
5062

@@ -117,8 +129,8 @@ export default function ApiConfigAssistant({ onClose, currentSettings, onApply }
117129
};
118130

119131
return (
120-
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
121-
<div className="relative w-full max-w-2xl max-h-[85vh] flex flex-col bg-gray-900/95 border border-wuxia-gold/30 rounded-xl shadow-2xl">
132+
<div className="fixed inset-0 z-[300] flex items-center justify-center bg-black/60 backdrop-blur-sm">
133+
<div className="relative w-full max-w-2xl max-h-[85vh] sm:max-h-[85vh] h-[100dvh] sm:h-auto flex flex-col bg-gray-900/95 border border-wuxia-gold/30 rounded-none sm:rounded-xl shadow-2xl mx-2 sm:mx-4">
122134
{/* Header */}
123135
<div className="flex items-center justify-between px-4 py-3 border-b border-wuxia-gold/20">
124136
<h2 className="text-lg font-bold font-serif text-wuxia-gold">AI 配置助手</h2>
@@ -258,32 +270,32 @@ function AssistantConfigPanel({
258270
</div>
259271
)}
260272

261-
<div className="flex gap-2">
273+
<div className="flex flex-wrap gap-2">
262274
<input
263275
type="text"
264276
value={baseUrl}
265277
onChange={(e) => onBaseUrlChange(e.target.value)}
266278
placeholder="https://example.com/v1"
267-
className="flex-1 bg-gray-700 border border-gray-600 rounded px-2 py-1.5 text-xs text-white placeholder-gray-500 focus:border-wuxia-gold focus:outline-none"
279+
className="min-w-0 flex-1 sm:flex-1 bg-gray-700 border border-gray-600 rounded px-2 py-1.5 text-xs text-white placeholder-gray-500 focus:border-wuxia-gold focus:outline-none"
268280
/>
269281
<input
270282
type="password"
271283
value={apiKey}
272284
onChange={(e) => onApiKeyChange(e.target.value)}
273285
placeholder="sk-..."
274-
className="flex-1 bg-gray-700 border border-gray-600 rounded px-2 py-1.5 text-xs text-white placeholder-gray-500 focus:border-wuxia-gold focus:outline-none"
286+
className="min-w-0 flex-1 sm:flex-1 bg-gray-700 border border-gray-600 rounded px-2 py-1.5 text-xs text-white placeholder-gray-500 focus:border-wuxia-gold focus:outline-none"
275287
/>
276288
<input
277289
type="text"
278290
value={model}
279291
onChange={(e) => onModelChange(e.target.value)}
280292
placeholder="模型名 (可选)"
281-
className="w-32 bg-gray-700 border border-gray-600 rounded px-2 py-1.5 text-xs text-white placeholder-gray-500 focus:border-wuxia-gold focus:outline-none"
293+
className="w-24 sm:w-32 bg-gray-700 border border-gray-600 rounded px-2 py-1.5 text-xs text-white placeholder-gray-500 focus:border-wuxia-gold focus:outline-none"
282294
/>
283295
<button
284296
onClick={onConfirm}
285297
disabled={!baseUrl.trim() || !apiKey.trim()}
286-
className={`px-3 py-1.5 rounded text-xs font-bold transition-colors ${
298+
className={`w-full sm:w-auto px-3 py-1.5 rounded text-xs font-bold transition-colors ${
287299
isReady
288300
? 'bg-green-600/30 text-green-400 border border-green-500/30'
289301
: 'bg-wuxia-gold/20 text-wuxia-gold disabled:opacity-40'
@@ -303,7 +315,7 @@ function MessageBubble({ message }: { message: AssistantMessage }) {
303315
return (
304316
<div className={`flex ${isUser ? 'justify-end' : 'justify-start'}`}>
305317
<div
306-
className={`max-w-[85%] rounded-lg px-3 py-2 text-sm whitespace-pre-wrap ${
318+
className={`max-w-[85%] rounded-lg px-3 py-2 text-sm whitespace-pre-wrap break-words ${
307319
isError
308320
? 'bg-red-900/40 text-red-300 border border-red-500/30'
309321
: isUser
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# API 配置助手体验优化
2+
3+
## 背景与目标
4+
5+
### 背景
6+
当前 API 配置助手(`ApiConfigAssistant.tsx`)每次打开后,用户必须先配置助手的 LLM 后端(选择已有配置或手动输入 baseUrl/apiKey/model,然后点击"确认"),才能开始使用助手解析 API 配置。对于已有可用接口配置的用户来说,这增加了不必要的操作步骤。
7+
8+
此外,配置助手的 UI 在移动端和桌面端都存在超出页面边界的问题:
9+
- 桌面端:`max-w-2xl` 容器 + 不包裹的输入行在小窗口下会溢出
10+
- 移动端:固定高度弹窗 + 不包裹的表单控件在窄屏下超出可视区域
11+
12+
### 目标
13+
1. **自动配置**:当用户已有可用的 API 配置时,打开助手即自动使用主配置作为助手后端,跳过手动确认步骤
14+
2. **响应式修复**:确保 UI 在移动端和桌面端都不会超出页面边界
15+
16+
## 涉及文件
17+
18+
| 文件 | 变更类型 | 说明 |
19+
|------|----------|------|
20+
| `components/features/Settings/ApiConfigAssistant.tsx` | 修改 | 核心变更:自动配置 + 响应式修复 |
21+
| `components/features/Settings/ApiSettings.tsx` | 无变更 | 仅作为参考,无需修改 |
22+
23+
## 技术方案
24+
25+
### 需求 1:自动配置助手后端
26+
27+
**现状分析**
28+
- `ApiConfigAssistant.tsx` 第 41-49 行已有 `useEffect` 自动填充 `assistantBaseUrl`/`assistantApiKey`/`assistantModel`
29+
- 但填充后仍需要用户手动点击"确认"按钮才能关闭配置面板(`showConfigPanel` 保持 `true`
30+
- `configReady` 仍为 `false`,导致输入框被禁用
31+
32+
**方案**
33+
1. 当检测到 `currentSettings.activeConfigId` 对应的配置存在且 `baseUrl``apiKey` 均非空时:
34+
- 自动设置 `configReady = true`
35+
- 自动关闭配置面板(`showConfigPanel = false`
36+
- 在消息区追加一条系统提示:"已自动使用当前配置:{名称}"
37+
2. 保留手动切换能力:用户仍可点击齿轮图标重新打开配置面板修改助手后端
38+
3. 当没有可用配置时,维持现有行为(要求手动配置)
39+
40+
### 需求 2:响应式 UI 修复
41+
42+
**桌面端问题**
43+
- `AssistantConfigPanel` 中的三个输入框 + 按钮在同一行(flex),窄屏下溢出
44+
- 消息区 `max-w-[85%]` 在大文本下可能过宽
45+
46+
**移动端问题**
47+
- 整个助手弹窗是 `fixed inset-0`,但 SettingsPanel 在移动端已经是 `fixed inset-0 z-[220]`
48+
- 助手弹窗 `z-50` 低于 SettingsPanel 的 `z-[220]`,会被遮挡
49+
- 输入行在窄屏下不换行
50+
51+
**方案**
52+
1. **z-index 修正**:助手弹窗的 `z-50` 改为 `z-[300]`,确保覆盖 SettingsPanel
53+
2. **容器约束**:外层容器添加 `max-w-full mx-2` 防止贴边溢出
54+
3. **配置面板响应式**`AssistantConfigPanel` 中的输入行改为 `flex-wrap`,小屏下自动换行
55+
4. **消息区约束**:保持 `max-w-[85%]` 但添加 `break-words` 防止超长文本溢出
56+
5. **移动端全高**:移动端使用 `h-full max-h-full` 确保不超出屏幕
57+
58+
## 实施步骤
59+
60+
- [x] 步骤 1:修改 `ApiConfigAssistant.tsx` - 自动配置逻辑
61+
- 修改 `useEffect`(第 41-49 行),在自动填充后同步设置 `configReady=true``showConfigPanel=false`
62+
- 添加一条自动配置成功的系统消息
63+
- 处理无可用配置时的降级行为
64+
65+
- [x] 步骤 2:修改 `ApiConfigAssistant.tsx` - z-index 修正
66+
- 弹窗根元素 `className``z-50``z-[300]`
67+
68+
- [x] 步骤 3:修改 `ApiConfigAssistant.tsx` - 容器响应式
69+
- 外层容器添加 `max-w-full w-full mx-2 sm:mx-4`
70+
- 移动端使用 `h-[100dvh]` 而非 `max-h-[85vh]`
71+
- 桌面端保持 `max-h-[85vh]`
72+
73+
- [x] 步骤 4:修改 `ApiConfigAssistant.tsx` - 配置面板输入行响应式
74+
- `AssistantConfigPanel` 中输入行改为 `flex flex-wrap gap-2`
75+
- 输入框在小屏下 `w-full`,中屏以上恢复 `flex-1`
76+
- 确认按钮在小屏下 `w-full`
77+
78+
- [ ] 步骤 5:手动验证
79+
- 桌面端:打开助手 → 验证自动配置生效 → 验证 UI 不溢出
80+
- 移动端:打开助手 → 验证自动配置生效 → 验证 UI 不溢出
81+
- 无配置场景:新建用户首次打开 → 验证手动配置流程正常
82+
83+
## 风险评估
84+
85+
| 风险 | 等级 | 应对 |
86+
|------|------|------|
87+
| 自动使用的配置本身不可用(apiKey 过期等) || 用户发送配置文本后,如果助手调用失败,仍可点击齿轮重新配置后端 |
88+
| z-index 与其他弹窗冲突 || z-[300] 高于 SettingsPanel 的 z-[220],低于测试结果的 z-[260],合理 |
89+
| 响应式修改影响现有美观 || 仅添加 flex-wrap 和条件宽度,不改变配色和布局结构 |
90+
91+
## 预计复杂度:低
92+
93+
- 自动配置逻辑:~15 行变更
94+
- 响应式修复:~10 行 className 变更
95+
- 总变更集中在单一文件 `ApiConfigAssistant.tsx`

0 commit comments

Comments
 (0)