Bläddra i källkod

Merge remote-tracking branch 'origin/master'

zhujing 3 veckor sedan
förälder
incheckning
543a817181

+ 2 - 1
java/storlead-api/src/main/resources/application-dev.yml

@@ -191,7 +191,8 @@ logging:
 environment: test
 dify:
   base-url: http://47.112.196.2:11434/v1/
-  download-url: http://47.112.196.2:11435
+  download-url: https://trade.test.storlead.com
+  #http://47.112.196.2:11435
   dataset-api-key: dataset-qfhXMNcjsRSwN5CK6aoWx3hl
   app-keys:
     chat: app-1-qfhXMNcjsRSwN5CK6aoWx3hl  #对话

+ 1 - 1
java/storlead-api/src/main/resources/application-prod.yml

@@ -241,7 +241,7 @@ file:
 
 dify:
   base-url: http://47.112.196.2:11434/v1/
-  download-url: http://47.112.196.2:11435
+  download-url: https://trade.test.storlead.com
   dataset-api-key: dataset-qfhXMNcjsRSwN5CK6aoWx3hl
   app-keys:
     chat: app-1-qfhXMNcjsRSwN5CK6aoWx3hl  #对话

+ 1 - 1
java/storlead-api/src/main/resources/application-test.yml

@@ -176,7 +176,7 @@ logging:
 environment: test
 dify:
   base-url: http://47.112.196.2:11434/v1/
-  download-url: http://47.112.196.2:11435
+  download-url: https://trade.test.storlead.com
   dataset-api-key: dataset-qfhXMNcjsRSwN5CK6aoWx3hl
   app-keys:
     chat: app-1-qfhXMNcjsRSwN5CK6aoWx3hl  #对话

+ 2 - 3
java/storlead-knowledge/storlead-knowledge-biz/src/main/resources/mapper/AiMessageMapper.xml

@@ -23,9 +23,7 @@
     </resultMap>
     <select id="queryList" resultMap="AiMessageWithReviewMap">
         SELECT
-        m.id,
-        m.query,
-        m.answer,
+        m.*,
         IFNULL(sum(r.agree), 0) AS agree,
         IFNULL(sum(r.disagree), 0) AS disagree,
         MAX(CASE WHEN r.owner_by = 1 THEN r.agree    ELSE 0 END) AS my_agree,
@@ -45,6 +43,7 @@
         <if test="queryField != null and queryField != ''">
             HAVING ${queryField} > 0
         </if>
+        ORDER BY create_time desc
     </select>
 
     <select id="getTotal" resultType="java.lang.Integer">

+ 0 - 3
java/storlead-mail/storlead-mail-api/src/main/java/com/storlead/mail/webclient/dto/MktSendMailRemoteDTO.java

@@ -60,7 +60,4 @@ public class MktSendMailRemoteDTO {
 
     @ApiModelProperty("回复原信 id")
     private Long replyMsgId;
-
-    @ApiModelProperty("是否已打开(像素)")
-    private Integer opened;
 }

+ 1 - 1
java/storlead-mail/storlead-mail-biz/src/main/java/com/storlead/mail/service/impl/MktMailStatusServiceImpl.java

@@ -29,7 +29,7 @@ public class MktMailStatusServiceImpl
         }
         LambdaQueryWrapper<MktMailStatusEntity> wrapper = new LambdaQueryWrapper<>();
         wrapper.eq(MktMailStatusEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
-                .apply("update_time > status_updated_at")
+                .apply("update_time > status_updated_at or status_updated_at is null ")
                 .gt(lastId != null, MktMailStatusEntity::getId, lastId)
                 .orderByAsc(MktMailStatusEntity::getId)
                 .last("limit " + limit);

+ 1 - 1
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketEmailsServiceImpl.java

@@ -987,7 +987,7 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
             dto.setRecipientls(recipientls);
             dto.setSubject(marketEmail.getSubject());
             dto.setContent(marketEmail.getContent());
-            dto.setOpened(1);
+            dto.setIsTrack(1);
 //            dto.setDelaySendTime(marketEmail.getExpectSendTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
             Result result = mktMailRemoteClient.send(dto);
             if (result.isSuccess()) {

+ 28 - 57
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketingCampaignServiceImpl.java

@@ -275,6 +275,7 @@ public class MarketingCampaignServiceImpl
                     marketingCampaignSopDetailEntity.setName(sopDetailEntity.getName());
                     marketingCampaignSopDetailEntity.setStep(sopDetailEntity.getStep());
                     marketingCampaignSopDetailEntity.setType(sopDetailEntity.getType());
+                    marketingCampaignSopDetailEntity.setDays(sopDetailEntity.getDays());
                     marketingCampaignSopDetailEntity.setEmailContent(sopDetailEntity.getEmailContent());
                     //预留补充ai生成的邮件内容模板
 //                    marketingCampaignSopDetailEntity.setEmailContent();
@@ -296,6 +297,10 @@ public class MarketingCampaignServiceImpl
             return Result.error("id不能为空");
         }
         MarketingCampaignEntity marketingCampaignOld = this.getById(marketingCampaignDTO.getId());
+        //只有未开始的营销活动才能修改
+        if (marketingCampaignOld.getStatus() != null && marketingCampaignOld.getStatus() != 0) {
+            return Result.error("该营销活动不能修改");
+        }
         MarketingCampaignEntity marketingCampaignEntity = new MarketingCampaignEntity();
         BeanUtils.copyProperties(marketingCampaignDTO, marketingCampaignEntity);
         // supervisorList 转为逗号分隔字符串
@@ -347,6 +352,7 @@ public class MarketingCampaignServiceImpl
                     marketingCampaignSopDetailEntity.setName(sopDetailEntity.getName());
                     marketingCampaignSopDetailEntity.setStep(sopDetailEntity.getStep());
                     marketingCampaignSopDetailEntity.setType(sopDetailEntity.getType());
+                    marketingCampaignSopDetailEntity.setDays(sopDetailEntity.getDays());
                     marketingCampaignSopDetailEntity.setEmailContent(sopDetailEntity.getEmailContent());
                     //预留补充ai生成的邮件内容模板
 //                    marketingCampaignSopDetailEntity.setEmailContent();
@@ -401,68 +407,33 @@ public class MarketingCampaignServiceImpl
     public void syncStartEndStatus() {
         LocalDate today = LocalDate.now(ZoneId.of("Asia/Shanghai"));
         // 查询所有未开始的活动
-        List<MarketingCampaignEntity> all = this.lambdaQuery()
+        List<MarketingCampaignEntity> nonAll = this.lambdaQuery()
                 .eq(MarketingCampaignEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
                 .eq(MarketingCampaignEntity::getStatus, 0)
+                .ge(MarketingCampaignEntity::getBeginData, today)
                 .list();
-        if (CollectionUtils.isEmpty(all)) {
-            log.info("营销活动开始/结束状态同步:无未删除活动,跳过");
-            return;
+        if (!CollectionUtils.isEmpty(nonAll)) {
+            List<Long> startIdList = nonAll.stream().map(MarketingCampaignEntity::getId).collect(Collectors.toList());
+            LambdaUpdateWrapper<MarketEmailsEntity> marketEmailsUpdateWrapper = new LambdaUpdateWrapper<>();
+            marketEmailsUpdateWrapper.in(MarketEmailsEntity::getMarketingCampaignId, startIdList);
+            marketEmailsUpdateWrapper.ne(MarketEmailsEntity::getStatus, -3);
+            marketEmailsUpdateWrapper.set(MarketEmailsEntity::getStatus, -1);
+            marketEmailsService.update(marketEmailsUpdateWrapper);
         }
-        // 按目标状态分组,只收集需要变更的 id(跳过暂停 / 日期缺失 / 状态已一致)
-        // 后续每种状态仅执行一次批量 UPDATE,而非逐条 UPDATE
-        Map<Integer, List<Long>> idsByStatus = new HashMap<>(4);
-        // 变更的实体列表(status 已回填为目标状态,用于区分改为开始/结束)
-        List<MarketingCampaignEntity> changed = new ArrayList<>();
-        for (MarketingCampaignEntity c : all) {
-            Integer expected = computeStartEndStatus(c, today);
-            if (expected == null) {
-                continue;
-            }
-            Integer current = c.getStatus();
-            // 尊重手动暂停,不自动覆盖
-            if (current != null && current == STATUS_PAUSED) {
-                continue;
-            }
-            if (expected.equals(current)) {
-                continue;
-            }
-            idsByStatus.computeIfAbsent(expected, k -> new ArrayList<>()).add(c.getId());
-            c.setStatus(expected);
-            changed.add(c);
+        // 查询所有已结束的活动
+        List<MarketingCampaignEntity> stopAll = this.lambdaQuery()
+                .eq(MarketingCampaignEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
+                .eq(MarketingCampaignEntity::getStatus, 1)
+                .le(MarketingCampaignEntity::getEndDate, today)
+                .list();
+        if (!CollectionUtils.isEmpty(stopAll)) {
+            List<Long> stopIdList = stopAll.stream().map(MarketingCampaignEntity::getId).collect(Collectors.toList());
+            LambdaUpdateWrapper<MarketEmailsEntity> marketEmailsUpdateWrapper = new LambdaUpdateWrapper<>();
+            marketEmailsUpdateWrapper.in(MarketEmailsEntity::getMarketingCampaignId, stopIdList);
+            marketEmailsUpdateWrapper.eq(MarketEmailsEntity::getStatus, -1);
+            marketEmailsUpdateWrapper.set(MarketEmailsEntity::getStatus, -3);
+            marketEmailsService.update(marketEmailsUpdateWrapper);
         }
-//        // 每种目标状态执行一次批量 UPDATE
-//        for (Map.Entry<Integer, List<Long>> entry : idsByStatus.entrySet()) {
-//            List<Long> ids = entry.getValue();
-//            if (CollectionUtils.isEmpty(ids)) {
-//                continue;
-//            }
-//            this.lambdaUpdate()
-//                    .in(MarketingCampaignEntity::getId, ids)
-//                    .set(MarketingCampaignEntity::getStatus, entry.getKey())
-//                    .update();
-//        }
-//        // 按目标状态拆分列表并打印:哪些改为开始、哪些改为结束
-//        List<Long> started = changed.stream()
-//                .filter(e -> STATUS_RUNNING == e.getStatus())
-//                .map(MarketingCampaignEntity::getId)
-//                .collect(Collectors.toList());
-//        List<Long> ended = changed.stream()
-//                .filter(e -> STATUS_COMPLETED == e.getStatus())
-//                .map(MarketingCampaignEntity::getId)
-//                .collect(Collectors.toList());
-//        log.info("营销活动开始/结束状态同步完成:改为开始(运行中)={}, 改为结束(完成)={}", started, ended);
-//        MarketEmailsCustomerVO startVO = new MarketEmailsCustomerVO();
-//        startVO.setMarketingCampaignIdList(started);
-//        //修改状态为待发送
-//        startVO.setStatus(-1);
-//        marketEmailsService.updateCustomerEmailStatus(startVO);
-//
-//        MarketEmailsCustomerVO endVO = new MarketEmailsCustomerVO();
-//        endVO.setMarketingCampaignIdList(ended);
-//        //修改状态为待发送
-//        endVO.setStatus(-3);
-//        marketEmailsService.updateCustomerEmailStatus(endVO);
     }
 
     /**

+ 52 - 51
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketingCampaignSopDetailServiceImpl.java

@@ -84,69 +84,70 @@ public class MarketingCampaignSopDetailServiceImpl
 
 
 //        List<CustomerEntity> customerEntityList = customerService.listByIds(customerIdList);
-        //查询本地信息
-        String yourName = "";
-        String companyName = "";
-        String yourTitle = "";
-        String yourCompany = "";
-        String yourPhone = "";
-        String yourEmail = "";
-        String fullCompanyAddress = "";
-        List<SysDictDetailResponseDTO> sysDictDetailResponseDTOList = sysDictService.getListByCode("company_base");
-        if (!CollectionUtils.isEmpty(sysDictDetailResponseDTOList)){
-            //取label为本地信息的value值
-            for (SysDictDetailResponseDTO sysDictDetailResponseDTO : sysDictDetailResponseDTOList) {
-                if ("yourName".equals(sysDictDetailResponseDTO.getLabel())) {
-                    yourName = sysDictDetailResponseDTO.getValue();
-                }if ("companyName".equals(sysDictDetailResponseDTO.getLabel())) {
-                    companyName = sysDictDetailResponseDTO.getValue();
-                }
-                if ("yourTitle".equals(sysDictDetailResponseDTO.getLabel())) {
-                    yourTitle = sysDictDetailResponseDTO.getValue();
-                }
-                if ("yourCompany".equals(sysDictDetailResponseDTO.getLabel())) {
-                    yourTitle = sysDictDetailResponseDTO.getValue();
-                }
-                if ("yourPhone".equals(sysDictDetailResponseDTO.getLabel())) {
-                    yourPhone = sysDictDetailResponseDTO.getValue();
-                }
-                if ("yourEmail".equals(sysDictDetailResponseDTO.getLabel())) {
-                    yourEmail = sysDictDetailResponseDTO.getValue();
-                }
-                if ("fullCompanyAddress".equals(sysDictDetailResponseDTO.getLabel())) {
-                    fullCompanyAddress = sysDictDetailResponseDTO.getValue();
-                }
-            }
 
-        }
 
 
         Map<Long,CustomerVO> customerEntityMap = customerVOList.stream().collect(Collectors.toMap(CustomerVO::getId, customerVO -> customerVO));
         for (MarketEmailsEntity marketEmailsEntity : marketEmailsEntityList) {
-            marketEmailsEntity.setSubject(emailSubject);
+            String emailContentNew = emailContent;
+            String emailSubjectNew = emailSubject;
+            //查询客户信息
+//            客户名称:${customerName}$
+//            区域名称:${areaName}$
+//            企业名称:${companyName}$
+//            企业网址:${companyUrl}$
+//            联系人名称:${liaisonName}$
+//            联系人邮箱:${email}$
+            String customerName = "";
+            String areaName = "";
+            String companyName = "";
+            String companyUrl = "";
+            String liaisonName = "";
+            String email = "";
+//            marketEmailsEntity.setSubject(emailSubject);
             marketEmailsEntity.setStatus(-1);
             CustomerVO customerEntity = customerEntityMap.get(marketEmailsEntity.getCustomerId());
             if (customerEntity != null) {
                 if (ObjectUtils.isEmpty(customerEntity.getCustomerCompany())) {
                     customerEntity.setCustomerCompany(new CustomerCompanyEntity());
                 }
-
-//                ${areaName}$、${customerIndustry}$
-                //修改emailContent中全部的${customerName}$为customerEntity.getCustomerName()
-                String industry = "";
-                if (!ObjectUtils.isEmpty(customerEntity.getCustomerCompany().getIndustry())){
-                    industry = customerEntity.getCustomerCompany().getIndustry();
+                if (ObjectUtils.isEmpty(customerEntity.getLiaison())) {
+                    customerEntity.setLiaison(new LiaisonEntity());
+                }
+                if (!ObjectUtils.isEmpty(customerEntity.getCustomerName())) {
+                    customerName = customerEntity.getCustomerName();
+                }
+                if (!ObjectUtils.isEmpty(customerEntity.getCountry())) {
+                    areaName = customerEntity.getCountry();
+                }
+                if (!ObjectUtils.isEmpty(customerEntity.getCustomerCompany().getName())){
+                    companyName = customerEntity.getCustomerCompany().getName();
                 }
-                emailContent = emailContent.replace("${customerName}$", companyName)
-                        .replace("${areaName}$", customerEntity.getCountry())
-                        .replace("${customerIndustry}$", industry)
-                        .replace("${yourName}$", yourName)
-                        .replace("${yourTitle}$", yourTitle)
-                        .replace("${yourCompany}$", yourCompany)
-                        .replace("${yourPhone}$", yourPhone)
-                        .replace("${yourEmail}$", yourEmail)
-                        .replace("${fullCompanyAddress}$", fullCompanyAddress);
-                marketEmailsEntity.setContent(emailContent);
+                if (!ObjectUtils.isEmpty(customerEntity.getCustomerCompany().getWebsite())){
+                    companyUrl = customerEntity.getCustomerCompany().getWebsite();
+                }
+                if (!ObjectUtils.isEmpty(customerEntity.getLiaison().getName())){
+                    liaisonName = customerEntity.getLiaison().getName();
+                }
+                if (!ObjectUtils.isEmpty(customerEntity.getLiaison().getEmail())){
+                    email = customerEntity.getLiaison().getEmail();
+                }
+                emailContentNew = emailContentNew.replace("${customerName}$", customerName)
+                        .replace("${areaName}$", areaName)
+                        .replace("${companyName}$", companyName)
+                        .replace("${companyUrl}$", companyUrl)
+                        .replace("${liaisonName}$", liaisonName)
+                        .replace("${email}$", email);
+
+                emailSubjectNew = emailSubjectNew.replace("${customerName}$", customerName)
+                        .replace("${areaName}$", areaName)
+                        .replace("${companyName}$", companyName)
+                        .replace("${companyUrl}$", companyUrl)
+                        .replace("${liaisonName}$", liaisonName)
+                        .replace("${email}$", email);
+                marketEmailsEntity.setContent(emailContentNew);
+                marketEmailsEntity.setSubject(emailSubjectNew);
+
             }
             if (!ObjectUtils.isEmpty(marketEmailsEntity.getCustomerId()) && !ObjectUtils.isEmpty(customerEntityMap.get(marketEmailsEntity.getCustomerId()).getCustomerCompany()) && !ObjectUtils.isEmpty(customerEntityMap.get(marketEmailsEntity.getCustomerId()).getCustomerCompany().getEmail())){
                 marketEmailsEntity.setRecipient(customerEntityMap.get(marketEmailsEntity.getCustomerId()).getCustomerCompany().getEmail());

+ 1 - 1
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/task/MarketStartOrEndTask.java

@@ -18,7 +18,7 @@ public class MarketStartOrEndTask {
     @Resource
     private MarketingCampaignService marketingCampaignService;
 
-    @Scheduled(cron = "0 0 8 * * ?")
+    @Scheduled(cron = "0 50 10 * * ?")
     public void dispatch() {
         long start = System.currentTimeMillis();
         log.info("营销活动开始/结束状态同步任务开始");

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

@@ -923,6 +923,10 @@
 
 .no-data{ min-height: 100px; display: flex; align-items: center; justify-content: center; color: var(--text-muted); font-size: 14px; }
 :deep(.el-loading-mask){ background: transparent; }
+.btn:disabled{
+  opacity: 0.5;
+  cursor: not-allowed;
+}
 
 
 @media (max-width: 1400px) {

+ 10 - 4
ui/smarttrade-platform/src/components/addMarketing.vue

@@ -455,7 +455,7 @@
                                 "></div>
                             <div class="rule-content">
                                 <div class="rule-title">未打开邮件自动跟进</div>
-                                <div class="rule-desc">3天后发送提醒邮件,更换主题行</div>
+                                <div class="rule-desc">{{ newCampaign.rules.noOpenFollowupDays }}天后发送提醒邮件,更换主题行</div>
                             </div>
                             <div class="rule-config" v-if="newCampaign.rules.noOpenFollowup">
                                 <el-select style="width: 90px;" v-model="newCampaign.rules.noOpenFollowupDays" placeholder="请选择">
@@ -632,9 +632,9 @@
                 <button v-if="currentStep < 5" class="btn btn-primary" @click="currentStep++">
                     下一步 <i class="fas fa-arrow-right"></i>
                 </button>
-                <button v-else class="btn btn-primary" @click="createCampaign">
-                    <i class="fas fa-rocket"></i> {{ isEditMode ? "保存活动" : "创建活动" }}
-                </button>
+                <el-button :loading="loading" style="height: 41px;" v-else class="btn btn-primary" @click="createCampaign">
+                    <i class="fas fa-rocket" style="margin-right: 6px;"></i> {{ isEditMode ? "保存活动" : "创建活动" }}
+                </el-button>
             </div>
         </div>
     </div>
@@ -888,6 +888,7 @@
 
     const goToStep = (step) => { currentStep.value = step }
 
+    const loading = ref(false)
     const createCampaign = async () => {
         if (!newCampaign.value.name) {
             currentStep.value = 1
@@ -904,6 +905,7 @@
             return
         }
         try {
+            loading.value = true
             const typeMap = { prospect: 1, nurture: 2, reactivate: 3, promote: 4, seasonal: 5, exhibition: 6, other: 7 }
             const priorityMap = { urgent: 1, high: 2, medium: 3, low: 4 }
             const channelConfig = newCampaign.value.channels.reduce((acc, channel) => {
@@ -952,6 +954,8 @@
                     closeCreateModal()
                 }).catch(err => {
                     ElMessage.error(err?.message || '更新营销活动失败')
+                }).finally(() => {
+                    loading.value = false
                 })
             } else {
                 await addMarketing(payload).then(res => {
@@ -960,6 +964,8 @@
                     closeCreateModal()
                 }).catch(err => {
                     ElMessage.error(err?.message || '创建营销活动失败')
+                }).finally(() => {
+                    loading.value = false
                 })
             }
         } catch (error) {

+ 5 - 1
ui/smarttrade-platform/src/components/layout/TopBar.vue

@@ -567,7 +567,7 @@
     </transition>
   </header>
 
-  <AddMarketing ref="addMarketingRef" />
+  <AddMarketing ref="addMarketingRef" @refresh="handleMarketingRefresh" />
 
   <div v-if="showSettings" class="modal-overlay" @click.self="showSettings = false">
     <div class="modal create-modal" style="max-width: 800px;">
@@ -709,6 +709,10 @@ const pageTitle = computed(() => {
 })
 
 const addMarketingRef = ref()
+const handleMarketingRefresh = () => {
+  window.dispatchEvent(new CustomEvent('marketing:refresh'))
+}
+
 const openModal = (type) => {
   showQuickActions.value = false
   addMarketingRef.value.open()

+ 4 - 2
ui/smarttrade-platform/src/components/marketing/emailList.vue

@@ -45,7 +45,7 @@
               <button v-if="activeFilter !== 'sent'" class="btn btn-secondary" @click="cancelSend(item)">
                 {{  activeFilter === 'pending' ? '取消' : '重新' }}发送
               </button>
-              <button class="btn btn-secondary" @click="viewDetail(item)">
+              <button class="btn btn-secondary" @click="viewDetail(item)" v-if="activeFilter == 'sent'">
                 邮件详情
               </button>
               <button v-if="activeFilter !== 'sent'" class="btn btn-primary" @click="editEmail(item)">
@@ -75,6 +75,7 @@ const emailList = ref([])
 const open = (campaign) => {
   selectedCampaign.value = campaign || null
   emailList.value = []
+  activeFilter.value = 'pending'
   getStatusCounts()
   getList()
   showEmailListModal.value = true
@@ -138,9 +139,10 @@ const cancelSend = (item) => {
       type: 'warning',
     }
   ).then(() => {
-    cancelEmail({ id: item.id, status: (item.status == -2 ? -3 : -2) }).then(() => {
+    cancelEmail({ id: item.id, status: (item.status == -1 ? -3 : -1) }).then(() => {
       ElMessage.success('操作成功')
       getList()
+      getStatusCounts()
     }).catch((err) => {
       ElMessage.error(err.message || '操作失败')
     })

+ 2 - 2
ui/smarttrade-platform/src/components/marketing/marketingDetail.vue

@@ -143,7 +143,7 @@
                   <div class="step-marker">{{ item.step }}</div>
                   <div class="step-content">
                     <div class="step-title">{{ item.name }}</div>
-                    <div class="step-meta">第{{ item.days }}天 · 邮件 · 待执行</div>
+                    <div class="step-meta">间隔{{ item.days }}天 · 邮件 · 待执行</div>
                   </div>
                 </div>
               </div>
@@ -208,7 +208,7 @@
             <i class="fas fa-download"></i> 导出报告
           </button> -->
           <button class="btn btn-secondary" @click="showCampaignDetailModal = false">关闭</button>
-          <button class="btn btn-primary" @click="editCampaign(selectedCampaign)">
+          <button class="btn btn-primary" :disabled="selectedCampaign.status != 0" @click="editCampaign(selectedCampaign)">
             <i class="fas fa-edit"></i> 编辑活动
           </button>
         </div>

+ 10 - 1
ui/smarttrade-platform/src/views/MarketingView.vue

@@ -731,7 +731,7 @@
 </template>
 
 <script setup>
-import { ref, computed, onMounted } from 'vue'
+import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
 import { ElMessageBox } from 'element-plus'
 import AddMarketing from '../components/addMarketing.vue'
 import { getMarketingList, setMarketingStatus, marketingAnalysis } from '../api/marketing'
@@ -773,9 +773,18 @@ const openCreateModal = () => {
 }
 
 const marketingList = ref([])
+const handleExternalMarketingRefresh = () => {
+  getData()
+}
+
 onMounted(() => {
   getData()
   getStatsData()
+  window.addEventListener('marketing:refresh', handleExternalMarketingRefresh)
+})
+
+onBeforeUnmount(() => {
+  window.removeEventListener('marketing:refresh', handleExternalMarketingRefresh)
 })
 
 const loading = ref(false)