|
@@ -21,17 +21,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
<div v-if="basicExpanded" class="collapse-content">
|
|
<div v-if="basicExpanded" class="collapse-content">
|
|
|
<el-form label-position="top" size="default">
|
|
<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-form-item label="背景音">
|
|
|
<el-radio-group v-model="config.bgSoundEnabled">
|
|
<el-radio-group v-model="config.bgSoundEnabled">
|
|
|
<el-radio-button :value="true">开启</el-radio-button>
|
|
<el-radio-button :value="true">开启</el-radio-button>
|
|
@@ -111,6 +100,9 @@
|
|
|
<img v-if="agent.avatarUrl" :src="getAvatarUrl(agent.avatarUrl)" class="avatar-img" />
|
|
<img v-if="agent.avatarUrl" :src="getAvatarUrl(agent.avatarUrl)" class="avatar-img" />
|
|
|
<div v-else class="avatar" :class="agent.gender"></div>
|
|
<div v-else class="avatar" :class="agent.gender"></div>
|
|
|
<div class="gender-icon" :class="agent.gender">{{ agent.gender === 'female' ? '♀' : '♂' }}</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 class="agent-name">{{ agent.name }}</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -206,7 +198,6 @@ const basicExpanded = ref(true)
|
|
|
const otherExpanded = ref(false)
|
|
const otherExpanded = ref(false)
|
|
|
const currentPage = ref(0)
|
|
const currentPage = ref(0)
|
|
|
const chatContent = ref(null)
|
|
const chatContent = ref(null)
|
|
|
-const languageOptions = ref([])
|
|
|
|
|
|
|
|
|
|
// 语音识别
|
|
// 语音识别
|
|
|
const { isRecording, currentTranscription, tempTranscription, startRecording, stopRecording } = useVoiceRecognition()
|
|
const { isRecording, currentTranscription, tempTranscription, startRecording, stopRecording } = useVoiceRecognition()
|
|
@@ -291,6 +282,7 @@ watch(currentTranscription, async (newVal, oldVal) => {
|
|
|
|
|
|
|
|
// 发送到后端处理
|
|
// 发送到后端处理
|
|
|
try {
|
|
try {
|
|
|
|
|
+ const selectedAgentData = agents.value.find(a => a.id === selectedAgent.value)
|
|
|
const response = await fetch('http://localhost:8080/talk/message', {
|
|
const response = await fetch('http://localhost:8080/talk/message', {
|
|
|
method: 'POST',
|
|
method: 'POST',
|
|
|
headers: {
|
|
headers: {
|
|
@@ -298,7 +290,9 @@ watch(currentTranscription, async (newVal, oldVal) => {
|
|
|
},
|
|
},
|
|
|
body: JSON.stringify({
|
|
body: JSON.stringify({
|
|
|
message: newContent,
|
|
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)
|
|
clearInterval(waveformInterval)
|
|
|
waveformInterval = null
|
|
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 {
|
|
try {
|
|
|
|
|
+ const selectedAgentData = agents.value.find(a => a.id === selectedAgent.value)
|
|
|
const response = await fetch('http://localhost:8080/talk/message', {
|
|
const response = await fetch('http://localhost:8080/talk/message', {
|
|
|
method: 'POST',
|
|
method: 'POST',
|
|
|
headers: {
|
|
headers: {
|
|
@@ -417,7 +431,9 @@ const sendTextMessage = async () => {
|
|
|
},
|
|
},
|
|
|
body: JSON.stringify({
|
|
body: JSON.stringify({
|
|
|
message: content,
|
|
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 agents = ref([])
|
|
|
|
|
+const ttsVcnList = ref([])
|
|
|
|
|
|
|
|
const config = ref({
|
|
const config = ref({
|
|
|
- language: 'zh',
|
|
|
|
|
bgSoundEnabled: false,
|
|
bgSoundEnabled: false,
|
|
|
speed: 50,
|
|
speed: 50,
|
|
|
pitch: 50,
|
|
pitch: 50,
|
|
@@ -453,6 +469,17 @@ const config = ref({
|
|
|
|
|
|
|
|
const selectedAgent = ref(null)
|
|
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 () => {
|
|
const fetchAgents = async () => {
|
|
|
try {
|
|
try {
|
|
@@ -470,7 +497,7 @@ const fetchAgents = async () => {
|
|
|
ttsPitch: agent.ttsPitch,
|
|
ttsPitch: agent.ttsPitch,
|
|
|
ttsVolume: agent.ttsVolume,
|
|
ttsVolume: agent.ttsVolume,
|
|
|
ttsBgs: agent.ttsBgs,
|
|
ttsBgs: agent.ttsBgs,
|
|
|
- language: agent.language
|
|
|
|
|
|
|
+ status: agent.status
|
|
|
}))
|
|
}))
|
|
|
if (agents.value.length > 0) {
|
|
if (agents.value.length > 0) {
|
|
|
selectedAgent.value = agents.value[0].id
|
|
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(() => {
|
|
onMounted(() => {
|
|
|
- fetchLanguageOptions()
|
|
|
|
|
fetchAgents()
|
|
fetchAgents()
|
|
|
|
|
+ fetchTtsVcnList()
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// 获取头像完整URL
|
|
// 获取头像完整URL
|
|
@@ -531,7 +546,7 @@ const startChat = async () => {
|
|
|
ttsPitch: config.value.pitch,
|
|
ttsPitch: config.value.pitch,
|
|
|
ttsVolume: config.value.volume,
|
|
ttsVolume: config.value.volume,
|
|
|
ttsBgs: config.value.bgSoundEnabled ? 1 : 0,
|
|
ttsBgs: config.value.bgSoundEnabled ? 1 : 0,
|
|
|
- language: config.value.language
|
|
|
|
|
|
|
+ status: '2' // 设置状态为对话中
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
|
|
|
|
@@ -973,6 +988,33 @@ const handleWheel = (e) => {
|
|
|
background: #3b82f6;
|
|
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 {
|
|
.agent-name {
|
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
|
color: #1f2937;
|
|
color: #1f2937;
|