collabdocchat 1.2.13 → 2.0.1
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 +219 -218
- package/index.html +2 -0
- package/install-and-start.bat +5 -0
- package/install-and-start.sh +5 -0
- package/package.json +9 -2
- package/scripts/generate-docs.js +448 -0
- package/scripts/pre-publish-check.js +213 -0
- package/scripts/start-app.js +15 -15
- package/server/index.js +38 -6
- package/server/middleware/cache.js +115 -0
- package/server/middleware/errorHandler.js +209 -0
- package/server/models/Document.js +66 -59
- package/server/models/File.js +49 -43
- package/server/models/Group.js +6 -0
- package/server/models/KnowledgeBase.js +254 -0
- package/server/models/Message.js +43 -0
- package/server/models/Task.js +87 -55
- package/server/models/User.js +67 -60
- package/server/models/Workflow.js +249 -0
- package/server/routes/ai.js +327 -0
- package/server/routes/audit.js +245 -210
- package/server/routes/backup.js +108 -0
- package/server/routes/chunked-upload.js +343 -0
- package/server/routes/export.js +440 -0
- package/server/routes/files.js +294 -218
- package/server/routes/groups.js +182 -0
- package/server/routes/knowledge.js +509 -0
- package/server/routes/tasks.js +257 -110
- package/server/routes/workflows.js +380 -0
- package/server/utils/backup.js +439 -0
- package/server/utils/cache.js +223 -0
- package/server/utils/workflow-engine.js +479 -0
- package/server/websocket/enhanced.js +509 -0
- package/server/websocket/index.js +233 -1
- package/src/components/knowledge-modal.js +485 -0
- package/src/components/optimized-poll-detail.js +724 -0
- package/src/main.js +5 -0
- package/src/pages/admin-dashboard.js +2248 -44
- package/src/pages/optimized-backup-view.js +616 -0
- package/src/pages/optimized-knowledge-view.js +803 -0
- package/src/pages/optimized-task-detail.js +843 -0
- package/src/pages/optimized-workflow-view.js +806 -0
- package/src/pages/simplified-workflows.js +651 -0
- package/src/pages/user-dashboard.js +677 -58
- package/src/services/api.js +64 -0
- package/src/services/auth.js +1 -1
- package/src/services/websocket.js +124 -16
- package/src/styles/collaboration-modern.js +708 -0
- package/src/styles/enhancements.css +392 -0
- package/src/styles/main.css +620 -1420
- package/src/styles/responsive.css +1000 -0
- package/src/styles/sidebar-fix.css +60 -0
- package/src/utils/ai-assistant.js +1398 -0
- package/src/utils/chat-enhancements.js +509 -0
- package/src/utils/collaboration-enhancer.js +1151 -0
- package/src/utils/feature-integrator.js +1724 -0
- package/src/utils/onboarding-guide.js +734 -0
- package/src/utils/performance.js +394 -0
- package/src/utils/permission-manager.js +890 -0
- package/src/utils/responsive-handler.js +491 -0
- package/src/utils/theme-manager.js +811 -0
- package/src/utils/ui-enhancements-loader.js +329 -0
- package/USAGE.md +0 -298
|
@@ -0,0 +1,1398 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI 助手系统
|
|
3
|
+
* 提供智能回复、内容摘要、翻译等功能
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class AIAssistant {
|
|
7
|
+
constructor(apiService) {
|
|
8
|
+
this.apiService = apiService;
|
|
9
|
+
this.isEnabled = true;
|
|
10
|
+
this.suggestions = [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 生成AI响应
|
|
15
|
+
*/
|
|
16
|
+
async generateAIResponse(message) {
|
|
17
|
+
const lowerMessage = message.toLowerCase();
|
|
18
|
+
|
|
19
|
+
// 问候语
|
|
20
|
+
if (lowerMessage.includes('你好') || lowerMessage.includes('hi') || lowerMessage.includes('hello')) {
|
|
21
|
+
return '你好!我是AI助手,很高兴为你服务。有什么可以帮助你的吗?';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 感谢
|
|
25
|
+
if (lowerMessage.includes('谢谢') || lowerMessage.includes('thanks') || lowerMessage.includes('thank you')) {
|
|
26
|
+
return '不客气!很高兴能帮到你。还有其他问题吗?';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 询问功能
|
|
30
|
+
if (lowerMessage.includes('功能') || lowerMessage.includes('能做什么') || lowerMessage.includes('帮助')) {
|
|
31
|
+
return '我可以帮你:\n1. 智能回复建议 - 为你的消息提供回复建议\n2. 内容摘要 - 快速总结长文本\n3. 语法检查 - 检查文本中的语法问题\n4. 情感分析 - 分析文本的情感倾向\n5. 实时对话 - 随时与我交流\n\n你想了解哪个功能?';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 询问时间
|
|
35
|
+
if (lowerMessage.includes('时间') || lowerMessage.includes('几点')) {
|
|
36
|
+
const now = new Date();
|
|
37
|
+
return `现在是 ${now.toLocaleString('zh-CN')}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 询问日期
|
|
41
|
+
if (lowerMessage.includes('日期') || lowerMessage.includes('今天')) {
|
|
42
|
+
const now = new Date();
|
|
43
|
+
return `今天是 ${now.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' })}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 询问天气(模拟)
|
|
47
|
+
if (lowerMessage.includes('天气')) {
|
|
48
|
+
return '抱歉,我目前还不能查询实时天气信息。你可以使用天气应用或网站查询。';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 询问文档相关
|
|
52
|
+
if (lowerMessage.includes('文档') || lowerMessage.includes('document')) {
|
|
53
|
+
return '关于文档功能:\n- 你可以在"文档管理"中创建和编辑文档\n- 支持实时协作编辑\n- 可以设置文档权限(只读/可编辑)\n- 支持版本历史记录\n\n需要我详细介绍某个功能吗?';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 询问任务相关
|
|
57
|
+
if (lowerMessage.includes('任务') || lowerMessage.includes('task')) {
|
|
58
|
+
return '关于任务功能:\n- 管理员可以创建任务并分配给成员\n- 支持设置截止日期\n- 可以查看任务完成情况\n- 支持投票任务\n\n你想了解更多吗?';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 询问群组相关
|
|
62
|
+
if (lowerMessage.includes('群组') || lowerMessage.includes('group')) {
|
|
63
|
+
return '关于群组功能:\n- 管理员可以创建和管理群组\n- 支持添加/移除成员\n- 可以设置全体禁言或个人禁言\n- 支持清除聊天记录\n\n有什么具体问题吗?';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 询问协作工具
|
|
67
|
+
if (lowerMessage.includes('协作') || lowerMessage.includes('工具') || lowerMessage.includes('白板')) {
|
|
68
|
+
return '协作工具包括:\n1. 白板 - 实时协作绘图\n2. 投票 - 创建投票任务(管理员)\n3. 代码编辑 - 协作编写代码\n4. 思维导图 - 创建思维导图\n\n你想使用哪个工具?';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 问题类型
|
|
72
|
+
if (lowerMessage.includes('怎么') || lowerMessage.includes('如何') || lowerMessage.includes('怎样')) {
|
|
73
|
+
return '我会尽力帮你解答。请告诉我具体的问题,比如:\n- 怎么创建文档?\n- 如何分配任务?\n- 怎样使用白板?\n\n请详细描述你的问题。';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 确认/同意
|
|
77
|
+
if (lowerMessage.includes('好的') || lowerMessage.includes('ok') || lowerMessage.includes('可以') || lowerMessage.includes('明白')) {
|
|
78
|
+
return '很好!如果还有其他问题,随时告诉我。';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 否定/拒绝
|
|
82
|
+
if (lowerMessage.includes('不') && (lowerMessage.includes('需要') || lowerMessage.includes('用'))) {
|
|
83
|
+
return '好的,如果以后需要帮助,随时找我!';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 再见
|
|
87
|
+
if (lowerMessage.includes('再见') || lowerMessage.includes('拜拜') || lowerMessage.includes('bye')) {
|
|
88
|
+
return '再见!祝你使用愉快!👋';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 默认回复
|
|
92
|
+
const defaultReplies = [
|
|
93
|
+
'我理解你的意思。能告诉我更多细节吗?',
|
|
94
|
+
'这是个有趣的问题。你能具体说说吗?',
|
|
95
|
+
'我在学习中。你可以换个方式问我,或者使用其他AI功能。',
|
|
96
|
+
'我会记住这个问题。你还想了解什么?',
|
|
97
|
+
'有趣!你可以试试我的其他功能,比如内容摘要或语法检查。'
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
return defaultReplies[Math.floor(Math.random() * defaultReplies.length)];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 智能回复建议
|
|
105
|
+
*/
|
|
106
|
+
async getSmartReplies(message, context = []) {
|
|
107
|
+
// 模拟AI回复建议(实际应用中应调用AI API)
|
|
108
|
+
const replies = this.generateSmartReplies(message);
|
|
109
|
+
return replies;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 生成智能回复
|
|
114
|
+
*/
|
|
115
|
+
generateSmartReplies(message) {
|
|
116
|
+
const lowerMessage = message.toLowerCase();
|
|
117
|
+
|
|
118
|
+
// 问候语
|
|
119
|
+
if (lowerMessage.includes('你好') || lowerMessage.includes('hi') || lowerMessage.includes('hello')) {
|
|
120
|
+
return [
|
|
121
|
+
'你好!有什么可以帮助你的吗?',
|
|
122
|
+
'嗨!很高兴见到你!',
|
|
123
|
+
'你好!欢迎!'
|
|
124
|
+
];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 感谢
|
|
128
|
+
if (lowerMessage.includes('谢谢') || lowerMessage.includes('thanks')) {
|
|
129
|
+
return [
|
|
130
|
+
'不客气!',
|
|
131
|
+
'很高兴能帮到你!',
|
|
132
|
+
'随时为你服务!'
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 询问
|
|
137
|
+
if (lowerMessage.includes('怎么') || lowerMessage.includes('如何') || lowerMessage.includes('?') || lowerMessage.includes('?')) {
|
|
138
|
+
return [
|
|
139
|
+
'让我来帮你解答...',
|
|
140
|
+
'这是个好问题,我来看看...',
|
|
141
|
+
'我需要了解更多信息才能回答'
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 确认
|
|
146
|
+
if (lowerMessage.includes('好的') || lowerMessage.includes('ok') || lowerMessage.includes('可以')) {
|
|
147
|
+
return [
|
|
148
|
+
'明白了!',
|
|
149
|
+
'收到!',
|
|
150
|
+
'好的,我知道了'
|
|
151
|
+
];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 默认回复
|
|
155
|
+
return [
|
|
156
|
+
'我明白了',
|
|
157
|
+
'好的',
|
|
158
|
+
'收到'
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 内容摘要
|
|
164
|
+
*/
|
|
165
|
+
async summarizeContent(content) {
|
|
166
|
+
// 简单的摘要算法(实际应用中应使用AI模型)
|
|
167
|
+
const sentences = content.split(/[。!?.!?]/);
|
|
168
|
+
const summary = sentences.slice(0, 3).join('。') + '。';
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
summary: summary,
|
|
172
|
+
keyPoints: this.extractKeyPoints(content),
|
|
173
|
+
wordCount: content.length
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 提取关键点
|
|
179
|
+
*/
|
|
180
|
+
extractKeyPoints(content) {
|
|
181
|
+
// 简单的关键词提取
|
|
182
|
+
const keywords = [];
|
|
183
|
+
const commonWords = ['的', '了', '是', '在', '有', '和', '就', '不', '人', '都', '一', '我', '他', '她', '它'];
|
|
184
|
+
|
|
185
|
+
const words = content.match(/[\u4e00-\u9fa5]+/g) || [];
|
|
186
|
+
const wordFreq = {};
|
|
187
|
+
|
|
188
|
+
words.forEach(word => {
|
|
189
|
+
if (word.length > 1 && !commonWords.includes(word)) {
|
|
190
|
+
wordFreq[word] = (wordFreq[word] || 0) + 1;
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const sorted = Object.entries(wordFreq)
|
|
195
|
+
.sort((a, b) => b[1] - a[1])
|
|
196
|
+
.slice(0, 5);
|
|
197
|
+
|
|
198
|
+
return sorted.map(([word]) => word);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 文本翻译(模拟)
|
|
203
|
+
*/
|
|
204
|
+
async translate(text, targetLang = 'en') {
|
|
205
|
+
// 实际应用中应调用翻译API
|
|
206
|
+
return {
|
|
207
|
+
original: text,
|
|
208
|
+
translated: `[${targetLang}] ${text}`,
|
|
209
|
+
targetLang: targetLang
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 语法检查
|
|
215
|
+
*/
|
|
216
|
+
async checkGrammar(text) {
|
|
217
|
+
// 简单的语法检查
|
|
218
|
+
const issues = [];
|
|
219
|
+
|
|
220
|
+
// 检查标点符号
|
|
221
|
+
if (!text.match(/[。!?.!?]$/)) {
|
|
222
|
+
issues.push({
|
|
223
|
+
type: 'punctuation',
|
|
224
|
+
message: '建议在句末添加标点符号',
|
|
225
|
+
position: text.length
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 检查重复词
|
|
230
|
+
const words = text.split(/\s+/);
|
|
231
|
+
for (let i = 0; i < words.length - 1; i++) {
|
|
232
|
+
if (words[i] === words[i + 1]) {
|
|
233
|
+
issues.push({
|
|
234
|
+
type: 'repetition',
|
|
235
|
+
message: `重复的词: "${words[i]}"`,
|
|
236
|
+
position: i
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
text: text,
|
|
243
|
+
issues: issues,
|
|
244
|
+
score: Math.max(0, 100 - issues.length * 10)
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 内容建议
|
|
250
|
+
*/
|
|
251
|
+
async getSuggestions(text, type = 'general') {
|
|
252
|
+
const suggestions = [];
|
|
253
|
+
|
|
254
|
+
switch (type) {
|
|
255
|
+
case 'email':
|
|
256
|
+
suggestions.push('建议添加称呼');
|
|
257
|
+
suggestions.push('建议添加结束语');
|
|
258
|
+
break;
|
|
259
|
+
case 'document':
|
|
260
|
+
suggestions.push('建议添加标题');
|
|
261
|
+
suggestions.push('建议分段显示');
|
|
262
|
+
break;
|
|
263
|
+
case 'chat':
|
|
264
|
+
suggestions.push('建议使用表情符号');
|
|
265
|
+
suggestions.push('建议@相关人员');
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return suggestions;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* 情感分析
|
|
274
|
+
*/
|
|
275
|
+
async analyzeSentiment(text) {
|
|
276
|
+
// 简单的情感分析
|
|
277
|
+
const positiveWords = ['好', '棒', '优秀', '喜欢', '开心', '高兴', '感谢', '谢谢'];
|
|
278
|
+
const negativeWords = ['不好', '差', '糟糕', '讨厌', '难过', '失望', '抱歉', '对不起'];
|
|
279
|
+
|
|
280
|
+
let positiveCount = 0;
|
|
281
|
+
let negativeCount = 0;
|
|
282
|
+
|
|
283
|
+
positiveWords.forEach(word => {
|
|
284
|
+
if (text.includes(word)) positiveCount++;
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
negativeWords.forEach(word => {
|
|
288
|
+
if (text.includes(word)) negativeCount++;
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
let sentiment = 'neutral';
|
|
292
|
+
let score = 0;
|
|
293
|
+
|
|
294
|
+
if (positiveCount > negativeCount) {
|
|
295
|
+
sentiment = 'positive';
|
|
296
|
+
score = Math.min(1, positiveCount / 5);
|
|
297
|
+
} else if (negativeCount > positiveCount) {
|
|
298
|
+
sentiment = 'negative';
|
|
299
|
+
score = -Math.min(1, negativeCount / 5);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
sentiment: sentiment,
|
|
304
|
+
score: score,
|
|
305
|
+
confidence: Math.abs(score)
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* 自动完成
|
|
311
|
+
*/
|
|
312
|
+
async getAutoComplete(text) {
|
|
313
|
+
// 简单的自动完成
|
|
314
|
+
const completions = [];
|
|
315
|
+
|
|
316
|
+
if (text.endsWith('你好')) {
|
|
317
|
+
completions.push('你好!很高兴见到你!');
|
|
318
|
+
completions.push('你好!有什么可以帮助你的吗?');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (text.endsWith('谢谢')) {
|
|
322
|
+
completions.push('谢谢你的帮助!');
|
|
323
|
+
completions.push('谢谢!非常感谢!');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return completions;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* 渲染AI助手面板(优化后)
|
|
331
|
+
*/
|
|
332
|
+
renderAssistantPanel(container, context = {}) {
|
|
333
|
+
// 添加优化样式
|
|
334
|
+
this.addAIAssistantStyles();
|
|
335
|
+
|
|
336
|
+
container.innerHTML = `
|
|
337
|
+
<div class="ai-assistant-panel-modern">
|
|
338
|
+
<div class="assistant-header-modern">
|
|
339
|
+
<div class="header-left">
|
|
340
|
+
<div class="ai-avatar-large">🤖</div>
|
|
341
|
+
<div class="header-info">
|
|
342
|
+
<h3>AI 智能助手</h3>
|
|
343
|
+
<p class="header-subtitle">为您提供智能服务</p>
|
|
344
|
+
</div>
|
|
345
|
+
</div>
|
|
346
|
+
<button class="btn-close-modern" id="closeAssistant">✕</button>
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
<div class="assistant-tabs-modern">
|
|
350
|
+
<button class="tab-btn-modern active" data-tab="chat">
|
|
351
|
+
<span class="tab-icon">💬</span>
|
|
352
|
+
<span class="tab-label">AI对话</span>
|
|
353
|
+
</button>
|
|
354
|
+
<button class="tab-btn-modern" data-tab="reply">
|
|
355
|
+
<span class="tab-icon">💡</span>
|
|
356
|
+
<span class="tab-label">智能回复</span>
|
|
357
|
+
</button>
|
|
358
|
+
<button class="tab-btn-modern" data-tab="summary">
|
|
359
|
+
<span class="tab-icon">📝</span>
|
|
360
|
+
<span class="tab-label">内容摘要</span>
|
|
361
|
+
</button>
|
|
362
|
+
<button class="tab-btn-modern" data-tab="grammar">
|
|
363
|
+
<span class="tab-icon">✍️</span>
|
|
364
|
+
<span class="tab-label">语法检查</span>
|
|
365
|
+
</button>
|
|
366
|
+
<button class="tab-btn-modern" data-tab="sentiment">
|
|
367
|
+
<span class="tab-icon">😊</span>
|
|
368
|
+
<span class="tab-label">情感分析</span>
|
|
369
|
+
</button>
|
|
370
|
+
</div>
|
|
371
|
+
|
|
372
|
+
<div class="assistant-content-modern">
|
|
373
|
+
<div class="tab-content-modern active" id="chat-tab">
|
|
374
|
+
<div class="ai-chat-container-modern">
|
|
375
|
+
<div class="ai-chat-messages-modern" id="aiChatMessages">
|
|
376
|
+
<div class="ai-message-modern">
|
|
377
|
+
<div class="ai-avatar-small">🤖</div>
|
|
378
|
+
<div class="ai-message-bubble">
|
|
379
|
+
你好!我是AI助手,有什么可以帮助你的吗?
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
<div class="ai-chat-input-modern">
|
|
384
|
+
<input type="text" id="aiChatInput" placeholder="输入消息...按Enter发送" class="chat-input-field">
|
|
385
|
+
<button class="btn-send-modern" id="sendAiMessage">
|
|
386
|
+
<span>📤</span> 发送
|
|
387
|
+
</button>
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
</div>
|
|
391
|
+
|
|
392
|
+
<div class="tab-content-modern" id="reply-tab">
|
|
393
|
+
<div class="feature-card-modern">
|
|
394
|
+
<div class="feature-header">
|
|
395
|
+
<h4>💡 智能回复建议</h4>
|
|
396
|
+
<p>AI将根据上下文为您生成回复建议</p>
|
|
397
|
+
</div>
|
|
398
|
+
<div id="smartReplies" class="smart-replies-modern">
|
|
399
|
+
<div class="empty-state-small">
|
|
400
|
+
<div class="empty-icon">💭</div>
|
|
401
|
+
<p>输入消息后,AI将为您提供回复建议</p>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
</div>
|
|
406
|
+
|
|
407
|
+
<div class="tab-content-modern" id="summary-tab">
|
|
408
|
+
<div class="feature-card-modern">
|
|
409
|
+
<div class="feature-header">
|
|
410
|
+
<h4>📝 内容摘要</h4>
|
|
411
|
+
<p>快速提取文本的核心内容和关键信息</p>
|
|
412
|
+
</div>
|
|
413
|
+
<textarea id="summaryInput" placeholder="粘贴要摘要的内容..." rows="8" class="modern-textarea"></textarea>
|
|
414
|
+
<button class="btn-action-modern" id="generateSummary">
|
|
415
|
+
<span>✨</span> 生成摘要
|
|
416
|
+
</button>
|
|
417
|
+
<div id="summaryResult" class="result-box-modern"></div>
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
|
|
421
|
+
<div class="tab-content-modern" id="grammar-tab">
|
|
422
|
+
<div class="feature-card-modern">
|
|
423
|
+
<div class="feature-header">
|
|
424
|
+
<h4>✍️ 语法检查</h4>
|
|
425
|
+
<p>检查文本中的语法错误和标点问题</p>
|
|
426
|
+
</div>
|
|
427
|
+
<textarea id="grammarInput" placeholder="输入要检查的文本..." rows="8" class="modern-textarea"></textarea>
|
|
428
|
+
<button class="btn-action-modern" id="checkGrammar">
|
|
429
|
+
<span>🔍</span> 检查语法
|
|
430
|
+
</button>
|
|
431
|
+
<div id="grammarResult" class="result-box-modern"></div>
|
|
432
|
+
</div>
|
|
433
|
+
</div>
|
|
434
|
+
|
|
435
|
+
<div class="tab-content-modern" id="sentiment-tab">
|
|
436
|
+
<div class="feature-card-modern">
|
|
437
|
+
<div class="feature-header">
|
|
438
|
+
<h4>😊 情感分析</h4>
|
|
439
|
+
<p>分析文本的情感倾向和情绪色彩</p>
|
|
440
|
+
</div>
|
|
441
|
+
<textarea id="sentimentInput" placeholder="输入要分析的文本..." rows="8" class="modern-textarea"></textarea>
|
|
442
|
+
<button class="btn-action-modern" id="analyzeSentiment">
|
|
443
|
+
<span>📊</span> 分析情感
|
|
444
|
+
</button>
|
|
445
|
+
<div id="sentimentResult" class="result-box-modern"></div>
|
|
446
|
+
</div>
|
|
447
|
+
</div>
|
|
448
|
+
</div>
|
|
449
|
+
</div>
|
|
450
|
+
`;
|
|
451
|
+
|
|
452
|
+
// 标签切换
|
|
453
|
+
container.querySelectorAll('.tab-btn-modern').forEach(btn => {
|
|
454
|
+
btn.addEventListener('click', () => {
|
|
455
|
+
const tab = btn.dataset.tab;
|
|
456
|
+
|
|
457
|
+
container.querySelectorAll('.tab-btn-modern').forEach(b => b.classList.remove('active'));
|
|
458
|
+
container.querySelectorAll('.tab-content-modern').forEach(c => c.classList.remove('active'));
|
|
459
|
+
|
|
460
|
+
btn.classList.add('active');
|
|
461
|
+
container.querySelector(`#${tab}-tab`).classList.add('active');
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// 关闭按钮
|
|
466
|
+
container.querySelector('#closeAssistant').addEventListener('click', () => {
|
|
467
|
+
// 完全移除容器内容和事件监听器
|
|
468
|
+
const panel = container.querySelector('.ai-assistant-panel');
|
|
469
|
+
if (panel) {
|
|
470
|
+
panel.remove();
|
|
471
|
+
}
|
|
472
|
+
container.innerHTML = '';
|
|
473
|
+
|
|
474
|
+
// 如果容器是模态框,也移除模态框本身
|
|
475
|
+
if (container.classList.contains('modal')) {
|
|
476
|
+
container.remove();
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
// AI对话功能
|
|
481
|
+
const aiChatMessages = container.querySelector('#aiChatMessages');
|
|
482
|
+
const aiChatInput = container.querySelector('#aiChatInput');
|
|
483
|
+
const sendAiMessageBtn = container.querySelector('#sendAiMessage');
|
|
484
|
+
|
|
485
|
+
const sendAiMessage = async () => {
|
|
486
|
+
const message = aiChatInput.value.trim();
|
|
487
|
+
if (!message) return;
|
|
488
|
+
|
|
489
|
+
// 添加用户消息
|
|
490
|
+
const userMessageEl = document.createElement('div');
|
|
491
|
+
userMessageEl.className = 'user-message-modern';
|
|
492
|
+
userMessageEl.innerHTML = `
|
|
493
|
+
<div class="user-message-bubble">${message}</div>
|
|
494
|
+
<div class="user-avatar-small">👤</div>
|
|
495
|
+
`;
|
|
496
|
+
aiChatMessages.appendChild(userMessageEl);
|
|
497
|
+
aiChatInput.value = '';
|
|
498
|
+
|
|
499
|
+
// 滚动到底部
|
|
500
|
+
aiChatMessages.scrollTop = aiChatMessages.scrollHeight;
|
|
501
|
+
|
|
502
|
+
// 显示"正在输入"提示
|
|
503
|
+
const typingEl = document.createElement('div');
|
|
504
|
+
typingEl.className = 'ai-message-modern typing-indicator-modern';
|
|
505
|
+
typingEl.innerHTML = `
|
|
506
|
+
<div class="ai-avatar-small">🤖</div>
|
|
507
|
+
<div class="typing-bubble">
|
|
508
|
+
<span class="typing-dot"></span>
|
|
509
|
+
<span class="typing-dot"></span>
|
|
510
|
+
<span class="typing-dot"></span>
|
|
511
|
+
</div>
|
|
512
|
+
`;
|
|
513
|
+
aiChatMessages.appendChild(typingEl);
|
|
514
|
+
aiChatMessages.scrollTop = aiChatMessages.scrollHeight;
|
|
515
|
+
|
|
516
|
+
// 模拟AI响应(延迟1秒)
|
|
517
|
+
setTimeout(async () => {
|
|
518
|
+
typingEl.remove();
|
|
519
|
+
|
|
520
|
+
// 生成AI回复
|
|
521
|
+
const aiReply = await this.generateAIResponse(message);
|
|
522
|
+
|
|
523
|
+
// 添加AI消息
|
|
524
|
+
const aiMessageEl = document.createElement('div');
|
|
525
|
+
aiMessageEl.className = 'ai-message-modern';
|
|
526
|
+
aiMessageEl.innerHTML = `
|
|
527
|
+
<div class="ai-avatar-small">🤖</div>
|
|
528
|
+
<div class="ai-message-bubble">${aiReply}</div>
|
|
529
|
+
`;
|
|
530
|
+
aiChatMessages.appendChild(aiMessageEl);
|
|
531
|
+
|
|
532
|
+
// 滚动到底部
|
|
533
|
+
aiChatMessages.scrollTop = aiChatMessages.scrollHeight;
|
|
534
|
+
}, 1000);
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
sendAiMessageBtn.addEventListener('click', sendAiMessage);
|
|
538
|
+
aiChatInput.addEventListener('keypress', (e) => {
|
|
539
|
+
if (e.key === 'Enter') {
|
|
540
|
+
sendAiMessage();
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
// 生成摘要
|
|
545
|
+
container.querySelector('#generateSummary').addEventListener('click', async () => {
|
|
546
|
+
const input = container.querySelector('#summaryInput').value;
|
|
547
|
+
if (!input) {
|
|
548
|
+
alert('请输入内容');
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const result = await this.summarizeContent(input);
|
|
553
|
+
const resultDiv = container.querySelector('#summaryResult');
|
|
554
|
+
|
|
555
|
+
resultDiv.innerHTML = `
|
|
556
|
+
<div class="result-card-modern">
|
|
557
|
+
<div class="result-section">
|
|
558
|
+
<h5 class="result-title">📄 摘要内容</h5>
|
|
559
|
+
<p class="result-text">${result.summary}</p>
|
|
560
|
+
</div>
|
|
561
|
+
<div class="result-section">
|
|
562
|
+
<h5 class="result-title">🔑 关键词</h5>
|
|
563
|
+
<div class="keywords-modern">
|
|
564
|
+
${result.keyPoints.map(kw => `<span class="keyword-tag">${kw}</span>`).join('')}
|
|
565
|
+
</div>
|
|
566
|
+
</div>
|
|
567
|
+
<div class="result-meta">
|
|
568
|
+
<span class="meta-item">📊 字数: ${result.wordCount}</span>
|
|
569
|
+
</div>
|
|
570
|
+
</div>
|
|
571
|
+
`;
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// 语法检查
|
|
575
|
+
container.querySelector('#checkGrammar').addEventListener('click', async () => {
|
|
576
|
+
const input = container.querySelector('#grammarInput').value;
|
|
577
|
+
if (!input) {
|
|
578
|
+
alert('请输入内容');
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const result = await this.checkGrammar(input);
|
|
583
|
+
const resultDiv = container.querySelector('#grammarResult');
|
|
584
|
+
|
|
585
|
+
resultDiv.innerHTML = `
|
|
586
|
+
<div class="result-card-modern">
|
|
587
|
+
<div class="result-section">
|
|
588
|
+
<h5 class="result-title">📊 语法评分</h5>
|
|
589
|
+
<div class="score-display">
|
|
590
|
+
<div class="score-circle" style="background: conic-gradient(var(--success) ${result.score}%, var(--bg-dark) 0);">
|
|
591
|
+
<div class="score-inner">
|
|
592
|
+
<span class="score-value">${result.score}</span>
|
|
593
|
+
<span class="score-max">/100</span>
|
|
594
|
+
</div>
|
|
595
|
+
</div>
|
|
596
|
+
</div>
|
|
597
|
+
</div>
|
|
598
|
+
${result.issues.length === 0 ?
|
|
599
|
+
'<div class="success-message"><span>✓</span> 未发现语法问题</div>' :
|
|
600
|
+
`<div class="result-section">
|
|
601
|
+
<h5 class="result-title">⚠️ 发现的问题</h5>
|
|
602
|
+
<div class="issues-list">
|
|
603
|
+
${result.issues.map(issue => `
|
|
604
|
+
<div class="issue-item">
|
|
605
|
+
<span class="issue-type-badge">${issue.type}</span>
|
|
606
|
+
<span class="issue-message">${issue.message}</span>
|
|
607
|
+
</div>
|
|
608
|
+
`).join('')}
|
|
609
|
+
</div>
|
|
610
|
+
</div>`
|
|
611
|
+
}
|
|
612
|
+
</div>
|
|
613
|
+
`;
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
// 情感分析
|
|
617
|
+
container.querySelector('#analyzeSentiment').addEventListener('click', async () => {
|
|
618
|
+
const input = container.querySelector('#sentimentInput').value;
|
|
619
|
+
if (!input) {
|
|
620
|
+
alert('请输入内容');
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const result = await this.analyzeSentiment(input);
|
|
625
|
+
const resultDiv = container.querySelector('#sentimentResult');
|
|
626
|
+
|
|
627
|
+
const sentimentText = {
|
|
628
|
+
positive: '积极',
|
|
629
|
+
negative: '消极',
|
|
630
|
+
neutral: '中性'
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
const sentimentEmoji = {
|
|
634
|
+
positive: '😊',
|
|
635
|
+
negative: '😔',
|
|
636
|
+
neutral: '😐'
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
const sentimentColor = {
|
|
640
|
+
positive: 'linear-gradient(135deg, #10b981 0%, #059669 100%)',
|
|
641
|
+
negative: 'linear-gradient(135deg, #ef4444 0%, #dc2626 100%)',
|
|
642
|
+
neutral: 'linear-gradient(135deg, #6b7280 0%, #4b5563 100%)'
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
resultDiv.innerHTML = `
|
|
646
|
+
<div class="result-card-modern">
|
|
647
|
+
<div class="result-section">
|
|
648
|
+
<h5 class="result-title">😊 情感倾向</h5>
|
|
649
|
+
<div class="sentiment-display">
|
|
650
|
+
<div class="sentiment-badge-large" style="background: ${sentimentColor[result.sentiment]};">
|
|
651
|
+
<span class="sentiment-emoji">${sentimentEmoji[result.sentiment]}</span>
|
|
652
|
+
<span class="sentiment-text">${sentimentText[result.sentiment]}</span>
|
|
653
|
+
</div>
|
|
654
|
+
</div>
|
|
655
|
+
</div>
|
|
656
|
+
<div class="result-section">
|
|
657
|
+
<h5 class="result-title">📊 详细数据</h5>
|
|
658
|
+
<div class="sentiment-stats">
|
|
659
|
+
<div class="stat-row">
|
|
660
|
+
<span class="stat-label">情感得分</span>
|
|
661
|
+
<span class="stat-value">${(result.score * 100).toFixed(0)}</span>
|
|
662
|
+
</div>
|
|
663
|
+
<div class="stat-row">
|
|
664
|
+
<span class="stat-label">置信度</span>
|
|
665
|
+
<span class="stat-value">${(result.confidence * 100).toFixed(0)}%</span>
|
|
666
|
+
</div>
|
|
667
|
+
</div>
|
|
668
|
+
</div>
|
|
669
|
+
</div>
|
|
670
|
+
`;
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* 添加AI助手样式
|
|
676
|
+
*/
|
|
677
|
+
addAIAssistantStyles() {
|
|
678
|
+
if (document.getElementById('ai-assistant-modern-styles')) return;
|
|
679
|
+
|
|
680
|
+
const style = document.createElement('style');
|
|
681
|
+
style.id = 'ai-assistant-modern-styles';
|
|
682
|
+
style.textContent = `
|
|
683
|
+
/* AI助手面板 - 现代化样式 */
|
|
684
|
+
.ai-assistant-panel-modern {
|
|
685
|
+
background: var(--bg-card);
|
|
686
|
+
border-radius: 20px;
|
|
687
|
+
overflow: hidden;
|
|
688
|
+
display: flex;
|
|
689
|
+
flex-direction: column;
|
|
690
|
+
height: 80vh;
|
|
691
|
+
max-height: 700px;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/* 头部 */
|
|
695
|
+
.assistant-header-modern {
|
|
696
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
|
697
|
+
padding: 20px 24px;
|
|
698
|
+
display: flex;
|
|
699
|
+
justify-content: space-between;
|
|
700
|
+
align-items: center;
|
|
701
|
+
color: white;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
.header-left {
|
|
705
|
+
display: flex;
|
|
706
|
+
align-items: center;
|
|
707
|
+
gap: 16px;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.ai-avatar-large {
|
|
711
|
+
width: 50px;
|
|
712
|
+
height: 50px;
|
|
713
|
+
border-radius: 12px;
|
|
714
|
+
background: rgba(255,255,255,0.2);
|
|
715
|
+
display: flex;
|
|
716
|
+
align-items: center;
|
|
717
|
+
justify-content: center;
|
|
718
|
+
font-size: 28px;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.header-info h3 {
|
|
722
|
+
margin: 0;
|
|
723
|
+
font-size: 20px;
|
|
724
|
+
font-weight: 700;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.header-subtitle {
|
|
728
|
+
margin: 4px 0 0;
|
|
729
|
+
font-size: 13px;
|
|
730
|
+
opacity: 0.9;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.btn-close-modern {
|
|
734
|
+
width: 36px;
|
|
735
|
+
height: 36px;
|
|
736
|
+
border-radius: 8px;
|
|
737
|
+
background: rgba(255,255,255,0.2);
|
|
738
|
+
border: none;
|
|
739
|
+
color: white;
|
|
740
|
+
font-size: 24px;
|
|
741
|
+
cursor: pointer;
|
|
742
|
+
transition: all 0.3s ease;
|
|
743
|
+
display: flex;
|
|
744
|
+
align-items: center;
|
|
745
|
+
justify-content: center;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.btn-close-modern:hover {
|
|
749
|
+
background: rgba(255,255,255,0.3);
|
|
750
|
+
transform: rotate(90deg);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/* 标签栏 */
|
|
754
|
+
.assistant-tabs-modern {
|
|
755
|
+
display: flex;
|
|
756
|
+
background: var(--bg-dark);
|
|
757
|
+
border-bottom: 2px solid var(--border);
|
|
758
|
+
overflow-x: auto;
|
|
759
|
+
scrollbar-width: none;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
.assistant-tabs-modern::-webkit-scrollbar {
|
|
763
|
+
display: none;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
.tab-btn-modern {
|
|
767
|
+
flex: 1;
|
|
768
|
+
min-width: 100px;
|
|
769
|
+
padding: 16px 12px;
|
|
770
|
+
background: transparent;
|
|
771
|
+
border: none;
|
|
772
|
+
color: var(--text-secondary);
|
|
773
|
+
cursor: pointer;
|
|
774
|
+
transition: all 0.3s ease;
|
|
775
|
+
display: flex;
|
|
776
|
+
flex-direction: column;
|
|
777
|
+
align-items: center;
|
|
778
|
+
gap: 6px;
|
|
779
|
+
position: relative;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
.tab-btn-modern::after {
|
|
783
|
+
content: '';
|
|
784
|
+
position: absolute;
|
|
785
|
+
bottom: 0;
|
|
786
|
+
left: 0;
|
|
787
|
+
right: 0;
|
|
788
|
+
height: 3px;
|
|
789
|
+
background: var(--primary);
|
|
790
|
+
transform: scaleX(0);
|
|
791
|
+
transition: transform 0.3s ease;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.tab-btn-modern.active {
|
|
795
|
+
color: var(--primary);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
.tab-btn-modern.active::after {
|
|
799
|
+
transform: scaleX(1);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.tab-btn-modern:hover {
|
|
803
|
+
background: rgba(99,102,241,0.1);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.tab-icon {
|
|
807
|
+
font-size: 24px;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.tab-label {
|
|
811
|
+
font-size: 12px;
|
|
812
|
+
font-weight: 600;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/* 内容区域 */
|
|
816
|
+
.assistant-content-modern {
|
|
817
|
+
flex: 1;
|
|
818
|
+
overflow-y: auto;
|
|
819
|
+
padding: 20px;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
.tab-content-modern {
|
|
823
|
+
display: none;
|
|
824
|
+
animation: fadeIn 0.3s ease;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.tab-content-modern.active {
|
|
828
|
+
display: block;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/* 功能卡片 */
|
|
832
|
+
.feature-card-modern {
|
|
833
|
+
background: var(--bg-dark);
|
|
834
|
+
border: 2px solid var(--border);
|
|
835
|
+
border-radius: 16px;
|
|
836
|
+
padding: 24px;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.feature-header {
|
|
840
|
+
margin-bottom: 20px;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
.feature-header h4 {
|
|
844
|
+
margin: 0 0 8px;
|
|
845
|
+
font-size: 18px;
|
|
846
|
+
color: var(--text-primary);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.feature-header p {
|
|
850
|
+
margin: 0;
|
|
851
|
+
font-size: 14px;
|
|
852
|
+
color: var(--text-secondary);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/* AI对话容器 */
|
|
856
|
+
.ai-chat-container-modern {
|
|
857
|
+
display: flex;
|
|
858
|
+
flex-direction: column;
|
|
859
|
+
height: 100%;
|
|
860
|
+
background: var(--bg-dark);
|
|
861
|
+
border: 2px solid var(--border);
|
|
862
|
+
border-radius: 16px;
|
|
863
|
+
overflow: hidden;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
.ai-chat-messages-modern {
|
|
867
|
+
flex: 1;
|
|
868
|
+
overflow-y: auto;
|
|
869
|
+
padding: 20px;
|
|
870
|
+
display: flex;
|
|
871
|
+
flex-direction: column;
|
|
872
|
+
gap: 16px;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/* AI消息 */
|
|
876
|
+
.ai-message-modern {
|
|
877
|
+
display: flex;
|
|
878
|
+
align-items: flex-start;
|
|
879
|
+
gap: 12px;
|
|
880
|
+
animation: slideInLeft 0.3s ease;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.ai-avatar-small {
|
|
884
|
+
width: 36px;
|
|
885
|
+
height: 36px;
|
|
886
|
+
border-radius: 8px;
|
|
887
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
|
888
|
+
display: flex;
|
|
889
|
+
align-items: center;
|
|
890
|
+
justify-content: center;
|
|
891
|
+
font-size: 20px;
|
|
892
|
+
flex-shrink: 0;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
.ai-message-bubble {
|
|
896
|
+
background: var(--bg-card);
|
|
897
|
+
border: 1px solid var(--border);
|
|
898
|
+
border-radius: 12px 12px 12px 4px;
|
|
899
|
+
padding: 12px 16px;
|
|
900
|
+
max-width: 70%;
|
|
901
|
+
color: var(--text-primary);
|
|
902
|
+
line-height: 1.6;
|
|
903
|
+
word-wrap: break-word;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/* 用户消息 */
|
|
907
|
+
.user-message-modern {
|
|
908
|
+
display: flex;
|
|
909
|
+
align-items: flex-start;
|
|
910
|
+
gap: 12px;
|
|
911
|
+
justify-content: flex-end;
|
|
912
|
+
animation: slideInRight 0.3s ease;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
.user-avatar-small {
|
|
916
|
+
width: 36px;
|
|
917
|
+
height: 36px;
|
|
918
|
+
border-radius: 8px;
|
|
919
|
+
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
|
920
|
+
display: flex;
|
|
921
|
+
align-items: center;
|
|
922
|
+
justify-content: center;
|
|
923
|
+
font-size: 20px;
|
|
924
|
+
flex-shrink: 0;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.user-message-bubble {
|
|
928
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
|
929
|
+
border-radius: 12px 12px 4px 12px;
|
|
930
|
+
padding: 12px 16px;
|
|
931
|
+
max-width: 70%;
|
|
932
|
+
color: white;
|
|
933
|
+
line-height: 1.6;
|
|
934
|
+
word-wrap: break-word;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/* 输入中动画 */
|
|
938
|
+
.typing-indicator-modern {
|
|
939
|
+
display: flex;
|
|
940
|
+
align-items: flex-start;
|
|
941
|
+
gap: 12px;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
.typing-bubble {
|
|
945
|
+
background: var(--bg-card);
|
|
946
|
+
border: 1px solid var(--border);
|
|
947
|
+
border-radius: 12px;
|
|
948
|
+
padding: 12px 16px;
|
|
949
|
+
display: flex;
|
|
950
|
+
gap: 6px;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.typing-dot {
|
|
954
|
+
width: 8px;
|
|
955
|
+
height: 8px;
|
|
956
|
+
border-radius: 50%;
|
|
957
|
+
background: var(--text-secondary);
|
|
958
|
+
animation: typingDot 1.4s infinite;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
.typing-dot:nth-child(2) {
|
|
962
|
+
animation-delay: 0.2s;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
.typing-dot:nth-child(3) {
|
|
966
|
+
animation-delay: 0.4s;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
@keyframes typingDot {
|
|
970
|
+
0%, 60%, 100% {
|
|
971
|
+
transform: translateY(0);
|
|
972
|
+
opacity: 0.5;
|
|
973
|
+
}
|
|
974
|
+
30% {
|
|
975
|
+
transform: translateY(-10px);
|
|
976
|
+
opacity: 1;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/* 聊天输入 */
|
|
981
|
+
.ai-chat-input-modern {
|
|
982
|
+
padding: 16px;
|
|
983
|
+
background: var(--bg-card);
|
|
984
|
+
border-top: 1px solid var(--border);
|
|
985
|
+
display: flex;
|
|
986
|
+
gap: 12px;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
.chat-input-field {
|
|
990
|
+
flex: 1;
|
|
991
|
+
padding: 12px 16px;
|
|
992
|
+
background: var(--bg-dark);
|
|
993
|
+
border: 2px solid var(--border);
|
|
994
|
+
border-radius: 10px;
|
|
995
|
+
color: var(--text-primary);
|
|
996
|
+
font-size: 14px;
|
|
997
|
+
transition: all 0.3s ease;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
.chat-input-field:focus {
|
|
1001
|
+
outline: none;
|
|
1002
|
+
border-color: var(--primary);
|
|
1003
|
+
box-shadow: 0 0 0 3px rgba(99,102,241,0.1);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
.btn-send-modern {
|
|
1007
|
+
padding: 12px 24px;
|
|
1008
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
|
1009
|
+
border: none;
|
|
1010
|
+
border-radius: 10px;
|
|
1011
|
+
color: white;
|
|
1012
|
+
font-weight: 600;
|
|
1013
|
+
cursor: pointer;
|
|
1014
|
+
transition: all 0.3s ease;
|
|
1015
|
+
display: flex;
|
|
1016
|
+
align-items: center;
|
|
1017
|
+
gap: 8px;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
.btn-send-modern:hover {
|
|
1021
|
+
transform: translateY(-2px);
|
|
1022
|
+
box-shadow: 0 4px 12px rgba(99,102,241,0.4);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/* 文本域 */
|
|
1026
|
+
.modern-textarea {
|
|
1027
|
+
width: 100%;
|
|
1028
|
+
padding: 12px 16px;
|
|
1029
|
+
background: var(--bg-card);
|
|
1030
|
+
border: 2px solid var(--border);
|
|
1031
|
+
border-radius: 12px;
|
|
1032
|
+
color: var(--text-primary);
|
|
1033
|
+
font-size: 14px;
|
|
1034
|
+
font-family: inherit;
|
|
1035
|
+
resize: vertical;
|
|
1036
|
+
transition: all 0.3s ease;
|
|
1037
|
+
margin-bottom: 16px;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
.modern-textarea:focus {
|
|
1041
|
+
outline: none;
|
|
1042
|
+
border-color: var(--primary);
|
|
1043
|
+
box-shadow: 0 0 0 3px rgba(99,102,241,0.1);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/* 操作按钮 */
|
|
1047
|
+
.btn-action-modern {
|
|
1048
|
+
width: 100%;
|
|
1049
|
+
padding: 14px 24px;
|
|
1050
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
|
1051
|
+
border: none;
|
|
1052
|
+
border-radius: 12px;
|
|
1053
|
+
color: white;
|
|
1054
|
+
font-size: 15px;
|
|
1055
|
+
font-weight: 700;
|
|
1056
|
+
cursor: pointer;
|
|
1057
|
+
transition: all 0.3s ease;
|
|
1058
|
+
display: flex;
|
|
1059
|
+
align-items: center;
|
|
1060
|
+
justify-content: center;
|
|
1061
|
+
gap: 10px;
|
|
1062
|
+
margin-bottom: 20px;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
.btn-action-modern:hover {
|
|
1066
|
+
transform: translateY(-3px);
|
|
1067
|
+
box-shadow: 0 8px 24px rgba(99,102,241,0.4);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
.btn-action-modern span {
|
|
1071
|
+
font-size: 20px;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/* 结果卡片 */
|
|
1075
|
+
.result-box-modern {
|
|
1076
|
+
margin-top: 20px;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
.result-card-modern {
|
|
1080
|
+
background: var(--bg-card);
|
|
1081
|
+
border: 2px solid var(--border);
|
|
1082
|
+
border-radius: 16px;
|
|
1083
|
+
padding: 24px;
|
|
1084
|
+
animation: fadeInUp 0.5s ease;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
.result-section {
|
|
1088
|
+
margin-bottom: 24px;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
.result-section:last-child {
|
|
1092
|
+
margin-bottom: 0;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
.result-title {
|
|
1096
|
+
margin: 0 0 12px;
|
|
1097
|
+
font-size: 16px;
|
|
1098
|
+
font-weight: 700;
|
|
1099
|
+
color: var(--text-primary);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
.result-text {
|
|
1103
|
+
margin: 0;
|
|
1104
|
+
font-size: 14px;
|
|
1105
|
+
color: var(--text-primary);
|
|
1106
|
+
line-height: 1.8;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/* 关键词标签 */
|
|
1110
|
+
.keywords-modern {
|
|
1111
|
+
display: flex;
|
|
1112
|
+
flex-wrap: wrap;
|
|
1113
|
+
gap: 8px;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
.keyword-tag {
|
|
1117
|
+
padding: 6px 12px;
|
|
1118
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
|
1119
|
+
color: white;
|
|
1120
|
+
border-radius: 8px;
|
|
1121
|
+
font-size: 13px;
|
|
1122
|
+
font-weight: 600;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
.result-meta {
|
|
1126
|
+
padding-top: 16px;
|
|
1127
|
+
border-top: 1px solid var(--border);
|
|
1128
|
+
display: flex;
|
|
1129
|
+
gap: 16px;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
.meta-item {
|
|
1133
|
+
font-size: 13px;
|
|
1134
|
+
color: var(--text-secondary);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/* 评分显示 */
|
|
1138
|
+
.score-display {
|
|
1139
|
+
display: flex;
|
|
1140
|
+
justify-content: center;
|
|
1141
|
+
padding: 20px 0;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
.score-circle {
|
|
1145
|
+
width: 120px;
|
|
1146
|
+
height: 120px;
|
|
1147
|
+
border-radius: 50%;
|
|
1148
|
+
display: flex;
|
|
1149
|
+
align-items: center;
|
|
1150
|
+
justify-content: center;
|
|
1151
|
+
position: relative;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
.score-inner {
|
|
1155
|
+
width: 100px;
|
|
1156
|
+
height: 100px;
|
|
1157
|
+
border-radius: 50%;
|
|
1158
|
+
background: var(--bg-dark);
|
|
1159
|
+
display: flex;
|
|
1160
|
+
flex-direction: column;
|
|
1161
|
+
align-items: center;
|
|
1162
|
+
justify-content: center;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
.score-value {
|
|
1166
|
+
font-size: 32px;
|
|
1167
|
+
font-weight: 800;
|
|
1168
|
+
color: var(--text-primary);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
.score-max {
|
|
1172
|
+
font-size: 14px;
|
|
1173
|
+
color: var(--text-secondary);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
/* 成功消息 */
|
|
1177
|
+
.success-message {
|
|
1178
|
+
padding: 16px;
|
|
1179
|
+
background: linear-gradient(135deg, rgba(16,185,129,0.1) 0%, rgba(5,150,105,0.05) 100%);
|
|
1180
|
+
border: 2px solid var(--success);
|
|
1181
|
+
border-radius: 12px;
|
|
1182
|
+
color: var(--success);
|
|
1183
|
+
font-weight: 600;
|
|
1184
|
+
display: flex;
|
|
1185
|
+
align-items: center;
|
|
1186
|
+
gap: 10px;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
.success-message span {
|
|
1190
|
+
font-size: 20px;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
/* 问题列表 */
|
|
1194
|
+
.issues-list {
|
|
1195
|
+
display: flex;
|
|
1196
|
+
flex-direction: column;
|
|
1197
|
+
gap: 12px;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
.issue-item {
|
|
1201
|
+
padding: 12px;
|
|
1202
|
+
background: var(--bg-dark);
|
|
1203
|
+
border: 1px solid var(--border);
|
|
1204
|
+
border-radius: 10px;
|
|
1205
|
+
display: flex;
|
|
1206
|
+
align-items: center;
|
|
1207
|
+
gap: 12px;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
.issue-type-badge {
|
|
1211
|
+
padding: 4px 10px;
|
|
1212
|
+
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
|
1213
|
+
color: white;
|
|
1214
|
+
border-radius: 6px;
|
|
1215
|
+
font-size: 11px;
|
|
1216
|
+
font-weight: 700;
|
|
1217
|
+
text-transform: uppercase;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
.issue-message {
|
|
1221
|
+
flex: 1;
|
|
1222
|
+
font-size: 14px;
|
|
1223
|
+
color: var(--text-primary);
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
/* 情感显示 */
|
|
1227
|
+
.sentiment-display {
|
|
1228
|
+
display: flex;
|
|
1229
|
+
justify-content: center;
|
|
1230
|
+
padding: 20px 0;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
.sentiment-badge-large {
|
|
1234
|
+
padding: 20px 40px;
|
|
1235
|
+
border-radius: 16px;
|
|
1236
|
+
display: flex;
|
|
1237
|
+
flex-direction: column;
|
|
1238
|
+
align-items: center;
|
|
1239
|
+
gap: 12px;
|
|
1240
|
+
color: white;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.sentiment-emoji {
|
|
1244
|
+
font-size: 48px;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
.sentiment-text {
|
|
1248
|
+
font-size: 24px;
|
|
1249
|
+
font-weight: 700;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
.sentiment-stats {
|
|
1253
|
+
display: flex;
|
|
1254
|
+
flex-direction: column;
|
|
1255
|
+
gap: 12px;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
.stat-row {
|
|
1259
|
+
display: flex;
|
|
1260
|
+
justify-content: space-between;
|
|
1261
|
+
align-items: center;
|
|
1262
|
+
padding: 12px;
|
|
1263
|
+
background: var(--bg-dark);
|
|
1264
|
+
border: 1px solid var(--border);
|
|
1265
|
+
border-radius: 10px;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
.stat-label {
|
|
1269
|
+
font-size: 14px;
|
|
1270
|
+
color: var(--text-secondary);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
.stat-value {
|
|
1274
|
+
font-size: 18px;
|
|
1275
|
+
font-weight: 700;
|
|
1276
|
+
color: var(--text-primary);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
/* 空状态 */
|
|
1280
|
+
.empty-state-small {
|
|
1281
|
+
text-align: center;
|
|
1282
|
+
padding: 40px 20px;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
.empty-icon {
|
|
1286
|
+
font-size: 48px;
|
|
1287
|
+
margin-bottom: 16px;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
.empty-state-small p {
|
|
1291
|
+
margin: 0;
|
|
1292
|
+
color: var(--text-secondary);
|
|
1293
|
+
font-size: 14px;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
/* 智能回复 */
|
|
1297
|
+
.smart-replies-modern {
|
|
1298
|
+
display: flex;
|
|
1299
|
+
flex-direction: column;
|
|
1300
|
+
gap: 12px;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
/* 动画 */
|
|
1304
|
+
@keyframes fadeIn {
|
|
1305
|
+
from {
|
|
1306
|
+
opacity: 0;
|
|
1307
|
+
}
|
|
1308
|
+
to {
|
|
1309
|
+
opacity: 1;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
@keyframes fadeInUp {
|
|
1314
|
+
from {
|
|
1315
|
+
opacity: 0;
|
|
1316
|
+
transform: translateY(20px);
|
|
1317
|
+
}
|
|
1318
|
+
to {
|
|
1319
|
+
opacity: 1;
|
|
1320
|
+
transform: translateY(0);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
@keyframes slideInLeft {
|
|
1325
|
+
from {
|
|
1326
|
+
opacity: 0;
|
|
1327
|
+
transform: translateX(-20px);
|
|
1328
|
+
}
|
|
1329
|
+
to {
|
|
1330
|
+
opacity: 1;
|
|
1331
|
+
transform: translateX(0);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
@keyframes slideInRight {
|
|
1336
|
+
from {
|
|
1337
|
+
opacity: 0;
|
|
1338
|
+
transform: translateX(20px);
|
|
1339
|
+
}
|
|
1340
|
+
to {
|
|
1341
|
+
opacity: 1;
|
|
1342
|
+
transform: translateX(0);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
/* 响应式 */
|
|
1347
|
+
@media (max-width: 768px) {
|
|
1348
|
+
.ai-assistant-panel-modern {
|
|
1349
|
+
height: 90vh;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
.assistant-tabs-modern {
|
|
1353
|
+
overflow-x: auto;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
.tab-btn-modern {
|
|
1357
|
+
min-width: 80px;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
.tab-label {
|
|
1361
|
+
font-size: 11px;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
.ai-message-bubble,
|
|
1365
|
+
.user-message-bubble {
|
|
1366
|
+
max-width: 85%;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
`;
|
|
1370
|
+
document.head.appendChild(style);
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
/**
|
|
1374
|
+
* 显示智能回复
|
|
1375
|
+
*/
|
|
1376
|
+
async showSmartReplies(message, container) {
|
|
1377
|
+
const replies = await this.getSmartReplies(message);
|
|
1378
|
+
|
|
1379
|
+
container.innerHTML = `
|
|
1380
|
+
<div class="smart-replies-list">
|
|
1381
|
+
${replies.map(reply => `
|
|
1382
|
+
<button class="smart-reply-btn">${reply}</button>
|
|
1383
|
+
`).join('')}
|
|
1384
|
+
</div>
|
|
1385
|
+
`;
|
|
1386
|
+
|
|
1387
|
+
// 点击回复按钮
|
|
1388
|
+
container.querySelectorAll('.smart-reply-btn').forEach(btn => {
|
|
1389
|
+
btn.addEventListener('click', () => {
|
|
1390
|
+
// 触发自定义事件,将回复内容传递出去
|
|
1391
|
+
window.dispatchEvent(new CustomEvent('smartReplySelected', {
|
|
1392
|
+
detail: { reply: btn.textContent }
|
|
1393
|
+
}));
|
|
1394
|
+
});
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
|