3 Angajamente d9fcfe825c ... d3a8daea5f

Autor SHA1 Permisiunea de a trimite mesaje. Dacă este dezactivată, utilizatorul nu va putea trimite nici un fel de mesaj Data
  zhujing d3a8daea5f Merge remote-tracking branch 'origin/master' 2 zile în urmă
  zhujing 04d2d349fa ai分析+换行显示 2 zile în urmă
  zhujing 9418607d89 ai分析+换行显示 2 zile în urmă

+ 3 - 1
ui/smarttrade-platform/src/api/customer/index.js

@@ -2,4 +2,6 @@ import { get, post, put, remove, upload } from '@/utils/request'
 
 export const getCustomerList = (data = {}) => post('/router/rest/customerTrade/list', data)
 
-export const getCustomerDetail = (params = {}) => get('/router/rest/customerTrade/getById', params)
+export const getCustomerDetail = (params = {}) => get('/router/rest/customerTrade/getById', params)
+
+export const streaming = (data = {}) => post('/router/rest/chat/streaming', data)

+ 55 - 16
ui/smarttrade-platform/src/views/CustomersView.vue

@@ -194,14 +194,17 @@
 
           <!-- AI Insights -->
           <div class="detail-section" >
-            <h4><i class="fas fa-robot"></i> AI 洞察</h4>
-            <div class="ai-insight-cards" v-if="selectedCustomer.customerAnalysisResult?.reasonSummary">
+            <h4>
+              <div><i class="fas fa-robot"></i> AI 洞察</div>
+              <div><button class="btn btn-primary" @click="aiStreaming(selectedCustomer.id)" style="margin-left: 10px;padding: 4px 8px;border-radius: 4px;" :disabled="aiContentLoading"><i class="fas fa-sync" :class="{'icon-spin': aiContentLoading}" style="color: #fff;"></i> AI分析</button></div> 
+            </h4>
+            <div class="ai-insight-cards" v-if="formattedText">
               <div class="ai-insight-card">
                 <!-- <div class="insight-icon" :class="insight.level">
                   <i :class="insight.icon"></i>
                 </div> -->
                 <div class="insight-content">
-                  <div class="insight-title">{{ selectedCustomer.customerAnalysisResult?.reasonSummary }}</div>
+                  <div class="insight-title">{{ formattedText }}</div>
                   <!-- <div class="insight-desc">{{ insight.description }}</div> -->
                 </div>
               </div>
@@ -261,7 +264,7 @@
 
 <script setup>
 import { ref, computed } from 'vue'
-import { getCustomerList,getCustomerDetail } from '../api/customer'
+import { getCustomerList,getCustomerDetail,streaming } from '../api/customer'
 import {region} from '@/utils/region';
 // 引入添加客户组件
 import AddCustomerModal from '../components/addCustomer.vue'
@@ -277,6 +280,8 @@ const showToast = ref(false)
 const toastMessage = ref('')
 const toastType = ref('success')
 const dataLoading = ref(false)
+const aiContentLoading = ref(false)
+const formattedText = ref('')
 
 const customerStats = ref({
   total: 0,
@@ -327,6 +332,43 @@ const getRegion = (value) => {
     getCustomer()
 }
 
+const showCustomerDetail = (customer) => {
+  getCustomerDetail({id:customer.id}).then(res => {
+    if(res.success){
+      selectedCustomer.value = res.result
+      showDetailModal.value = true
+      if(selectedCustomer.value.customerAnalysisResult){
+        formattedText.value = selectedCustomer.value.customerAnalysisResult.reasonSummary.replace(/(?=【(沟通意见|注意事项)】)/g, '\n')
+      }
+    }else{
+      ElMessage.warning(res.message)
+    }
+  })
+}
+
+const aiStreaming= (id) =>{
+  let params = {
+    appId: "app-rQrSHhudWbi5LVRkIX4tfVrg",
+    inputs: {"analysis_batch_no":"1","customer_id":+id},
+    query: "1",
+    response_mode: "streaming",
+    user: "1",
+    files:[]
+  }
+  if(aiContentLoading.value) return
+  aiContentLoading.value = true
+  streaming(params).then(res => {
+    aiContentLoading.value = false
+    ElMessage.warning('AI分析时间大概为2-4分钟,请稍后查看')
+    if(res.success){
+      aiContentLoading.value = true
+    }
+    // else{
+    //   return ElMessage.error('请求超时,请稍后再试')
+    // }
+  })
+}
+
 const goOtherProject = (data) => {
   console.log(data)
   const baseUrl = 'https://sales.test.storlead.com/customer/followPanel' // 销售管理系统
@@ -450,17 +492,6 @@ const getStatusLabel = (status) => ({
   silent: '沉默'
 }[status] || status)
 
-const showCustomerDetail = (customer) => {
-  getCustomerDetail({id:customer.id}).then(res => {
-    console.log(res)
-    if(res.success){
-      selectedCustomer.value = res.result
-      showDetailModal.value = true
-    }else{
-      ElMessage.warning(res.message)
-    }
-  })
-}
 
 const sendEmail = (customer) => {
   showToastMessage(`正在发送邮件给 ${customer.contact}...`, 'success')
@@ -619,7 +650,7 @@ const handleAddCustomer = (customerData) => {
 .insight-icon { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 14px; }
 .insight-icon.high { background: rgba(16, 185, 129, 0.2); color: var(--success); }
 .insight-icon.medium { background: rgba(245, 158, 11, 0.2); color: var(--warning); }
-.insight-title { font-size: 13px;  margin-bottom: 4px; }
+.insight-title { font-size: 13px;  margin-bottom: 4px;white-space: pre-line; }
 .insight-desc { font-size: 11px; color: var(--text-secondary); line-height: 1.5; }
 .timeline { display: flex; flex-direction: column; gap: 12px; position: relative; padding-left: 24px; }
 .timeline::before { content: ''; position: absolute; left: 6px; top: 0; bottom: 0; width: 2px; background: var(--border); }
@@ -648,4 +679,12 @@ const handleAddCustomer = (customerData) => {
 .toast.success i { color: var(--success); }
 .toast-enter-active, .toast-leave-active { transition: all 0.3s ease; }
 .toast-enter-from, .toast-leave-to { opacity: 0; transform: translateY(20px); }
+
+.icon-spin {
+  animation: spin 1s linear infinite !important;
+}
+@keyframes spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
 </style>

+ 7 - 1
ui/smarttrade-platform/src/views/KnowledgeView.vue

@@ -414,6 +414,12 @@
         </div>
         <div class="modal-body">
           <div class="form-group">
+            <div style="display: flex;align-items: center;margin-bottom: 6px;justify-content: space-between;">
+              <label class="form-label">内容 <span class="required">*</span></label><button class="btn btn-primary" @click="aiOptimize('content')" style="margin-left: 10px;padding: 4px 8px;border-radius: 4px;" :disabled="aiContentLoading"><i class="fas fa-sync" :class="{'icon-spin': aiContentLoading}"></i> AI优化</button>
+            </div>
+            <textarea class="form-textarea" v-model="newKnowledge.content" rows="4" placeholder="输入详细内容" :disabled="aiContentLoading"></textarea>
+          </div>
+          <!-- <div class="form-group">
             <div style="display: flex;align-items: center;margin-bottom: 6px;justify-content: space-between;">
               <label class="form-label">问题/关键词 <span class="required">*</span></label><button class="btn btn-primary" @click="aiOptimize('content')" style="margin-left: 10px;padding: 4px 8px;border-radius: 4px;" :disabled="aiContentLoading"><i class="fas fa-sync" :class="{'icon-spin': aiContentLoading}"></i> AI优化</button>
             </div>
@@ -424,7 +430,7 @@
               <label class="form-label">答案/内容 <span class="required">*</span></label><button class="btn btn-primary" @click="aiOptimize('answer')" style="margin-left: 10px;padding: 4px 8px;border-radius: 4px;" :disabled="aiAnswerLoading"><i class="fas fa-sync" :class="{'icon-spin': aiAnswerLoading}"></i> AI优化</button>
             </div>
             <textarea class="form-textarea" v-model="newKnowledge.answer" rows="4" placeholder="输入详细答案..." :disabled="aiAnswerLoading"></textarea>
-          </div>
+          </div> -->
           <div class="form-group">
             <label class="form-label">知识分类 <span class="required">*</span></label>
             <select class="form-select" v-model="newKnowledge.dataset_id" @change='getDocument' :disabled='chunkType=="edit"'>