Przeglądaj źródła

客服卡片修改

Zhangbw 2 miesięcy temu
rodzic
commit
026dda20c4

+ 5 - 2
.claude/settings.local.json

@@ -8,11 +8,14 @@
       "Bash(dir:*)",
       "Read(//d/program/**)",
       "Bash(tree:*)",
-      "Bash(git checkout:*)"
+      "Bash(git checkout:*)",
+      "Bash(curl:*)"
     ],
     "additionalDirectories": [
       "d:\\program\\AI-TALK\\ruoyi-modules\\yp-talk",
-      "d:\\program\\AI-TALK\\ruoyi-modules\\yp-talk\\src\\main\\java\\org\\dromara\\talk"
+      "d:\\program\\AI-TALK\\ruoyi-modules\\yp-talk\\src\\main\\java\\org\\dromara\\talk",
+      "D:\\program\\AI-TALK-UI\\src\\views\\talk\\agent",
+      "D:\\program\\AI-TALK-UI\\src\\api\\talk\\agent"
     ]
   }
 }

+ 73 - 31
src/CustomerService.vue

@@ -21,17 +21,6 @@
               </div>
               <div v-if="basicExpanded" class="collapse-content">
                 <el-form label-position="top" size="default">
-                  <el-form-item label="语言">
-                    <el-select v-model="config.language" style="width: 100%">
-                      <el-option
-                        v-for="item in languageOptions"
-                        :key="item.dictValue"
-                        :label="item.dictLabel"
-                        :value="item.dictValue"
-                      />
-                    </el-select>
-                  </el-form-item>
-
                   <el-form-item label="背景音">
                     <el-radio-group v-model="config.bgSoundEnabled">
                       <el-radio-button :value="true">开启</el-radio-button>
@@ -111,6 +100,9 @@
                   <img v-if="agent.avatarUrl" :src="getAvatarUrl(agent.avatarUrl)" class="avatar-img" />
                   <div v-else class="avatar" :class="agent.gender"></div>
                   <div class="gender-icon" :class="agent.gender">{{ agent.gender === 'female' ? '♀' : '♂' }}</div>
+                  <div class="status-badge" :class="'status-' + agent.status">
+                    {{ agent.status === '0' ? '正常' : agent.status === '1' ? '停用' : '对话中' }}
+                  </div>
                   <div class="agent-name">{{ agent.name }}</div>
                 </div>
               </div>
@@ -206,7 +198,6 @@ const basicExpanded = ref(true)
 const otherExpanded = ref(false)
 const currentPage = ref(0)
 const chatContent = ref(null)
-const languageOptions = ref([])
 
 // 语音识别
 const { isRecording, currentTranscription, tempTranscription, startRecording, stopRecording } = useVoiceRecognition()
@@ -291,6 +282,7 @@ watch(currentTranscription, async (newVal, oldVal) => {
 
       // 发送到后端处理
       try {
+        const selectedAgentData = agents.value.find(a => a.id === selectedAgent.value)
         const response = await fetch('http://localhost:8080/talk/message', {
           method: 'POST',
           headers: {
@@ -298,7 +290,9 @@ watch(currentTranscription, async (newVal, oldVal) => {
           },
           body: JSON.stringify({
             message: newContent,
-            agentId: selectedAgent.value
+            agentId: selectedAgent.value,
+            agentGender: selectedAgentData?.gender === 'male' ? '0' : '1',
+            ttsVcnList: ttsVcnList.value
           })
         })
 
@@ -341,6 +335,25 @@ watch(showChat, async (newVal) => {
       clearInterval(waveformInterval)
       waveformInterval = null
     }
+
+    // 对话结束,将客服状态改回正常
+    if (selectedAgent.value) {
+      try {
+        await fetch('http://localhost:8080/talk/agent/' + selectedAgent.value, {
+          method: 'PUT',
+          headers: {
+            'Content-Type': 'application/json'
+          },
+          body: JSON.stringify({
+            id: selectedAgent.value,
+            status: '0'
+          })
+        })
+        console.log('客服状态已恢复为正常')
+      } catch (error) {
+        console.error('更新客服状态失败:', error)
+      }
+    }
   }
 })
 
@@ -410,6 +423,7 @@ const sendTextMessage = async () => {
 
   // 发送到后端处理
   try {
+    const selectedAgentData = agents.value.find(a => a.id === selectedAgent.value)
     const response = await fetch('http://localhost:8080/talk/message', {
       method: 'POST',
       headers: {
@@ -417,7 +431,9 @@ const sendTextMessage = async () => {
       },
       body: JSON.stringify({
         message: content,
-        agentId: selectedAgent.value
+        agentId: selectedAgent.value,
+        agentGender: selectedAgentData?.gender === 'male' ? '0' : '1',
+        ttsVcnList: ttsVcnList.value
       })
     })
 
@@ -442,9 +458,9 @@ const sendTextMessage = async () => {
 }
 
 const agents = ref([])
+const ttsVcnList = ref([])
 
 const config = ref({
-  language: 'zh',
   bgSoundEnabled: false,
   speed: 50,
   pitch: 50,
@@ -453,6 +469,17 @@ const config = ref({
 
 const selectedAgent = ref(null)
 
+// 获取发言人字典列表
+const fetchTtsVcnList = async () => {
+  try {
+    const response = await fetch('http://localhost:8080/talk/dict/ttsVcn')
+    const data = await response.json()
+    ttsVcnList.value = data || []
+  } catch (error) {
+    console.error('获取发言人字典失败:', error)
+  }
+}
+
 // 获取客服列表
 const fetchAgents = async () => {
   try {
@@ -470,7 +497,7 @@ const fetchAgents = async () => {
         ttsPitch: agent.ttsPitch,
         ttsVolume: agent.ttsVolume,
         ttsBgs: agent.ttsBgs,
-        language: agent.language
+        status: agent.status
       }))
       if (agents.value.length > 0) {
         selectedAgent.value = agents.value[0].id
@@ -482,22 +509,10 @@ const fetchAgents = async () => {
   }
 }
 
-// 获取语言字典
-const fetchLanguageOptions = async () => {
-  try {
-    const response = await fetch('http://localhost:8080/talk/dict/language')
-    const data = await response.json()
-    languageOptions.value = data
-  } catch (error) {
-    console.error('获取语言选项失败:', error)
-    ElMessage.error('获取语言选项失败')
-  }
-}
-
-// 组件挂载时获取语言选项和客服列表
+// 组件挂载时获取客服列表和发言人字典
 onMounted(() => {
-  fetchLanguageOptions()
   fetchAgents()
+  fetchTtsVcnList()
 })
 
 // 获取头像完整URL
@@ -531,7 +546,7 @@ const startChat = async () => {
           ttsPitch: config.value.pitch,
           ttsVolume: config.value.volume,
           ttsBgs: config.value.bgSoundEnabled ? 1 : 0,
-          language: config.value.language
+          status: '2'  // 设置状态为对话中
         })
       })
 
@@ -973,6 +988,33 @@ const handleWheel = (e) => {
   background: #3b82f6;
 }
 
+.status-badge {
+  position: absolute;
+  top: 8px;
+  left: 8px;
+  padding: 4px 12px;
+  border-radius: 20px;
+  font-size: 11px;
+  font-weight: 600;
+  z-index: 1;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.status-badge.status-0 {
+  background: #10b981;
+  color: white;
+}
+
+.status-badge.status-1 {
+  background: #9ca3af;
+  color: white;
+}
+
+.status-badge.status-2 {
+  background: #ef4444;
+  color: white;
+}
+
 .agent-name {
   font-size: 14px;
   color: #1f2937;

+ 10 - 1
target/classes/META-INF/mps/mappers

@@ -1,2 +1,11 @@
 org.dromara.web.domain.vo.TenantListVoToSysTenantVoMapper
-org.dromara.system.domain.vo.SysTenantVoToTenantListVoMapper
+org.dromara.workflow.domain.FlowSpelToFlowSpelVoMapper
+org.dromara.workflow.domain.vo.FlowCategoryVoToFlowCategoryMapper
+org.dromara.workflow.domain.bo.FlowCategoryBoToFlowCategoryMapper
+org.dromara.workflow.domain.vo.FlowSpelVoToFlowSpelMapper
+org.dromara.workflow.domain.bo.FlowSpelBoToFlowSpelMapper
+org.dromara.workflow.domain.bo.TestLeaveBoToTestLeaveMapper
+org.dromara.system.domain.vo.SysTenantVoToTenantListVoMapper
+org.dromara.workflow.domain.vo.TestLeaveVoToTestLeaveMapper
+org.dromara.workflow.domain.TestLeaveToTestLeaveVoMapper
+org.dromara.workflow.domain.FlowCategoryToFlowCategoryVoMapper