diff --git a/src/api/audio-statistics.js b/src/api/audio-statistics.js
index 4d63ed5..82d06c7 100644
--- a/src/api/audio-statistics.js
+++ b/src/api/audio-statistics.js
@@ -55,8 +55,11 @@ export function getStatisticsOverview() {
})
}
-
-
-
-
-
+// TTS请求日志相关接口
+export function getTtsRequestLogs(params) {
+ return request({
+ url: '/tts/log/list',
+ method: 'get',
+ params
+ })
+}
diff --git a/src/api/sales.js b/src/api/sales.js
index 16f21e2..db7c184 100644
--- a/src/api/sales.js
+++ b/src/api/sales.js
@@ -93,3 +93,41 @@ export function getTopSalesPage(params) {
}
})
}
+
+// 获取咨询场景列表(智能捡漏)
+export function getConsultingScenarioList(params) {
+ return request({
+ url: '/consultingScenario/list',
+ method: 'get',
+ params: {
+ current: params.current || 1,
+ size: params.size || 10,
+ mainCategory: params.mainCategory,
+ subCategory: params.subCategory,
+ confidence: params.confidence,
+ priority: params.priority
+ }
+ })
+}
+
+// AI分析咨询场景
+export function processConsultingScenario(data) {
+ return request({
+ url: '/consultingScenario/process',
+ method: 'post',
+ timeout: 80000, // 设置超时时间为60秒(1分钟)
+ data: {
+ chat: data.chat,
+ businessType: data.businessType || 'Channel_4in1',
+ sourceCorpusId: data.sourceCorpusId || '2180459',
+ sourceCorpusTime: data.sourceCorpusTime || new Date().toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ }).replace(/\//g, '-')
+ }
+ })
+}
diff --git a/src/router/index.js b/src/router/index.js
index 7bd782c..35b4bc8 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -55,31 +55,6 @@ export const constantRoutes = [
}]
},
- {
- path: '/audio-statistics',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'AudioStatistics',
- component: () => import('@/views/audio-statistics/index'),
- meta: { title: '录音统计', icon: 'el-icon-data-analysis' }
- }
- ]
- },
- {
- path: '/video',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'Video',
- component: () => import('@/views/video/index'),
- meta: { title: '视频管理', icon: 'el-icon-video-camera' }
- }
- ]
- },
-
{
path: '/sales',
component: Layout,
@@ -104,6 +79,12 @@ export const constantRoutes = [
name: 'DimensionAnalysis',
component: () => import('@/views/sales/dimension-analysis'),
meta: { title: '维度分析', icon: 'el-icon-data-analysis' }
+ },
+ {
+ path: 'intelligent-pickup',
+ name: 'IntelligentPickup',
+ component: () => import('@/views/sales/intelligent-pickup'),
+ meta: { title: '智能捡漏', icon: 'el-icon-magic-stick' }
}
]
},
@@ -215,71 +196,36 @@ export const constantRoutes = [
},
{
- path: '/nested',
+ path: '/audio-statistics',
component: Layout,
- redirect: '/nested/menu1',
- name: 'Nested',
- meta: {
- title: 'Nested',
- icon: 'nested'
- },
+ redirect: '/audio-statistics/index',
+ name: 'AudioStatisticsRoot',
+ meta: { title: '音频管理', icon: 'el-icon-data-analysis' },
children: [
{
- path: 'menu1',
- component: () => import('@/views/nested/menu1/index'), // Parent router-view
- name: 'Menu1',
- meta: { title: 'Menu1' },
- children: [
- {
- path: 'menu1-1',
- component: () => import('@/views/nested/menu1/menu1-1'),
- name: 'Menu1-1',
- meta: { title: 'Menu1-1' }
- },
- {
- path: 'menu1-2',
- component: () => import('@/views/nested/menu1/menu1-2'),
- name: 'Menu1-2',
- meta: { title: 'Menu1-2' },
- children: [
- {
- path: 'menu1-2-1',
- component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
- name: 'Menu1-2-1',
- meta: { title: 'Menu1-2-1' }
- },
- {
- path: 'menu1-2-2',
- component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
- name: 'Menu1-2-2',
- meta: { title: 'Menu1-2-2' }
- }
- ]
- },
- {
- path: 'menu1-3',
- component: () => import('@/views/nested/menu1/menu1-3'),
- name: 'Menu1-3',
- meta: { title: 'Menu1-3' }
- }
- ]
+ path: 'index',
+ name: 'AudioStatistics',
+ component: () => import('@/views/audio-statistics/index'),
+ meta: { title: '音频统计', icon: 'el-icon-data-analysis' }
},
{
- path: 'menu2',
- component: () => import('@/views/nested/menu2/index'),
- name: 'Menu2',
- meta: { title: 'menu2' }
+ path: 'audio-generation',
+ name: 'AudioGeneration',
+ component: () => import('@/views/audio-statistics/audio-generation'),
+ meta: { title: '音频生成', icon: 'el-icon-microphone' }
}
]
},
{
- path: 'external-link',
+ path: '/video',
component: Layout,
children: [
{
- path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
- meta: { title: 'External Link', icon: 'link' }
+ path: 'index',
+ name: 'Video',
+ component: () => import('@/views/video/index'),
+ meta: { title: '视频管理', icon: 'el-icon-video-camera' }
}
]
},
diff --git a/src/utils/request.js b/src/utils/request.js
index 5a4b4c7..248043b 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -39,11 +39,15 @@ service.interceptors.response.use(
// 前端期望格式: { code: 20000, data: {...}, message: "..." }
if (res.success === true) {
- // 后端成功响应,转换为前端期望格式
+ // 后端成功响应,转换为前端期望格式,保留分页信息
return {
code: 20000,
data: res.data,
- message: res.message || 'Success'
+ message: res.message || 'Success',
+ total: res.total,
+ current: res.current,
+ pages: res.pages,
+ size: res.size
}
} else if (res.success === false) {
// 后端失败响应
diff --git a/src/views/audio-statistics/audio-generation.vue b/src/views/audio-statistics/audio-generation.vue
new file mode 100644
index 0000000..8b9bbdf
--- /dev/null
+++ b/src/views/audio-statistics/audio-generation.vue
@@ -0,0 +1,381 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+
+
+
+ 重置
+
+
+
+
+
+
+
+
+
TTS请求日志列表
+
+
+
+ 刷新
+
+
+
+
+
+
+
+
+
+ {{ getStatusText(scope.row.status) }}
+
+
+
+
+
+
+
+
+ {{ scope.row.audioSizeBytes ? formatFileSize(scope.row.audioSizeBytes) : '-' }}
+
+
+
+
+ {{ scope.row.duration ? scope.row.duration.toFixed(2) : '-' }}
+
+
+
+
+
+ 播放
+
+ -
+
+
+
+
+
+
+
+ 详情
+
+
+ 重试
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ currentRow.id }}
+
+
+ {{ getStatusText(currentRow.status) }}
+
+
+ {{ currentRow.model }}
+ {{ currentRow.voice }}
+ {{ formatFileSize(currentRow.audioSizeBytes) }}
+ {{ currentRow.duration ? currentRow.duration.toFixed(2) + '秒' : '-' }}
+ {{ currentRow.processingTimeMs }}ms
+ {{ currentRow.createTime }}
+
+
+ {{ currentRow.inputText }}
+
+
+
+ {{ currentRow.errorMessage }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/sales/dimension-analysis.vue b/src/views/sales/dimension-analysis.vue
index 8a65142..e6956c9 100644
--- a/src/views/sales/dimension-analysis.vue
+++ b/src/views/sales/dimension-analysis.vue
@@ -228,116 +228,52 @@
title="TopSales评分详情"
:visible.sync="detailDialogVisible"
width="800px"
+ :close-on-click-modal="false"
@close="handleDetailDialogClose"
>
-
-
-
- {{ currentRecord.status }}
-
- {{ currentRecord.salespersonName || currentRecord.salesName || '-' }}
- {{ currentRecord.salespersonPhone || currentRecord.salesPhone || '-' }}
- {{ currentRecord.dealerName || currentRecord.dealershipName || '-' }}
- {{ currentRecord.dealerPhone || currentRecord.dealershipPhone || '-' }}
-
-
-
- {{ currentRecord.naturalnessScore || 0 }}分
-
-
-
-
- {{ currentRecord.coherenceScore || 0 }}分
-
-
-
-
- {{ currentRecord.fluencyScore || 0 }}分
-
-
+
+
-
-
-
- {{ currentRecord.advisorAggressivenessScore || 0 }}分
-
-
-
-
- {{ currentRecord.advisorConsistencyScore || 0 }}分
-
-
-
-
- {{ currentRecord.greetingReceptionScore || 0 }}分
-
-
+
+
基本信息
+
+
+ 总用时:
+ {{ currentRecord.elapsedTime }}秒
+
+
+ 综合评分:
+
+ {{ getOverallScore(currentRecord) }}
+
+
+
+
-
-
-
- {{ currentRecord.brandIntroductionScore || 0 }}分
-
-
-
-
- {{ currentRecord.safetyIntroductionScore || 0 }}分
-
-
-
-
- {{ currentRecord.healthEnvironmentIntroductionScore || 0 }}分
-
-
-
-
- {{ currentRecord.technologyIntroductionScore || 0 }}分
-
-
+
+
对话内容
+
+
+
+ {{ getSpeakerLabel(line) }}
+ {{ getSpeakerContent(line) }}
+
+
+
+
-
-
-
- {{ currentRecord.customerNeedsUnderstandingScore || 0 }}分
-
-
-
-
- {{ currentRecord.budgetUnderstandingScore || 0 }}分
-
-
-
-
- {{ currentRecord.recommendationScore || 0 }}分
-
-
-
-
-
-
- {{ currentRecord.testDriveInvitationScore || 0 }}分
-
-
-
-
- {{ currentRecord.negotiationDealScore || 0 }}分
-
-
-
{{ currentRecord.elapsedTime }}
-
{{ currentRecord.createdAt }}
-
-
-
-
+
@@ -686,6 +622,122 @@ export default {
// 详情对话框关闭
handleDetailDialogClose() {
this.currentRecord = null
+ },
+
+ // 复制内容
+ copyContent() {
+ if (!this.currentRecord || !this.currentRecord.srcContent) {
+ this.$message.warning('暂无内容可复制')
+ return
+ }
+
+ // 创建临时文本区域
+ const textArea = document.createElement('textarea')
+ textArea.value = this.currentRecord.srcContent
+ document.body.appendChild(textArea)
+ textArea.select()
+
+ try {
+ document.execCommand('copy')
+ this.$message.success('内容已复制到剪贴板')
+ } catch (err) {
+ this.$message.error('复制失败,请手动复制')
+ } finally {
+ document.body.removeChild(textArea)
+ }
+ },
+
+ // 获取格式化的文本行数组
+ getFormattedLines(text) {
+ if (!text || text.trim() === '') {
+ return [{ type: 'empty', content: '暂无对话内容' }]
+ }
+
+ // 先尝试按换行符分割
+ let lines = text.split('\n').filter(line => line.trim() !== '')
+
+ // 如果没有换行符,按说话人模式分割
+ if (lines.length === 1) {
+ const textContent = lines[0]
+ // 尝试识别说话人模式:销售:xxx 客户:xxx
+ const speakerPattern = /(销售|客户|顾问)[::]/g
+ const matches = []
+ let match
+ while ((match = speakerPattern.exec(textContent)) !== null) {
+ matches.push({
+ speaker: match[1],
+ index: match.index
+ })
+ }
+
+ if (matches.length > 0) {
+ lines = []
+ for (let i = 0; i < matches.length; i++) {
+ const currentMatch = matches[i]
+ const nextMatch = matches[i + 1]
+ const startIndex = currentMatch.index
+ const endIndex = nextMatch ? nextMatch.index : textContent.length
+ const content = textContent.substring(startIndex, endIndex).trim()
+ if (content) {
+ lines.push(content)
+ }
+ }
+ }
+ }
+
+ return lines.map(line => {
+ const trimmedLine = line.trim()
+ if (trimmedLine === '') {
+ return { type: 'empty', content: '' }
+ }
+
+ // 检查是否是说话人格式
+ if (trimmedLine.match(/^(销售|客户|顾问)[::]/)) {
+ const speakerMatch = trimmedLine.match(/^(销售|客户|顾问)[::](.*)/)
+ if (speakerMatch) {
+ return {
+ type: 'speaker',
+ speaker: speakerMatch[1],
+ content: speakerMatch[2].trim()
+ }
+ }
+ }
+
+ return {
+ type: 'text',
+ content: trimmedLine
+ }
+ })
+ },
+
+ // 获取行的CSS类
+ getLineClass(line) {
+ if (line.type === 'speaker') {
+ return `speaker ${line.speaker === '销售' || line.speaker === '顾问' ? 'sales' : 'customer'}`
+ }
+ if (line.type === 'empty') {
+ return 'no-text'
+ }
+ return 'text-line'
+ },
+
+ // 获取说话人标签
+ getSpeakerLabel(line) {
+ if (line.type === 'speaker') {
+ return line.speaker + ':'
+ }
+ return null
+ },
+
+ // 获取说话人内容
+ getSpeakerContent(line) {
+ if (line.type === 'speaker') {
+ return line.content || ''
+ }
+ if (line.type === 'empty') {
+ return line.content
+ }
+ return line.content || ''
}
}
}
@@ -724,4 +776,208 @@ export default {
.el-table .el-button--text:hover {
color: #409EFF;
}
+
+/* 详情弹窗样式 - 参考录音管理页面 */
+.detail-view-container {
+ padding: 20px 0;
+}
+
+.detail-header {
+ margin-bottom: 20px;
+ padding: 15px;
+ background-color: #f5f7fa;
+ border-radius: 4px;
+ border-left: 4px solid #409eff;
+}
+
+.detail-header h3 {
+ margin: 0 0 10px 0;
+ color: #303133;
+ font-size: 18px;
+}
+
+.detail-header p {
+ margin: 5px 0;
+ color: #606266;
+ font-size: 14px;
+}
+
+.basic-info {
+ margin-bottom: 20px;
+}
+
+.basic-info h4 {
+ margin: 0 0 15px 0;
+ color: #303133;
+ font-size: 16px;
+ border-bottom: 2px solid #409eff;
+ padding-bottom: 8px;
+}
+
+.info-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 12px;
+}
+
+.info-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 16px;
+ background-color: #f8f9fa;
+ border-radius: 6px;
+ border: 1px solid #e4e7ed;
+}
+
+.info-label {
+ font-weight: 500;
+ color: #606266;
+ margin-right: 8px;
+}
+
+.info-value {
+ font-weight: 600;
+ color: #303133;
+}
+
+.original-content {
+ margin-bottom: 20px;
+}
+
+.original-content h4 {
+ margin: 0 0 15px 0;
+ color: #303133;
+ font-size: 16px;
+ border-bottom: 2px solid #409eff;
+ padding-bottom: 8px;
+}
+
+.content-display {
+ border: 1px solid #e4e7ed;
+ border-radius: 8px;
+ padding: 20px;
+ background-color: #fff;
+ max-height: 500px;
+ overflow-y: auto;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.formatted-content {
+ line-height: 1.8;
+ font-size: 15px;
+ color: #333;
+}
+
+.formatted-content .speaker {
+ margin-bottom: 16px;
+ padding: 12px 16px;
+ border-radius: 8px;
+ border-left: 4px solid;
+ background-color: #f8f9fa;
+ transition: all 0.2s ease;
+}
+
+.formatted-content .speaker:hover {
+ transform: translateX(2px);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.formatted-content .speaker.sales {
+ background-color: #f0f9ff;
+ border-left-color: #409eff;
+}
+
+.formatted-content .speaker.customer {
+ background-color: #f0f9f0;
+ border-left-color: #67c23a;
+}
+
+.formatted-content .speaker.other {
+ background-color: #f5f5f5;
+ border-left-color: #909399;
+}
+
+.formatted-content .speaker-label {
+ font-weight: 600;
+ color: #333;
+ margin-right: 8px;
+ font-size: 14px;
+ display: inline-block;
+ min-width: 50px;
+}
+
+.formatted-content .speaker.sales .speaker-label {
+ color: #409eff;
+}
+
+.formatted-content .speaker.customer .speaker-label {
+ color: #67c23a;
+}
+
+.formatted-content .speaker-content {
+ color: #555;
+ line-height: 1.6;
+ word-wrap: break-word;
+}
+
+.formatted-content .text-line {
+ margin-bottom: 12px;
+ padding: 8px 12px;
+ color: #666;
+ background-color: #f8f9fa;
+ border-radius: 6px;
+ border-left: 3px solid #e4e7ed;
+}
+
+.formatted-content .no-text {
+ text-align: center;
+ color: #999;
+ font-style: italic;
+ padding: 40px 20px;
+ background-color: #f8f9fa;
+ border-radius: 8px;
+ border: 2px dashed #ddd;
+}
+
+.detail-actions {
+ text-align: center;
+ padding-top: 15px;
+ border-top: 1px solid #e4e7ed;
+}
+
+.detail-actions .el-button {
+ margin: 0 8px;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+ .info-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .info-item {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ .info-label {
+ margin-bottom: 4px;
+ }
+
+ .content-display {
+ padding: 15px;
+ max-height: 400px;
+ }
+
+ .formatted-content .speaker {
+ padding: 10px 12px;
+ margin-bottom: 12px;
+ }
+
+ .formatted-content .speaker-label {
+ display: block;
+ margin-bottom: 4px;
+ }
+}
diff --git a/src/views/sales/intelligent-pickup.vue b/src/views/sales/intelligent-pickup.vue
new file mode 100644
index 0000000..59eefdd
--- /dev/null
+++ b/src/views/sales/intelligent-pickup.vue
@@ -0,0 +1,725 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+ 刷新数据
+
+
+
+
+
+
+
+
+
+
+
{{ totalCount }}
+
总记录数
+
+
+
+
+
+
+
{{ highConfidenceCount }}
+
高置信度
+
+
+
+
+
+
+
{{ highPriorityCount }}
+
高优先级
+
+
+
+
+
+
+
{{ salesRelatedCount }}
+
购车相关
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.mainCategory }}
+
+
+
+
+
+
+
+ {{ scope.row.subCategory }}
+
+
+
+
+
+
+
+ {{ scope.row.confidence }}
+
+
+
+
+
+
+
+ {{ scope.row.priority }}
+
+
+
+
+
+
+
+
+
+ {{ scope.row.involvedVehicleModels }}
+
+ -
+
+
+
+
+
+ {{ formatDate(scope.row.createdAt) }}
+
+
+
+
+
+
+ 详情
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ currentRecord.mainCategory }}
+
+
+
+
+
+
+ {{ currentRecord.subCategory }}
+
+
+
+
+
+
+
+
+
+ {{ currentRecord.confidence }}
+
+
+
+
+
+
+
+ {{ currentRecord.priority }}
+
+
+
+
+
+
+
+
{{ currentRecord.userDemand }}
+
+
+
+
+
{{ currentRecord.consultingContent }}
+
+
+
+
+
+
+ {{ currentRecord.involvedVehicleModels }}
+
+ 无
+
+
+
+
+
+
{{ currentRecord.knowledgeGap }}
+
+
+
+
+
{{ currentRecord.remarks }}
+
+
+
+
+
+
+ {{ formatDate(currentRecord.createdAt) }}
+
+
+
+
+
+ {{ formatDate(currentRecord.updatedAt) }}
+
+
+
+
+
+
+
+
+
+
+
+
+