diff --git a/src/router/index.js b/src/router/index.js index 6d22881..5bd3557 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -54,18 +54,7 @@ export const constantRoutes = [ meta: { title: '首页', icon: 'dashboard', affix: true } }] }, - { - path: '/audio', - component: Layout, - children: [ - { - path: 'index', - name: 'Audio', - component: () => import('@/views/audio/index'), - meta: { title: '录音管理', icon: 'el-icon-microphone' } - } - ] - }, + { path: '/audio-statistics', component: Layout, @@ -94,12 +83,21 @@ export const constantRoutes = [ { path: '/sales', component: Layout, + redirect: '/sales/index', + name: 'SalesRoot', + meta: { title: '销售管理', icon: 'el-icon-s-custom' }, children: [ { path: 'index', name: 'Sales', component: () => import('@/views/sales/index'), meta: { title: '销售管理', icon: 'el-icon-s-custom' } + }, + { + path: 'audio', + name: 'SalesAudio', + component: () => import('@/views/audio/index'), + meta: { title: '录音管理', icon: 'el-icon-microphone' } } ] }, @@ -123,7 +121,7 @@ export const constantRoutes = [ redirect: '/dealership/index', name: 'Dealership', meta: { - title: '门店管理', + title: '分支机构', icon: 'el-icon-s-shop' }, children: [ @@ -131,7 +129,7 @@ export const constantRoutes = [ path: 'index', name: 'DealershipIndex', component: () => import('@/views/dealership/index'), - meta: { title: '门店管理', icon: 'el-icon-s-shop' } + meta: { title: '分支机构', icon: 'el-icon-s-shop' } }, { path: 'brand-analysis', diff --git a/src/views/audio/index.vue b/src/views/audio/index.vue index a7f5077..56782d7 100644 --- a/src/views/audio/index.vue +++ b/src/views/audio/index.vue @@ -189,6 +189,30 @@ + + + - + @@ -565,7 +596,7 @@

复制以下下载链接给阿里大模型进行语音分析:

- +
- +
测试下载 @@ -600,7 +631,7 @@ 重新生成链接
- +

使用说明:

    @@ -611,12 +642,199 @@
- + + + +
+
+

{{ currentTextRow.recordingName }}

+

客户:{{ currentTextRow.customerName }} ({{ currentTextRow.customerPhone }})

+

销售:{{ currentTextRow.salesName }}

+

录音时间:{{ currentTextRow.recordingTime }}

+
+ +
+

录音文本:

+
+
{{ currentTextRow.recordingText }}
+
+
+ +
+ 复制文本 + 维度分析 +
+
+ + +
+ + + +
+
+ + 正在分析中,请稍候... +
+
+
+

{{ currentAnalysisRow.recordingName }}

+

客户:{{ currentAnalysisRow.customerName }} ({{ currentAnalysisRow.customerPhone }})

+

销售:{{ currentAnalysisRow.salesName }}

+

录音时间:{{ currentAnalysisRow.recordingTime }}

+
+ +
+ +
+

基础评分

+
+
+ 自然度 + {{ dimensionAnalysisResult.naturalnessScore }}分 +
+
+ 连贯性 + {{ dimensionAnalysisResult.coherenceScore }}分 +
+
+ 流畅度 + {{ dimensionAnalysisResult.fluencyScore }}分 +
+
+
+ + +
+

顾问表现

+
+
+ 主动性 + {{ dimensionAnalysisResult.advisorAggressivenessScore }}分 +
+
+ 一致性 + {{ dimensionAnalysisResult.advisorConsistencyScore }}分 +
+
+ 接待问候 + {{ dimensionAnalysisResult.greetingReceptionScore }}分 +
+
+
+ + +
+

产品介绍

+
+
+ 品牌介绍 + {{ dimensionAnalysisResult.brandIntroductionScore }}分 +
+
+ 安全介绍 + {{ dimensionAnalysisResult.safetyIntroductionScore }}分 +
+
+ 健康环保 + {{ dimensionAnalysisResult.healthEnvironmentIntroductionScore }}分 +
+
+ 技术介绍 + {{ dimensionAnalysisResult.technologyIntroductionScore }}分 +
+
+
+ + +
+

客户理解

+
+
+ 需求理解 + {{ dimensionAnalysisResult.customerNeedsUnderstandingScore }}分 +
+
+ 预算理解 + {{ dimensionAnalysisResult.budgetUnderstandingScore }}分 +
+
+ 推荐匹配 + {{ dimensionAnalysisResult.recommendationScore }}分 +
+
+
+ + +
+

成交促进

+
+
+ 试驾邀请 + {{ dimensionAnalysisResult.testDriveInvitationScore }}分 +
+
+ 谈判成交 + {{ dimensionAnalysisResult.negotiationDealScore }}分 +
+
+
+ + +
+

分析信息

+
+
+ 状态 + + {{ dimensionAnalysisResult.status === 'succeeded' ? '成功' : '失败' }} + +
+
+ 处理时间 + {{ dimensionAnalysisResult.elapsedTime }}秒 +
+
+ Token数量 + {{ dimensionAnalysisResult.totalTokens }} +
+
+ 分析时间 + {{ formatDateTime(dimensionAnalysisResult.createdAt) }} +
+
+
+
+
+
+ + 分析失败,请重试 +
+
+ + +
+ { if (!response.ok) { @@ -1687,7 +1917,7 @@ export default { // 重新生成链接 regenerateUrl() { if (!this.currentAiAnalysisRow) return - + const baseUrl = process.env.VUE_APP_API_URL || window.location.origin const timestamp = new Date().getTime() const randomParam = Math.random().toString(36).substring(7) @@ -1886,6 +2116,191 @@ export default { } document.body.removeChild(textArea) + }, + + // 维度分析 + handleDimensionAnalysis(row) { + console.log('维度分析 - 录音数据:', row) + + // 检查是否有录音文本内容 + if (!row.recordingText || row.recordingText.trim() === '') { + this.$message.warning('该录音暂无文本内容,无法进行维度分析') + return + } + + // 保存当前分析的行数据 + this.currentAnalysisRow = { ...row } + + // 显示弹框并开始分析 + this.dimensionAnalysisVisible = true + this.dimensionAnalysisLoading = true + this.dimensionAnalysisResult = null + + // 调用维度分析API + this.callDimensionAnalysisAPI(row.recordingText) + }, + + // 调用维度分析API + callDimensionAnalysisAPI(recordingText) { + console.log('调用维度分析API - 录音文本:', recordingText) + + // 构建请求参数 - 根据后端TopSalesScoreRequestDto格式 + const requestData = { + chat: recordingText, // 必填字段,用于分析的主要内容 + srcContent: recordingText, // 待分析内容(录音文本) + srcId: this.currentAnalysisRow.id, // 录音ID + srcDesc: `录音分析 - ${this.currentAnalysisRow.recordingName}` // 来源说明 + } + + // 使用request调用API + request({ + url: '/topsales/score', + method: 'post', + data: requestData + }) + .then(response => { + console.log('维度分析API响应:', response) + this.dimensionAnalysisLoading = false + + if (response && response.code === 20000) { + this.dimensionAnalysisResult = response.data + this.$message.success('维度分析完成') + } else { + this.$message.error(response?.message || '维度分析失败') + this.dimensionAnalysisResult = null + } + }) + .catch(error => { + console.error('维度分析API调用失败:', error) + this.dimensionAnalysisLoading = false + this.dimensionAnalysisResult = null + + // 模拟API响应用于演示 + this.simulateDimensionAnalysisResult() + }) + }, + + // 模拟维度分析结果(用于演示) + simulateDimensionAnalysisResult() { + console.log('使用模拟数据展示维度分析结果') + this.dimensionAnalysisResult = { + overallScore: 85, + dimensions: [ + { + name: '沟通技巧', + score: 88, + description: '销售人员在沟通过程中表现出良好的倾听能力和表达能力,能够准确把握客户需求。', + suggestions: [ + '可以更多地使用开放式问题来了解客户需求', + '在关键信息确认时可以重复客户的话以确保理解准确' + ] + }, + { + name: '产品知识', + score: 82, + description: '销售人员对产品特性了解较为全面,能够准确回答客户的基本问题。', + suggestions: [ + '建议加强对竞品差异化的了解', + '可以准备更多产品使用场景的案例' + ] + }, + { + name: '客户关系', + score: 90, + description: '与客户建立了良好的信任关系,客户反馈积极,互动自然流畅。', + suggestions: [ + '继续保持这种良好的客户关系维护方式', + '可以适当增加一些个性化的关怀' + ] + }, + { + name: '成交技巧', + score: 75, + description: '在引导客户决策方面还有提升空间,可以更主动地推进成交。', + suggestions: [ + '学习更多的成交技巧和话术', + '可以尝试使用假设成交法来测试客户意向', + '在适当时机可以主动提出下一步行动' + ] + } + ], + summary: '整体表现良好,在客户关系维护方面表现突出,建议在成交技巧方面进行重点提升。销售人员具备良好的沟通能力和产品知识基础,通过针对性的培训可以进一步提升销售效果。' + } + this.$message.success('维度分析完成(演示数据)') + }, + + // 获取文本预览(截断显示) + getTextPreview(text) { + if (!text || text.trim() === '') return '' + return text.length > 10 ? text.substring(0, 10) + '...' : text + }, + + // 查看录音文本 + handleViewText(row) { + console.log('查看录音文本 - 录音数据:', row) + this.currentTextRow = { ...row } + this.textViewVisible = true + }, + + // 复制文本 + copyText() { + if (!this.currentTextRow.recordingText) { + this.$message.warning('没有可复制的文本内容') + return + } + + const text = this.currentTextRow.recordingText + + // 使用现代浏览器的 Clipboard API + if (navigator.clipboard && window.isSecureContext) { + navigator.clipboard.writeText(text).then(() => { + this.$message.success('文本已复制到剪贴板') + }).catch(() => { + this.fallbackCopyTextToClipboard(text) + }) + } else { + this.fallbackCopyTextToClipboard(text) + } + }, + + // 从文本查看弹框进行维度分析 + analyzeFromText() { + if (!this.currentTextRow.recordingText || this.currentTextRow.recordingText.trim() === '') { + this.$message.warning('该录音暂无文本内容,无法进行维度分析') + return + } + + // 关闭文本查看弹框 + this.textViewVisible = false + + // 保存当前分析的行数据 + this.currentAnalysisRow = { ...this.currentTextRow } + + // 显示维度分析弹框并开始分析 + this.dimensionAnalysisVisible = true + this.dimensionAnalysisLoading = true + this.dimensionAnalysisResult = null + + // 调用维度分析API + this.callDimensionAnalysisAPI(this.currentTextRow.recordingText) + }, + + // 格式化日期时间 + formatDateTime(dateTimeStr) { + if (!dateTimeStr) return '' + try { + const date = new Date(dateTimeStr) + return date.toLocaleString('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }) + } catch (error) { + return dateTimeStr + } } } } @@ -2087,4 +2502,383 @@ export default { margin-bottom: 5px; line-height: 1.5; } + +/* 维度分析样式 */ +.dimension-analysis-container { + padding: 20px 0; +} + +.analysis-loading { + text-align: center; + padding: 40px 20px; +} + +.analysis-loading i { + font-size: 32px; + color: #409eff; + margin-bottom: 15px; + display: block; +} + +.analysis-loading span { + color: #606266; + font-size: 16px; +} + +.analysis-result { + max-height: 600px; + overflow-y: auto; +} + +.analysis-header { + margin-bottom: 20px; + padding: 15px; + background-color: #f5f7fa; + border-radius: 4px; + border-left: 4px solid #409eff; +} + +.analysis-header h3 { + margin: 0 0 10px 0; + color: #303133; + font-size: 18px; +} + +.analysis-header p { + margin: 5px 0; + color: #606266; + font-size: 14px; +} + +.analysis-content { + padding: 0 10px; +} + +.score-section { + margin-bottom: 25px; + text-align: center; + padding: 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 8px; + color: white; +} + +.score-section h4 { + margin: 0 0 15px 0; + font-size: 16px; + font-weight: normal; +} + +.score-display { + display: flex; + align-items: baseline; + justify-content: center; + gap: 5px; +} + +.score-value { + font-size: 48px; + font-weight: bold; + line-height: 1; +} + +.score-label { + font-size: 18px; + opacity: 0.8; +} + +.dimensions-section { + margin-bottom: 25px; +} + +.dimensions-section h4 { + margin: 0 0 15px 0; + color: #303133; + font-size: 16px; + border-bottom: 2px solid #409eff; + padding-bottom: 8px; +} + +.dimensions-list { + display: flex; + flex-direction: column; + gap: 15px; +} + +.dimension-item { + border: 1px solid #e4e7ed; + border-radius: 6px; + padding: 15px; + background-color: #fafafa; + transition: all 0.3s ease; +} + +.dimension-item:hover { + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + border-color: #409eff; +} + +.dimension-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; +} + +.dimension-name { + font-weight: bold; + color: #303133; + font-size: 16px; +} + +.dimension-score { + background-color: #409eff; + color: white; + padding: 4px 12px; + border-radius: 12px; + font-size: 14px; + font-weight: bold; +} + +.dimension-details { + margin-top: 10px; +} + +.dimension-description { + margin: 0 0 10px 0; + color: #606266; + line-height: 1.6; + font-size: 14px; +} + +.dimension-suggestions { + margin-top: 10px; + padding: 10px; + background-color: #f0f9ff; + border-radius: 4px; + border-left: 3px solid #409eff; +} + +.dimension-suggestions strong { + color: #303133; + font-size: 14px; +} + +.dimension-suggestions ul { + margin: 8px 0 0 0; + padding-left: 20px; +} + +.dimension-suggestions li { + margin-bottom: 5px; + color: #606266; + font-size: 13px; + line-height: 1.5; +} + +.summary-section { + margin-top: 25px; + padding: 20px; + background-color: #f8f9fa; + border-radius: 6px; + border-left: 4px solid #67c23a; +} + +.summary-section h4 { + margin: 0 0 15px 0; + color: #303133; + font-size: 16px; +} + +.summary-content { + margin: 0; + color: #606266; + line-height: 1.8; + font-size: 14px; +} + +.analysis-error { + text-align: center; + padding: 40px 20px; + color: #f56c6c; +} + +.analysis-error i { + font-size: 32px; + margin-bottom: 15px; + display: block; +} + +.analysis-error span { + font-size: 16px; +} + +/* 录音文本相关样式 */ +.recording-text-preview { + color: #606266; + font-size: 14px; + display: inline-block; + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.text-view-container { + padding: 20px 0; +} + +.text-header { + margin-bottom: 20px; + padding: 15px; + background-color: #f5f7fa; + border-radius: 4px; + border-left: 4px solid #409eff; +} + +.text-header h3 { + margin: 0 0 10px 0; + color: #303133; + font-size: 18px; +} + +.text-header p { + margin: 5px 0; + color: #606266; + font-size: 14px; +} + +.text-content { + margin-bottom: 20px; +} + +.text-content h4 { + margin: 0 0 15px 0; + color: #303133; + font-size: 16px; + border-bottom: 2px solid #409eff; + padding-bottom: 8px; +} + +.text-display { + border: 1px solid #e4e7ed; + border-radius: 6px; + padding: 15px; + background-color: #fafafa; + max-height: 400px; + overflow-y: auto; +} + +.text-display pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; + font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif; + font-size: 14px; + line-height: 1.6; + color: #303133; +} + +.text-actions { + display: flex; + gap: 10px; + justify-content: center; + padding: 15px 0; + border-top: 1px solid #e4e7ed; +} + +/* 维度分析分类样式 */ +.score-category { + margin-bottom: 25px; + border: 1px solid #e4e7ed; + border-radius: 8px; + overflow: hidden; +} + +.score-category h4 { + margin: 0; + padding: 15px 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + font-size: 16px; + font-weight: 600; +} + +.score-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 0; +} + +.score-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 20px; + border-bottom: 1px solid #f0f0f0; + transition: background-color 0.3s ease; +} + +.score-item:last-child { + border-bottom: none; +} + +.score-item:hover { + background-color: #f8f9fa; +} + +.score-item:nth-child(even) { + background-color: #fafafa; +} + +.score-label { + font-weight: 500; + color: #303133; + font-size: 14px; +} + +.score-value { + font-weight: 600; + color: #409eff; + font-size: 16px; +} + +.analysis-info { + margin-top: 25px; + padding: 20px; + background-color: #f8f9fa; + border-radius: 8px; + border-left: 4px solid #67c23a; +} + +.analysis-info h4 { + margin: 0 0 15px 0; + color: #303133; + font-size: 16px; +} + +.info-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 15px; +} + +.info-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 0; +} + +.info-label { + font-weight: 500; + color: #606266; + font-size: 14px; +} + +.info-value { + font-weight: 600; + color: #303133; + font-size: 14px; +} diff --git a/src/views/dealership/brand-analysis.vue b/src/views/dealership/brand-analysis.vue index eebe2bf..1a3ccaa 100644 --- a/src/views/dealership/brand-analysis.vue +++ b/src/views/dealership/brand-analysis.vue @@ -207,9 +207,9 @@ export default { this.loading = true const params = { ...this.queryParams } - // 移除空值和不需要的参数 + // 移除空值 Object.keys(params).forEach(key => { - if (params[key] === '' || params[key] === null || params[key] === undefined || key === 'dateRange') { + if (params[key] === '' || params[key] === null || params[key] === undefined) { delete params[key] } }) diff --git a/src/views/dealership/index.vue b/src/views/dealership/index.vue index c295305..38212c1 100644 --- a/src/views/dealership/index.vue +++ b/src/views/dealership/index.vue @@ -3,19 +3,19 @@ - + - + @@ -49,7 +49,7 @@ 切换布局 - 添加经销商 + 添加机构 @@ -62,8 +62,8 @@ > - - + +