Преглед на файлове

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

闪电 преди 10 месеца
родител
ревизия
9a438d0aea
променени са 2 файла, в които са добавени 101 реда и са изтрити 68 реда
  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,6 +274,10 @@
274 274
             type: String,
275 275
             default: ''
276 276
         },
277
+        knowledgeId: {
278
+            type: Number,
279
+            default: 0
280
+        },
277 281
     });
278 282
 
279 283
     onMounted(() => {
@@ -285,6 +289,9 @@
285 289
             postChatText.value = props.text;
286 290
             enterHnadle();
287 291
         }
292
+        if (props.knowledgeId) {
293
+            sendKnowledge(props.knowledgeId)
294
+        }
288 295
     })
289 296
 
290 297
     watch(props , (newVal, oldVal) => {
@@ -293,6 +300,9 @@
293 300
             postChatText.value = newVal.text;
294 301
             enterHnadle();
295 302
         }
303
+        if (newVal.knowledgeId) {
304
+            sendKnowledge(newVal.knowledgeId)
305
+        }
296 306
     })
297 307
 
298 308
     const currentSession = ref({});
@@ -367,6 +377,8 @@
367 377
     const knowledgeDetail = ref({})
368 378
     const knowledgeText = ref('')
369 379
     function sendKnowledge(docId) {
380
+        dialogState.value = '会话中'
381
+        tipFlag.value = false
370 382
         getPageDetail('/km/doc/' + docId).then((data) => {
371 383
             if (data.data) {
372 384
                 knowledgeDetail.value = data.data;

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

@@ -137,7 +137,7 @@
137 137
                                 <div class="relative mb-4">
138 138
                                     <div class="absolute left-0 top-0 w-full h-16 bg-gradient-to-b from
139 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 141
                                         <div v-for="(item, index) in transcripts" :key="index" class="p-3 rounded-lg"
142 142
                                             :class="[item.direction === 2 ? 'bg-blue-50' : 'bg-gray-50']">
143 143
                                             <div class="flex items-center mb-1">
@@ -171,6 +171,7 @@ from-white to-transparent pointer-events-none z-10"></div>
171 171
                                         effect="plain" size="small" @click="getKnowledgeBaseList(keyword.text)">
172 172
                                         {{ keyword.text }}
173 173
                                         <span
174
+                                        v-if="keyword.count > 1"
174 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 176
                                             {{ keyword.count }}
176 177
                                         </span>
@@ -184,14 +185,14 @@ from-white to-transparent pointer-events-none z-10"></div>
184 185
                                     <div v-for="(item, idx) in recommendedKnowledge" :key="idx"
185 186
                                         class="p-4 bg-white rounded-lg shadow-sm hover:shadow-md transition-all cursor-pointer">
186 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 189
                                             <el-tag size="small" type="default">{{ item.directoryname }}</el-tag>
189 190
                                         </div>
190 191
                                         <p class="text-sm text-gray-600 line-clamp-2 mb-2">{{
191 192
                                             stripHtmlByRegex(item.content) }}</p>
192 193
                                         <div class="flex items-center justify-between text-xs text-gray-500">
193 194
                                             <span>发布时间:{{ item.createTime }}</span>
194
-                                            <span>阅读:{{ item.reads }}</span>
195
+                                            <!-- <span>阅读:{{ item.reads }}</span> -->
195 196
                                         </div>
196 197
                                     </div>
197 198
                                 </div>
@@ -420,12 +421,24 @@ from-white to-transparent pointer-events-none z-10"></div>
420 421
             </div>
421 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 434
     </div>
424 435
 </template>
425 436
 <script lang="ts" setup name="CallScreen">
426 437
 import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
427 438
 import moment from 'moment';
428 439
 import { findKeyword } from '@/utils/trie';
440
+import { base64data } from '@/utils/baseUrlData'
441
+import aiDialog from '@/components/main/Navbar/cpns/aiDialog/aiDialog.vue'
429 442
 import {
430 443
     UserFilled,
431 444
     Phone,
@@ -466,6 +479,7 @@ const showCallPanel = ref(false);
466 479
 const searchQuery = ref('');
467 480
 const aiLoading = ref(false);
468 481
 const isCanAutoScroll = ref(1); 
482
+const dialogVisible = ref(false);
469 483
 
470 484
 const showAsr = ref(import.meta.env.VITE_APP_AI_ASR === 'true');
471 485
 const showAI = ref(import.meta.env.VITE_APP_AI_SEARCH === 'true');
@@ -845,23 +859,12 @@ const transcripts: any = ref([
845 859
 ])
846 860
 // 关键词提示
847 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 870
 const suggestions = ref([
@@ -873,21 +876,21 @@ const suggestions = ref([
873 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 895
 window.addEventListener('AsrMessageEvent', (msg: any) => {
893 896
     console.log(msg.detail, '接收asr消息');
@@ -1059,40 +1062,7 @@ async function getSearchDocs (text) {
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 1068
 const keys = useKeysStore().knowledgeKeys;
@@ -1142,8 +1112,33 @@ const setKeys = (keys: Array<string>) => {
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 1140
 </script>
1146
-<style scoped>
1141
+<style scoped lang="scss">
1147 1142
 * {
1148 1143
     transition: height 0.3s ease-out;
1149 1144
 }
@@ -1211,4 +1206,30 @@ const setKeys = (keys: Array<string>) => {
1211 1206
 :deep(.el-icon) {
1212 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 1235
 </style>