Bläddra i källkod

修改营销活动

Fan 4 veckor sedan
förälder
incheckning
367447d7a9

+ 1 - 0
ui/smarttrade-platform/src/assets/styles/marketing.css

@@ -328,6 +328,7 @@
 .status-badge.info { background: rgba(10, 10, 10, 0.2); color: white; }
 .status-badge.active { background: rgba(16, 185, 129, 0.2); color: var(--success); }
 .status-badge.paused { background: rgba(245, 158, 11, 0.2); color: var(--warning); }
+.status-badge.finished { background: rgba(99, 102, 241, 0.2); color: var(--primary); }
 .card-title { font-size: 15px; font-weight: 600; margin-bottom: 6px; }
 .card-desc { font-size: 12px; color: var(--text-secondary); margin-bottom: 12px; }
 .card-channels { display: flex; gap: 6px; margin-bottom: 12px; }

+ 55 - 6
ui/smarttrade-platform/src/components/marketing/aiGenerator.vue

@@ -82,6 +82,10 @@
                     <span>${email}$</span>
                 </div>
               </div>
+              <div class="subject-div">
+                <span>邮件主题:</span>
+                <el-input v-model="emailSubject" style="flex: 1" />
+              </div>
               <div class="msg-item">
                     <div class="msg-item-left">
                         <ckeditor
@@ -176,6 +180,7 @@
 
     const marketingData = ref()
     const typeData = ref([])
+    const emailSubject = ref('')
     const open = (data) => {
         marketingData.value = data
         getSopById(data.sopId).then(res => {
@@ -190,6 +195,7 @@
             extra: ''
         }
         emailContent.value = ''
+        emailSubject.value = ''
         showAIModal.value = true
     }
 
@@ -298,6 +304,9 @@
             // 3. 循环读取流式数据
             let buffer = ''; // 缓冲区
             let doneData = '<p>'
+            let subject = ''
+            let waitingForSubject = false
+            let readingSubject = false
             while (true) {
                 const { done, value } = await reader.read();
                 if (done) break;
@@ -315,16 +324,47 @@
                     if (!trimmedLine || trimmedLine.startsWith(':')) continue;
 
                     if (trimmedLine === 'data: [DONE]') {
-                    console.log('流传输结束');
-                    doneData += '</p>'
-                    return;
+                        console.log('流传输结束');
+                        doneData += '</p>'
+                        return;
                     }
 
                     if (trimmedLine.startsWith('data:')) {
                         const jsonStr = trimmedLine.replace('data:', '');
                         try {
                             const data = JSON.parse(jsonStr);
-                            if(data.trim()){
+                            const trimmedData = data.trim()
+                            if (trimmedData === 'Subject' || trimmedData === 'Subject:') {
+                                waitingForSubject = true
+                                continue
+                            }
+
+                            if (waitingForSubject) {
+                                waitingForSubject = false
+                                readingSubject = true
+                            }
+
+                            if (readingSubject) {
+                                if (!data) {
+                                    readingSubject = false
+                                    continue
+                                }
+
+                                const newlineIndex = data.indexOf('\n')
+                                if (newlineIndex === -1) {
+                                    subject += data
+                                    continue
+                                }
+
+                                subject += data.slice(0, newlineIndex)
+                                readingSubject = false
+                                const contentAfterSubject = data.slice(newlineIndex + 1)
+                                if (contentAfterSubject.trim()) {
+                                    doneData += contentAfterSubject
+                                } else {
+                                    doneData += '</p><p>'
+                                }
+                            } else if(trimmedData){
                                 doneData += data
                             }else{
                                 doneData += '</p><p>'
@@ -335,7 +375,8 @@
                     }
                 }
             }
-            emailContent.value = doneData
+            emailContent.value = doneData.replace('<p></p>', '')
+            emailSubject.value = subject.replace(': ', '')
             isGenerating.value = false
             ElMessage.success('生成成功')
         } catch (error) {
@@ -345,7 +386,8 @@
     const useEmail = () => {
         let params = {
             id: typeData.value.filter(item => item.name == aiGenerator.value.inputs.scene)[0].id,
-            emailContent: emailContent.value
+            emailContent: emailContent.value,
+            emailSubject: emailSubject.value,
         }
         saveGenerateEmail(params).then(res => {
             ElMessage.success('保存成功')
@@ -361,6 +403,7 @@
 <style scoped>
 @import '../../assets/styles/marketing.css';
 
+.ai-modal :deep(.el-input__wrapper),
 .ai-modal :deep(.el-textarea__inner),
 .ai-modal :deep(.el-select .el-select__wrapper) {
     background: var(--bg-dark);
@@ -379,6 +422,7 @@
     background: var(--primary);
     border-color: var(--primary);
 }
+.ai-modal :deep(.el-input__inner),
 .ai-modal :deep(.el-checkbox__label) {
     color: var(--text-primary);
 }
@@ -498,4 +542,9 @@
 .msg-item .ai-button :deep(.el-button):hover{
     background: #3441569a;
 }
+.subject-div{
+    display: flex;
+    align-items: center;
+    margin-top: 16px;
+}
 </style>

+ 4 - 4
ui/smarttrade-platform/src/views/MarketingView.vue

@@ -84,7 +84,7 @@
           <div class="card-icon" :style="{ background: 'rgba(99, 102, 241, 0.2)' }">
             <i class="fas fa-globe" :style="{ color: 'var(--primary)' }"></i>
           </div>
-          <span class="status-badge" :class="campaign.status == 0 ? 'info' : campaign.status == 1 ? 'active' : 'paused'">{{ getStatusLabel(campaign.status || 0) }}</span>
+          <span class="status-badge" :class="campaign.status == 0 ? 'info' : campaign.status == 1 ? 'active' : campaign.status == 2 ? 'paused' : 'finished'">{{ getStatusLabel(campaign.status || 0) }}</span>
         </div>
         <div class="card-title">{{ campaign.name }}</div>
         <div class="card-desc">{{ campaign.description }}</div>
@@ -95,15 +95,15 @@
         </div>
         <div class="card-stats">
           <div class="stat-item">
-            <span class="stat-value">{{ formatNumber(campaign.sendVolume) }}</span>
+            <span class="stat-value">{{ campaign.sendVolume || 0 }}</span>
             <span class="stat-label">已发送</span>
           </div>
           <div class="stat-item">
-            <span class="stat-value success">{{ campaign.openRate }}%</span>
+            <span class="stat-value success">{{ campaign.openRate || 0 }}%</span>
             <span class="stat-label">打开率</span>
           </div>
           <div class="stat-item">
-            <span class="stat-value primary">{{ campaign.replyRate }}%</span>
+            <span class="stat-value primary">{{ campaign.replyRate || 0 }}%</span>
             <span class="stat-label">回复率</span>
           </div>
         </div>