Quellcode durchsuchen

feat(aiDialog): 添加知识库ID参数及交互逻辑

闪电 vor 10 Monaten
Ursprung
Commit
9a438d0aea
2 geänderte Dateien mit 101 neuen und 68 gelöschten Zeilen
  1. 12 0
      src/components/main/Navbar/cpns/aiDialog/aiDialog.vue
  2. 89 68
      src/views/main/phone/index.vue

+ 12 - 0
src/components/main/Navbar/cpns/aiDialog/aiDialog.vue

274
             type: String,
274
             type: String,
275
             default: ''
275
             default: ''
276
         },
276
         },
277
+        knowledgeId: {
278
+            type: Number,
279
+            default: 0
280
+        },
277
     });
281
     });
278
 
282
 
279
     onMounted(() => {
283
     onMounted(() => {
285
             postChatText.value = props.text;
289
             postChatText.value = props.text;
286
             enterHnadle();
290
             enterHnadle();
287
         }
291
         }
292
+        if (props.knowledgeId) {
293
+            sendKnowledge(props.knowledgeId)
294
+        }
288
     })
295
     })
289
 
296
 
290
     watch(props , (newVal, oldVal) => {
297
     watch(props , (newVal, oldVal) => {
293
             postChatText.value = newVal.text;
300
             postChatText.value = newVal.text;
294
             enterHnadle();
301
             enterHnadle();
295
         }
302
         }
303
+        if (newVal.knowledgeId) {
304
+            sendKnowledge(newVal.knowledgeId)
305
+        }
296
     })
306
     })
297
 
307
 
298
     const currentSession = ref({});
308
     const currentSession = ref({});
367
     const knowledgeDetail = ref({})
377
     const knowledgeDetail = ref({})
368
     const knowledgeText = ref('')
378
     const knowledgeText = ref('')
369
     function sendKnowledge(docId) {
379
     function sendKnowledge(docId) {
380
+        dialogState.value = '会话中'
381
+        tipFlag.value = false
370
         getPageDetail('/km/doc/' + docId).then((data) => {
382
         getPageDetail('/km/doc/' + docId).then((data) => {
371
             if (data.data) {
383
             if (data.data) {
372
                 knowledgeDetail.value = data.data;
384
                 knowledgeDetail.value = data.data;

+ 89 - 68
src/views/main/phone/index.vue

137
                                 <div class="relative mb-4">
137
                                 <div class="relative mb-4">
138
                                     <div class="absolute left-0 top-0 w-full h-16 bg-gradient-to-b from
138
                                     <div class="absolute left-0 top-0 w-full h-16 bg-gradient-to-b from
139
 from-white to-transparent pointer-events-none z-10"></div>
139
 from-white to-transparent pointer-events-none z-10"></div>
140
-                                    <div ref="transcriptContainer" class="h-[500px] overflow-y-auto pr-4 space-y-3">
140
+                                    <div ref="transcriptContainer" class="h-[500px] overflow-y-auto pr-4 space-y-3"  @mouseenter="chatMouse(0)" @mouseleave="chatMouse(1)">
141
                                         <div v-for="(item, index) in transcripts" :key="index" class="p-3 rounded-lg"
141
                                         <div v-for="(item, index) in transcripts" :key="index" class="p-3 rounded-lg"
142
                                             :class="[item.direction === 2 ? 'bg-blue-50' : 'bg-gray-50']">
142
                                             :class="[item.direction === 2 ? 'bg-blue-50' : 'bg-gray-50']">
143
                                             <div class="flex items-center mb-1">
143
                                             <div class="flex items-center mb-1">
171
                                         effect="plain" size="small" @click="getKnowledgeBaseList(keyword.text)">
171
                                         effect="plain" size="small" @click="getKnowledgeBaseList(keyword.text)">
172
                                         {{ keyword.text }}
172
                                         {{ keyword.text }}
173
                                         <span
173
                                         <span
174
+                                        v-if="keyword.count > 1"
174
                                             class="absolute -top-1 -right-1 bg-blue-500 text-white text-[10px] rounded-full w-4 h-4 flex items-center justify-center">
175
                                             class="absolute -top-1 -right-1 bg-blue-500 text-white text-[10px] rounded-full w-4 h-4 flex items-center justify-center">
175
                                             {{ keyword.count }}
176
                                             {{ keyword.count }}
176
                                         </span>
177
                                         </span>
184
                                     <div v-for="(item, idx) in recommendedKnowledge" :key="idx"
185
                                     <div v-for="(item, idx) in recommendedKnowledge" :key="idx"
185
                                         class="p-4 bg-white rounded-lg shadow-sm hover:shadow-md transition-all cursor-pointer">
186
                                         class="p-4 bg-white rounded-lg shadow-sm hover:shadow-md transition-all cursor-pointer">
186
                                         <div class="flex items-center justify-between mb-2">
187
                                         <div class="flex items-center justify-between mb-2">
187
-                                            <h5 class="font-medium">{{ item.title }}</h5>
188
+                                            <h5 class="font-medium" @click="openKnowledgeAi(item.docId)">{{ item.title }}</h5>
188
                                             <el-tag size="small" type="default">{{ item.directoryname }}</el-tag>
189
                                             <el-tag size="small" type="default">{{ item.directoryname }}</el-tag>
189
                                         </div>
190
                                         </div>
190
                                         <p class="text-sm text-gray-600 line-clamp-2 mb-2">{{
191
                                         <p class="text-sm text-gray-600 line-clamp-2 mb-2">{{
191
                                             stripHtmlByRegex(item.content) }}</p>
192
                                             stripHtmlByRegex(item.content) }}</p>
192
                                         <div class="flex items-center justify-between text-xs text-gray-500">
193
                                         <div class="flex items-center justify-between text-xs text-gray-500">
193
                                             <span>发布时间:{{ item.createTime }}</span>
194
                                             <span>发布时间:{{ item.createTime }}</span>
194
-                                            <span>阅读:{{ item.reads }}</span>
195
+                                            <!-- <span>阅读:{{ item.reads }}</span> -->
195
                                         </div>
196
                                         </div>
196
                                     </div>
197
                                     </div>
197
                                 </div>
198
                                 </div>
420
             </div>
421
             </div>
421
         </div>
422
         </div>
422
 
423
 
424
+
425
+        <div class="aiDialog">
426
+            <!-- title="Tips" -->
427
+            <el-dialog v-model="dialogVisible" :close-on-click-modal="false" :close-on-press-escape="false"
428
+                :modal="false" width="30%"
429
+                :style="{ 'background': 'url(' + base64data.aiBG + ') center center / 100% 100% no-repeat' }" draggable>
430
+                <ai-dialog :knowledgeId="selectKnowledgeId"></ai-dialog>
431
+            </el-dialog>
432
+        </div>
433
+
423
     </div>
434
     </div>
424
 </template>
435
 </template>
425
 <script lang="ts" setup name="CallScreen">
436
 <script lang="ts" setup name="CallScreen">
426
 import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
437
 import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
427
 import moment from 'moment';
438
 import moment from 'moment';
428
 import { findKeyword } from '@/utils/trie';
439
 import { findKeyword } from '@/utils/trie';
440
+import { base64data } from '@/utils/baseUrlData'
441
+import aiDialog from '@/components/main/Navbar/cpns/aiDialog/aiDialog.vue'
429
 import {
442
 import {
430
     UserFilled,
443
     UserFilled,
431
     Phone,
444
     Phone,
466
 const searchQuery = ref('');
479
 const searchQuery = ref('');
467
 const aiLoading = ref(false);
480
 const aiLoading = ref(false);
468
 const isCanAutoScroll = ref(1); 
481
 const isCanAutoScroll = ref(1); 
482
+const dialogVisible = ref(false);
469
 
483
 
470
 const showAsr = ref(import.meta.env.VITE_APP_AI_ASR === 'true');
484
 const showAsr = ref(import.meta.env.VITE_APP_AI_ASR === 'true');
471
 const showAI = ref(import.meta.env.VITE_APP_AI_SEARCH === 'true');
485
 const showAI = ref(import.meta.env.VITE_APP_AI_SEARCH === 'true');
845
 ])
859
 ])
846
 // 关键词提示
860
 // 关键词提示
847
 const keywords: any = ref([
861
 const keywords: any = ref([
848
-    {
849
-        text: '强迫症',
850
-        type: 'primary',
851
-        count: 0,
852
-    },
853
-    // {
854
-    //     text: '操作流程',
855
-    //     type: 'success'
856
-    // },
857
     // {
862
     // {
858
-    //     text: '正面反馈',
859
-    //     type: 'success'
863
+    //     text: '强迫症',
864
+    //     type: 'primary',
865
+    //     count: 0,
860
     // },
866
     // },
861
-    // {
862
-    //     text: '满意度高',
863
-    //     type: 'success'
864
-    // }
867
+    
865
 ]);
868
 ]);
866
 // 建议话术
869
 // 建议话术
867
 const suggestions = ref([
870
 const suggestions = ref([
873
 const transcriptContainer = ref<HTMLElement | null>(null);
876
 const transcriptContainer = ref<HTMLElement | null>(null);
874
 // 监听新消息,自动滚动到底部
877
 // 监听新消息,自动滚动到底部
875
 // 监听新消息和内容变化,自动滚动到底部
878
 // 监听新消息和内容变化,自动滚动到底部
876
-watch(
877
-    [
878
-        () => transcripts.value.length,
879
-        () => transcripts.value.map(t => t.page_content)
880
-    ],
881
-    () => {
882
-        nextTick(() => {
883
-            console.log(transcriptContainer.value, 'transcriptContainer');
884
-            if (transcriptContainer.value) {
885
-                transcriptContainer.value.scrollTop = transcriptContainer.value.scrollHeight;
886
-            }
887
-        });
888
-    },
889
-    { deep: true }
890
-);
879
+// watch(
880
+//     [
881
+//         () => transcripts.value.length,
882
+//         () => transcripts.value.map(t => t.page_content)
883
+//     ],
884
+//     () => {
885
+//         nextTick(() => {
886
+//             console.log(transcriptContainer.value, 'transcriptContainer');
887
+//             if (transcriptContainer.value) {
888
+//                 transcriptContainer.value.scrollTop = transcriptContainer.value.scrollHeight;
889
+//             }
890
+//         });
891
+//     },
892
+//     { deep: true }
893
+// );
891
 
894
 
892
 window.addEventListener('AsrMessageEvent', (msg: any) => {
895
 window.addEventListener('AsrMessageEvent', (msg: any) => {
893
     console.log(msg.detail, '接收asr消息');
896
     console.log(msg.detail, '接收asr消息');
1059
 }
1062
 }
1060
 
1063
 
1061
 // 推荐知识
1064
 // 推荐知识
1062
-const recommendedKnowledge: any = ref([
1063
-    // {
1064
-    //     title: '智能客服系统功能配置指南',
1065
-    //     content: '本文详细介绍了智能客服系统的核心功能配置方法,包括自动应答规则设置、多渠道接入配置、知识库管理等内容。通过本指南,您可以快速掌握系统的基础配置和高级功能设置。',
1066
-    //     category: '使用指南',
1067
-    //     type: 'primary',
1068
-    //     publishTime: '2024-01-20',
1069
-    //     reads: 1234
1070
-    // },
1071
-    // {
1072
-    //     title: '常见故障诊断与解决方案',
1073
-    //     content: '汇总了系统使用过程中最常见的技术问题和解决方案,包括登录异常、数据同步失败、性能优化等问题的处理方法。本文档由技术支持团队整理,持续更新维护。',
1074
-    //     category: '技术支持',
1075
-    //     type: 'warning',
1076
-    //     publishTime: '2024-01-18',
1077
-    //     reads: 856
1078
-    // },
1079
-    // {
1080
-    //     title: '客服质量管理最佳实践',
1081
-    //     content: '本文从客服管理者的角度,详细介绍了如何提升客服团队的服务质量,包括话术规范、服务标准、质检方案等内容,帮助管理者建立高效的客服质量管理体系。',
1082
-    //     category: '最佳实践',
1083
-    //     type: 'success',
1084
-    //     publishTime: '2024-01-15',
1085
-    //     reads: 678
1086
-    // },
1087
-    // {
1088
-    //     title: '数据分析报表解读指南',
1089
-    //     content: '详细说明了系统各类数据分析报表的含义和使用方法,包括客服效率分析、满意度趋势、问题分类统计等报表的查看和导出方式,帮助您更好地利用数据指导工作。',
1090
-    //     category: '数据分析',
1091
-    //     type: 'info',
1092
-    //     publishTime: '2024-01-12',
1093
-    //     reads: 945
1094
-    // }
1095
-]);
1065
+const recommendedKnowledge: any = ref([]);
1096
 
1066
 
1097
 
1067
 
1098
 const keys = useKeysStore().knowledgeKeys;
1068
 const keys = useKeysStore().knowledgeKeys;
1142
 
1112
 
1143
 }
1113
 }
1144
 
1114
 
1115
+const selectKnowledgeId = ref(0);
1116
+
1117
+const openKnowledgeAi = (id) => {
1118
+    selectKnowledgeId.value = id;
1119
+    dialogVisible.value = true;
1120
+}
1121
+
1122
+const chatMouse = (type) => {
1123
+    isCanAutoScroll.value = type;
1124
+}
1125
+
1126
+const scrollToBottom = () => {
1127
+    if (transcriptContainer.value) {
1128
+        transcriptContainer.value.scrollTop = transcriptContainer.value.scrollHeight;
1129
+    }
1130
+}
1131
+
1132
+watch(transcripts, () => {
1133
+    nextTick(() => {
1134
+        if (isCanAutoScroll.value) scrollToBottom();
1135
+    })
1136
+}, {
1137
+    deep: true
1138
+})
1139
+
1145
 </script>
1140
 </script>
1146
-<style scoped>
1141
+<style scoped lang="scss">
1147
 * {
1142
 * {
1148
     transition: height 0.3s ease-out;
1143
     transition: height 0.3s ease-out;
1149
 }
1144
 }
1211
 :deep(.el-icon) {
1206
 :deep(.el-icon) {
1212
     font-size: 1.25rem;
1207
     font-size: 1.25rem;
1213
 }
1208
 }
1209
+
1210
+.aiDialog {
1211
+    z-index: 2033;
1212
+    pointer-events: none;
1213
+
1214
+    :deep(.el-dialog) {
1215
+        position: absolute;
1216
+        height: 700px;
1217
+        top: 50px;
1218
+        right: 0;
1219
+        margin: 0;
1220
+        left: unset;
1221
+        pointer-events: auto;
1222
+    }
1223
+}
1224
+
1225
+/* 隐藏所有滚动条 */
1226
+* {
1227
+  scrollbar-width: none; /* Firefox */
1228
+  -ms-overflow-style: none;  /* Internet Explorer 10+ */
1229
+}
1230
+
1231
+/* 针对Webkit浏览器(如Chrome和Safari) */
1232
+*::-webkit-scrollbar {
1233
+  display: none;
1234
+}
1214
 </style>
1235
 </style>