@zhinao-helper/ai-helper-vue3 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,309 @@
1
+ # @zhinao-helper/ai-helper-vue3
2
+
3
+ 基于 Vue 3 的 AI 聊天助手组件库。开箱即用,支持高度自定义的 API 适配、品牌主题和交互体验,适用于任意 Vue 3 项目。
4
+
5
+ ## 特性
6
+
7
+ - 悬浮 FAB 按钮 + 侧滑聊天面板
8
+ - 流式响应(SSE / NDJSON),打字机效果实时渲染
9
+ - 支持自定义 API 端点、请求格式、响应解析
10
+ - 品牌定制:名称、图标、欢迎语、欢迎描述
11
+ - 快捷问题(预设提示词)
12
+ - 历史消息加载
13
+ - 浅色/深色主题自动跟随
14
+ - 支持 Vue Router 路由切换自动关闭
15
+
16
+ ## 安装
17
+
18
+ ```bash
19
+ npm install @zhinao-helper/ai-helper-vue3
20
+ ```
21
+
22
+ ## 快速开始
23
+
24
+ ### 1. 注册插件
25
+
26
+ ```ts
27
+ // src/main.ts
28
+ import { createApp } from 'vue'
29
+ import App from './App.vue'
30
+ import router from './router'
31
+ import { AiHelperPlugin } from '@zhinao-helper/ai-helper-vue3'
32
+ import '@zhinao-helper/ai-helper-vue3/style.css'
33
+
34
+ const app = createApp(App)
35
+
36
+ app.use(AiHelperPlugin, {
37
+ apiBase: '/api/ai-chat', // API 基础地址
38
+ branding: {
39
+ name: 'AI Helper', // 显示名称
40
+ icon: '/logo.svg', // 图标 URL
41
+ welcomeTitle: '你好!', // 欢迎标题
42
+ welcomeDesc: '有什么可以帮你的?' // 欢迎描述
43
+ },
44
+ theme: 'auto', // 'light' | 'dark' | 'auto'
45
+ showQuickQuestions: true, // 是否显示快捷问题
46
+ closeOnRouteChange: true, // 路由切换时是否关闭聊天面板
47
+ endpoints: {
48
+ chat: '/chat', // 聊天接口路径(相对 apiBase)
49
+ history: '/history', // 历史接口路径
50
+ prompts: '/prompts' // 提示词接口路径
51
+ }
52
+ })
53
+
54
+ app.use(router)
55
+ app.mount('#app')
56
+ ```
57
+
58
+ ### 2. 在页面中使用
59
+
60
+ ```vue
61
+ <!-- src/App.vue -->
62
+ <template>
63
+ <router-view />
64
+ <AiHelper />
65
+ </template>
66
+ ```
67
+
68
+ ## 高级配置
69
+
70
+ ### 自定义 API 格式
71
+
72
+ 不同项目的后端 API 可能返回不同格式的数据结构。通过配置回调函数,你可以将任意 API 格式适配到组件内部:
73
+
74
+ #### 聊天接口(流式)
75
+
76
+ ```ts
77
+ app.use(AiHelperPlugin, {
78
+ // 自定义请求体格式
79
+ buildChatBody({ message }) {
80
+ // 默认: JSON.stringify({ message })
81
+ return JSON.stringify({ prompt: message, stream: true })
82
+ },
83
+
84
+ // 自定义流式响应解析(每个数据块调用一次)
85
+ parseChatChunk(raw) {
86
+ const data = JSON.parse(raw)
87
+ // 假设后端返回: { choices: [{ delta: { content: "..." } }] }
88
+ if (data.choices?.[0]?.delta?.content) {
89
+ return { content: data.choices[0].delta.content }
90
+ }
91
+ // 流结束标志
92
+ if (data.choices?.[0]?.finish_reason === 'stop') {
93
+ return { content: '', done: true }
94
+ }
95
+ return { content: '' }
96
+ }
97
+ })
98
+ ```
99
+
100
+ `parseChatChunk` 接收到的 `raw` 是每个数据行的纯文本内容:
101
+ - 标准 SSE 格式:`data: {"content": "hello"}` → `raw` 为 `{"content": "hello"}`
102
+ - NDJSON 格式:`{"content": "hello"}` → `raw` 为 `{"content": "hello"}`
103
+
104
+ 返回 `{ content: string, done?: boolean }`:
105
+ - `content` 会被追加到助手消息中显示
106
+ - `done: true` 表示流结束,loading 状态终止
107
+
108
+ #### 历史接口
109
+
110
+ ```ts
111
+ app.use(AiHelperPlugin, {
112
+ parseHistoryResponse(raw) {
113
+ const r = raw as any
114
+ return {
115
+ messages: r.data?.map(m => ({
116
+ role: m.role,
117
+ content: m.text,
118
+ timestamp: m.created_at
119
+ })) ?? [],
120
+ total: r.total ?? r.data?.length ?? 0
121
+ }
122
+ }
123
+ })
124
+ ```
125
+
126
+ 内部期望的历史响应格式:
127
+ ```ts
128
+ {
129
+ messages: { role: 'user' | 'assistant', content: string, timestamp: string }[],
130
+ total: number
131
+ }
132
+ ```
133
+
134
+ #### 提示词接口(快捷问题)
135
+
136
+ ```ts
137
+ app.use(AiHelperPlugin, {
138
+ parsePromptResponse(raw) {
139
+ const r = raw as any
140
+ return {
141
+ items: r.prompts?.map(p => ({
142
+ id: p.id,
143
+ name: p.title,
144
+ content: p.prompt
145
+ })) ?? [],
146
+ total: r.total ?? 0
147
+ }
148
+ }
149
+ })
150
+ ```
151
+
152
+ 内部期望的提示词响应格式:
153
+ ```ts
154
+ {
155
+ items: { id: number, name: string, content: string }[],
156
+ total: number
157
+ }
158
+ ```
159
+
160
+ ### 自定义请求头
161
+
162
+ ```ts
163
+ app.use(AiHelperPlugin, {
164
+ getHeaders: () => ({
165
+ 'Authorization': `Bearer ${localStorage.getItem('token')}`,
166
+ 'X-Project-Id': 'my-project'
167
+ })
168
+ })
169
+ ```
170
+
171
+ ### 完整配置示例
172
+
173
+ ```ts
174
+ import { AiHelperPlugin } from '@zhinao-helper/ai-helper-vue3'
175
+ import '@zhinao-helper/ai-helper-vue3/style.css'
176
+
177
+ app.use(AiHelperPlugin, {
178
+ apiBase: 'https://api.example.com',
179
+ branding: {
180
+ name: 'AI 助手',
181
+ icon: '/logo.png',
182
+ welcomeTitle: '你好!',
183
+ welcomeDesc: '有什么可以帮你的?'
184
+ },
185
+ theme: 'auto',
186
+ showQuickQuestions: true,
187
+ closeOnRouteChange: true,
188
+ endpoints: {
189
+ chat: '/v1/chat/stream',
190
+ history: '/v1/history',
191
+ prompts: '/v1/prompts'
192
+ },
193
+ getHeaders: () => ({
194
+ Authorization: `Bearer ${getToken()}`
195
+ }),
196
+ buildChatBody({ message }) {
197
+ return JSON.stringify({ prompt: message, stream: true })
198
+ },
199
+ parseChatChunk(raw) {
200
+ const data = JSON.parse(raw)
201
+ if (data.choices?.[0]?.delta?.content) {
202
+ return { content: data.choices[0].delta.content }
203
+ }
204
+ if (data.choices?.[0]?.finish_reason === 'stop') {
205
+ return { content: '', done: true }
206
+ }
207
+ return { content: '' }
208
+ },
209
+ parseHistoryResponse(raw) {
210
+ const r = raw as any
211
+ return {
212
+ messages: r.data?.map(m => ({
213
+ role: m.role,
214
+ content: m.text,
215
+ timestamp: m.created_at
216
+ })) ?? [],
217
+ total: r.total ?? 0
218
+ }
219
+ },
220
+ parsePromptResponse(raw) {
221
+ const r = raw as any
222
+ return {
223
+ items: r.prompts?.map(p => ({
224
+ id: p.id,
225
+ name: p.title,
226
+ content: p.prompt
227
+ })) ?? [],
228
+ total: r.total ?? 0
229
+ }
230
+ }
231
+ })
232
+ ```
233
+
234
+ ## API 说明
235
+
236
+ ### 请求格式
237
+
238
+ 所有请求默认使用 `POST` 方法,`Content-Type: application/json`,请求体为 `{ message: string }`。你可以通过 `buildChatBody` 覆盖。
239
+
240
+ ### 流式响应格式
241
+
242
+ 组件支持两种流式数据格式:
243
+
244
+ 1. **标准 SSE**(每行以 `data:` 开头)
245
+ 2. **NDJSON**(每行一个 JSON 对象)
246
+
247
+ 流式读取时,每收到一行数据就调用 `parseChatChunk`。组件会自动跳过空行和 SSE 元数据行(以 `:`、`id:`、`event:` 开头)。
248
+
249
+ ### 超时保护
250
+
251
+ 如果 60 秒内没有收到新的流数据块,组件会自动结束 loading 状态。
252
+
253
+ ## 自定义主题
254
+
255
+ 组件通过 CSS 变量控制样式,你可以在全局样式中覆盖:
256
+
257
+ ```css
258
+ :root {
259
+ --zhinao-helper-bg: #2563eb; /* FAB 背景色 */
260
+ --zhinao-helper-color-primary: #3b82f6; /* 主色调 */
261
+ --zhinao-helper-text-primary: #1e293b; /* 主要文字 */
262
+ --zhinao-helper-border: #e2e8f0; /* 边框色 */
263
+ --zhinao-helper-bg-card: #ffffff; /* 卡片背景 */
264
+ --zhinao-helper-bg-active: #f1f5f9; /* 面板背景 */
265
+ --zhinao-helper-bg-chat: #f8fafc; /* 助手消息气泡 */
266
+ }
267
+ ```
268
+
269
+ 所有可用 CSS 变量列表:
270
+
271
+ | 变量 | 默认值 | 说明 |
272
+ |------|--------|------|
273
+ | `--zhinao-helper-bg` | `#1a3a5c` | FAB 背景色 / 主背景 |
274
+ | `--zhinao-helper-bg-active` | `#b8d4f0` | 面板背景色 |
275
+ | `--zhinao-helper-bg-card` | `#ffffff` | 卡片/消息气泡背景 |
276
+ | `--zhinao-helper-bg-chat` | `rgb(184,212,240,0.5)` | 助手消息气泡 |
277
+ | `--zhinao-helper-text-primary` | `#1a3a5c` | 主要文字 |
278
+ | `--zhinao-helper-text-secondary` | `#4a6a8c` | 次要文字 |
279
+ | `--zhinao-helper-border` | `#b8d4f0` | 边框色 |
280
+ | `--zhinao-helper-color-primary` | `#409eff` | 主色调 |
281
+ | `--zhinao-helper-scrollbar-thumb` | `#c8dce8` | 滚动条滑块 |
282
+ | `--zhinao-helper-scrollbar-track` | `rgba(200,220,232,0.3)` | 滚动条轨道 |
283
+ | `--zhinao-helper-text-placeholder` | `#8aaacc` | 输入框占位符 |
284
+
285
+ ## 类型导出
286
+
287
+ 所有类型均从 `@zhinao-helper/ai-helper-vue3` 导出:
288
+
289
+ ```ts
290
+ import type {
291
+ AiHelperOptions, // 初始化配置选项
292
+ AiHelperConfig, // 完整解析后的配置
293
+ AiHelperBranding, // 品牌配置
294
+ AiHelperEndpoints, // API 端点
295
+ ChatParseResult, // 流式解析返回值
296
+ ChatRequestParams, // 聊天请求参数
297
+ Message, // 聊天消息
298
+ AiHelperState, // 内部状态
299
+ PromptRow, // 提示词
300
+ PromptListResponse, // 提示词响应
301
+ HistoryMessage, // 历史消息
302
+ HistoryResponse, // 历史响应
303
+ HistoryParams // 历史查询参数
304
+ } from '@zhinao-helper/ai-helper-vue3'
305
+ ```
306
+
307
+ ## License
308
+
309
+ MIT
@@ -0,0 +1,2 @@
1
+ .zhinao-btn{cursor:pointer;color:var(--zhinao-helper-text-primary);background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;gap:4px;padding:6px 12px;font-size:13px;transition:all .2s;display:inline-flex}.zhinao-btn:hover{background:#8080801a}.zhinao-btn:disabled{opacity:.5;cursor:not-allowed}.zhinao-btn--primary{background:var(--zhinao-helper-color-primary);color:#fff}.zhinao-btn--primary:hover:not(:disabled){opacity:.85}.zhinao-btn--icon{border-radius:50%;width:28px;height:28px;padding:4px}.zhinao-btn--icon:hover:not(:disabled){background:#80808026}.zhinao-btn--text{color:var(--zhinao-helper-color-primary);font-size:12px}.zhinao-icon{fill:currentColor;width:16px;height:16px}.zhinao-loading-dots{align-items:center;gap:4px;display:inline-flex}.zhinao-loading-dots span{background:var(--zhinao-helper-color-primary);border-radius:50%;width:6px;height:6px;animation:1.4s ease-in-out infinite both zhinao-dot-bounce}.zhinao-loading-dots span:first-child{animation-delay:-.32s}.zhinao-loading-dots span:nth-child(2){animation-delay:-.16s}.zhinao-loading-dots--small span{width:4px;height:4px}@keyframes zhinao-dot-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}:root{--zhinao-helper-bg:var(--app-ai-helper-bg,#1a3a5c);--zhinao-helper-bg-active:var(--app-bg-active,#b8d4f0);--zhinao-helper-bg-card:var(--app-bg-card,#fff);--zhinao-helper-bg-chat:var(--app-bg-chat,#b8d4f080);--zhinao-helper-text-primary:var(--app-text-primary,#1a3a5c);--zhinao-helper-text-secondary:var(--app-text-secondary,#4a6a8c);--zhinao-helper-border:var(--app-border-color,#b8d4f0);--zhinao-helper-color-primary:var(--app-color-primary,#409eff);--zhinao-helper-scrollbar-thumb:var(--app-scrollbar-thumb,#c8dce8);--zhinao-helper-scrollbar-track:var(--app-scrollbar-track,#c8dce84d);--zhinao-helper-scrollbar-thumb-hover:var(--app-scrollbar-thumb-hover,#409eff);--zhinao-helper-text-placeholder:var(--app-text-placeholder,#8aaacc);--zhinao-helper-bg-primary:var(--app-bg-primary,#e8f4ff)}html.dark{--zhinao-helper-bg:var(--app-ai-helper-bg,#000);--zhinao-helper-bg-active:var(--app-bg-active,#1a1a2e);--zhinao-helper-bg-card:var(--app-bg-card,#16213e);--zhinao-helper-bg-chat:var(--app-bg-chat,#00000080);--zhinao-helper-text-primary:var(--app-text-primary,#e8f4ff);--zhinao-helper-text-secondary:var(--app-text-secondary,#a0c4e8);--zhinao-helper-border:var(--app-border-color,#2a4a6c);--zhinao-helper-color-primary:var(--app-color-primary,#409eff);--zhinao-helper-scrollbar-thumb:#2a4a6c;--zhinao-helper-scrollbar-track:#2a4a6c4d}.zhinao-loading[data-v-3ac9b9a6]{color:var(--zhinao-helper-text-secondary);align-items:center;gap:8px;font-size:14px;display:flex}.zhinao-loading--small[data-v-3ac9b9a6]{font-size:12px}.zhinao-loading-dots[data-v-3ac9b9a6]{gap:4px;display:flex}.zhinao-loading-dots span[data-v-3ac9b9a6]{background:var(--zhinao-helper-color-primary);border-radius:50%;width:6px;height:6px;animation:1.4s ease-in-out infinite both zhinao-bounce-3ac9b9a6}.zhinao-loading-dots span[data-v-3ac9b9a6]:first-child{animation-delay:-.32s}.zhinao-loading-dots span[data-v-3ac9b9a6]:nth-child(2){animation-delay:-.16s}.zhinao-loading--small .zhinao-loading-dots span[data-v-3ac9b9a6]{width:4px;height:4px}@keyframes zhinao-bounce-3ac9b9a6{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.zhinao-quick-questions[data-v-6c57d374]{grid-template-columns:repeat(2,1fr);gap:8px;width:100%;max-width:400px;display:grid}.zhinao-quick-question[data-v-6c57d374]{border:1px solid var(--zhinao-helper-border);background:var(--zhinao-helper-bg-card);color:var(--zhinao-helper-text-primary);text-align:left;cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:8px;padding:10px 16px;font-size:13px;transition:all .2s;overflow:hidden}.zhinao-quick-question[data-v-6c57d374]:hover{border-color:var(--zhinao-helper-color-primary);background:var(--zhinao-helper-bg-active)}.zhinao-chat-messages[data-v-c33e4f6c]{background:var(--zhinao-helper-bg-card);scrollbar-width:thin;scrollbar-color:var(--zhinao-helper-scrollbar-thumb) var(--zhinao-helper-scrollbar-track);flex:1;padding:16px;overflow-y:auto}.zhinao-chat-messages[data-v-c33e4f6c]::-webkit-scrollbar{width:6px}.zhinao-chat-messages[data-v-c33e4f6c]::-webkit-scrollbar-track{background:var(--zhinao-helper-scrollbar-track);border-radius:3px}.zhinao-chat-messages[data-v-c33e4f6c]::-webkit-scrollbar-thumb{background:var(--zhinao-helper-scrollbar-thumb);border-radius:3px}.zhinao-chat-messages[data-v-c33e4f6c]::-webkit-scrollbar-thumb:hover{background:var(--zhinao-helper-scrollbar-thumb-hover)}.zhinao-chat-messages__welcome[data-v-c33e4f6c]{flex-direction:column;justify-content:center;align-items:center;gap:24px;min-height:100%;display:flex}.zhinao-chat-messages__welcome-inner[data-v-c33e4f6c]{text-align:center}.zhinao-chat-messages__avatar-wrap[data-v-c33e4f6c]{background:var(--zhinao-helper-bg);border-radius:50%;justify-content:center;align-items:center;width:64px;height:64px;margin:0 auto 16px;display:flex;box-shadow:0 4px 12px #00000026}.zhinao-chat-messages__avatar[data-v-c33e4f6c]{width:36px;height:36px}.zhinao-chat-messages__welcome-title[data-v-c33e4f6c]{color:var(--zhinao-helper-text-primary);margin-bottom:8px;font-size:18px;font-weight:500}.zhinao-chat-messages__welcome-desc[data-v-c33e4f6c]{color:var(--zhinao-helper-text-secondary);font-size:14px}.zhinao-chat-messages__list[data-v-c33e4f6c]{flex-direction:column;gap:16px;display:flex}.zhinao-chat-messages__load-more[data-v-c33e4f6c]{text-align:center}.zhinao-chat-messages__row[data-v-c33e4f6c]{display:flex}.zhinao-chat-messages__row--user[data-v-c33e4f6c]{justify-content:flex-end}.zhinao-chat-messages__row--assistant[data-v-c33e4f6c]{justify-content:flex-start}.zhinao-chat-messages__bubble[data-v-c33e4f6c]{word-break:break-word;border-radius:8px;max-width:90%;padding:8px 16px}.zhinao-chat-messages__bubble--user[data-v-c33e4f6c]{background:var(--zhinao-helper-color-primary);color:#fff;max-width:80%}.zhinao-chat-messages__bubble--assistant[data-v-c33e4f6c]{background:var(--zhinao-helper-bg-chat);color:var(--zhinao-helper-text-primary)}.zhinao-chat-markdown[data-v-c33e4f6c]{line-height:1.6}.zhinao-chat-markdown[data-v-c33e4f6c] p{margin:.5em 0}.zhinao-chat-markdown[data-v-c33e4f6c] p:first-child{margin-top:0}.zhinao-chat-markdown[data-v-c33e4f6c] p:last-child{margin-bottom:0}.zhinao-chat-markdown[data-v-c33e4f6c] code{background:var(--zhinao-helper-bg-active);border-radius:3px;padding:2px 6px;font-size:.9em}.zhinao-chat-markdown[data-v-c33e4f6c] pre{background:var(--zhinao-helper-bg-active);border-radius:6px;padding:12px;overflow-x:auto}.zhinao-chat-markdown[data-v-c33e4f6c] pre code{background:0 0;padding:0}.zhinao-chat-markdown[data-v-c33e4f6c] ul,.zhinao-chat-markdown[data-v-c33e4f6c] ol{margin:.5em 0;padding-left:20px}.zhinao-chat-markdown[data-v-c33e4f6c] blockquote{border-left:3px solid var(--zhinao-helper-border);color:var(--zhinao-helper-text-secondary);margin:.5em 0;padding-left:12px}.zhinao-chat-markdown[data-v-c33e4f6c] table{border-collapse:collapse;width:100%;margin:.5em 0}.zhinao-chat-markdown[data-v-c33e4f6c] th,.zhinao-chat-markdown[data-v-c33e4f6c] td{border:1px solid var(--zhinao-helper-border);text-align:left;padding:6px 12px}.zhinao-chat-markdown[data-v-c33e4f6c] th{background:var(--zhinao-helper-bg-active)}.zhinao-chat-markdown[data-v-c33e4f6c] a{color:var(--zhinao-helper-color-primary);text-decoration:none}.zhinao-chat-markdown[data-v-c33e4f6c] a:hover{text-decoration:underline}.zhinao-chat-markdown[data-v-c33e4f6c] img{max-width:100%;height:auto}@keyframes zhinao-peeking-tilt{0%,to{transform:rotate(-12deg)}30%{transform:rotate(-15deg)}60%{transform:rotate(-10deg)}}@keyframes zhinao-excited-bounce{0%{transform:rotate(-12deg)scale(1)}40%{transform:rotate(0)scale(1.15)}to{transform:rotate(0)scale(1)}}.zhinao-chat-fade-enter-active,.zhinao-chat-fade-leave-active{transition:all .3s}.zhinao-chat-fade-enter-from,.zhinao-chat-fade-leave-to{opacity:0;transform:translate(20px)}.zhinao-ai-helper-fab[data-v-fe5a8cb6]{z-index:50;cursor:pointer;align-items:center;transition:all .4s;display:flex;position:fixed;bottom:20px;right:-20px}.zhinao-ai-helper-fab[data-v-fe5a8cb6]:hover{border-radius:28px 0 0 28px;padding:4px 12px;right:0}.zhinao-ai-helper-fab--hidden[data-v-fe5a8cb6]{opacity:0;pointer-events:none;transform:translate(48px)}.zhinao-ai-helper-fab__capsule[data-v-fe5a8cb6]{z-index:-1;background:var(--zhinao-helper-bg);opacity:0;border-radius:28px 0 0 28px;transition:opacity .4s;position:absolute;inset:0;box-shadow:-4px 4px 12px #00000040}.zhinao-ai-helper-fab:hover .zhinao-ai-helper-fab__capsule[data-v-fe5a8cb6]{opacity:1}.zhinao-ai-helper-fab__icon-wrap[data-v-fe5a8cb6]{background:var(--zhinao-helper-bg);border-radius:50%;justify-content:center;align-items:center;width:52px;height:52px;transition:all .4s;animation:2.5s ease-in-out infinite zhinao-peeking-tilt;display:flex;box-shadow:-2px 2px 8px #0003}.zhinao-ai-helper-fab:hover .zhinao-ai-helper-fab__icon-wrap[data-v-fe5a8cb6]{box-shadow:none;background:0 0;animation:.5s ease-out zhinao-excited-bounce}.zhinao-ai-helper-fab__icon[data-v-fe5a8cb6]{width:36px;height:36px;transition:filter .4s}.zhinao-ai-helper-fab:hover .zhinao-ai-helper-fab__icon[data-v-fe5a8cb6]{filter:brightness(0)invert()}.zhinao-ai-helper-fab__label[data-v-fe5a8cb6]{color:#fff;white-space:nowrap;opacity:0;max-width:0;margin-left:0;font-size:14px;font-weight:500;transition:all .4s;overflow:hidden}.zhinao-ai-helper-fab:hover .zhinao-ai-helper-fab__label[data-v-fe5a8cb6]{opacity:1;max-width:100px;margin-left:4px}.zhinao-ai-helper-panel[data-v-fe5a8cb6]{z-index:100;background:var(--zhinao-helper-bg-active);border-radius:8px;flex-direction:column;width:560px;height:calc(100vh - 80px);display:flex;position:fixed;top:60px;right:20px;overflow:hidden;box-shadow:0 8px 32px #0003}.zhinao-ai-helper-panel__header[data-v-fe5a8cb6]{border-bottom:1px solid var(--zhinao-helper-border);color:var(--zhinao-helper-text-primary);justify-content:space-between;align-items:center;padding:12px 16px;display:flex}.zhinao-ai-helper-panel__title[data-v-fe5a8cb6]{font-weight:500}.zhinao-ai-helper-panel__actions[data-v-fe5a8cb6]{align-items:center;gap:8px;display:flex}.zhinao-ai-helper-panel__footer[data-v-fe5a8cb6]{border-top:1px solid var(--zhinao-helper-border);align-items:center;gap:8px;padding:16px;display:flex}.zhinao-input[data-v-fe5a8cb6]{border:1px solid var(--zhinao-helper-border);background:var(--zhinao-helper-bg-card);color:var(--zhinao-helper-text-primary);border-radius:6px;outline:none;flex:1;padding:8px 12px;font-size:14px;transition:border-color .2s}.zhinao-input[data-v-fe5a8cb6]:focus{border-color:var(--zhinao-helper-color-primary)}.zhinao-input[data-v-fe5a8cb6]:disabled{opacity:.6;cursor:not-allowed}
2
+ /*$vite$:1*/