From 57bc8ab4c976d778485d20f44bc02c0bd7aa5ed3 Mon Sep 17 00:00:00 2001 From: cb <275647614@qq.com> Date: Tue, 23 Dec 2025 10:53:19 +0800 Subject: [PATCH] no message --- .../system/ClewMaterialController.java | 29 ++++- .../system/MaterialStatsDailyController.java | 48 +++++++++ .../MaterialStatsDailyViewController.java | 16 +++ .../templates/system/material/stats.html | 82 ++++++++++++++ .../system/domain/MaterialStatsDaily.java | 100 ++++++++++++++++++ .../mapper/MaterialStatsDailyMapper.java | 41 +++++++ .../service/IMaterialStatsDailyService.java | 12 +++ .../impl/MaterialStatsDailyServiceImpl.java | 21 ++++ .../system/MaterialStatsDailyMapper.xml | 54 ++++++++++ .../sql/material_stats_daily_alter.sql | 11 ++ sql/add_click_count_to_clew_material.sql | 2 + sql/add_submit_count_and_efficiency_rate.sql | 4 + test_manual_service.md | 52 +++++++++ 13 files changed, 470 insertions(+), 2 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/MaterialStatsDailyController.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/MaterialStatsDailyViewController.java create mode 100644 ruoyi-admin/src/main/resources/templates/system/material/stats.html create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/MaterialStatsDaily.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/MaterialStatsDailyMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/IMaterialStatsDailyService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MaterialStatsDailyServiceImpl.java create mode 100644 ruoyi-system/src/main/resources/mapper/system/MaterialStatsDailyMapper.xml create mode 100644 ruoyi-system/src/main/resources/sql/material_stats_daily_alter.sql create mode 100644 sql/add_click_count_to_clew_material.sql create mode 100644 sql/add_submit_count_and_efficiency_rate.sql create mode 100644 test_manual_service.md diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/ClewMaterialController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/ClewMaterialController.java index a856ee86..5b3d2763 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/ClewMaterialController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/ClewMaterialController.java @@ -14,6 +14,10 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.system.mapper.MaterialStatsDailyMapper; +import javax.servlet.http.HttpServletRequest; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; /** * 素材Controller @@ -30,6 +34,9 @@ public class ClewMaterialController extends BaseController @Autowired private IClewMaterialService clewMaterialService; + @Autowired + private MaterialStatsDailyMapper materialStatsDailyMapper; + @RequiresPermissions("system:material:view") @GetMapping() public String material() @@ -138,9 +145,16 @@ public class ClewMaterialController extends BaseController */ @PostMapping("/app/click/{id}") @ResponseBody - public AjaxResult incrementClickCount(@PathVariable("id") Long id) + public AjaxResult incrementClickCount(@PathVariable("id") Long id, HttpServletRequest request) { System.out.println("点击统计接口被调用,素材ID: " + id); + String appName = "黑猫搞定逾期"; + String statDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + ClewMaterial material = clewMaterialService.selectClewMaterialById(id); + String title = material != null ? material.getTitle() : null; + String labels = material != null ? material.getLabels() : null; + String appSource = material != null && material.getSourceApp() != null ? String.valueOf(material.getSourceApp()) : "unknown"; + materialStatsDailyMapper.incrClick(id, appName, appSource, statDate, title, labels); int result = clewMaterialService.incrementClickCount(id); System.out.println("点击统计结果: " + result); return toAjax(result); @@ -151,11 +165,22 @@ public class ClewMaterialController extends BaseController */ @PostMapping("/app/submit/{id}") @ResponseBody - public AjaxResult incrementSubmitCount(@PathVariable("id") Long id) + public AjaxResult incrementSubmitCount(@PathVariable("id") Long id, HttpServletRequest request) { System.out.println("提交统计接口被调用,素材ID: " + id); + String appName = "黑猫搞定逾期"; + String statDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + ClewMaterial material = clewMaterialService.selectClewMaterialById(id); + String title = material != null ? material.getTitle() : null; + String labels = material != null ? material.getLabels() : null; + String appSource = material != null && material.getSourceApp() != null ? String.valueOf(material.getSourceApp()) : "unknown"; + materialStatsDailyMapper.incrSubmit(id, appName, appSource, statDate, title, labels); int result = clewMaterialService.incrementSubmitCount(id); System.out.println("提交统计结果: " + result); return toAjax(result); } + + private String defaultString(String val, String def) { + return (val == null || val.trim().isEmpty()) ? def : val.trim(); + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/MaterialStatsDailyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/MaterialStatsDailyController.java new file mode 100644 index 00000000..c9532553 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/MaterialStatsDailyController.java @@ -0,0 +1,48 @@ +package com.ruoyi.web.controller.system; + +import java.util.List; +import com.ruoyi.system.domain.MaterialStatsDaily; +import com.ruoyi.system.service.IMaterialStatsDailyService; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/system/material/stats") +public class MaterialStatsDailyController extends BaseController +{ + @Autowired + private IMaterialStatsDailyService statsService; + + /** + * 分页查询素材转化统计 + */ + @PostMapping("/list") + public TableDataInfo list(@RequestParam(value = "appName", required = false) String appName, + @RequestParam(value = "appSource", required = false) String appSource, + @RequestParam(value = "startDate", required = false) String startDate, + @RequestParam(value = "endDate", required = false) String endDate) + { + startPage(); + List list = statsService.selectStats(appName, appSource, startDate, endDate); + for (MaterialStatsDaily item : list) { + item.setAppSource(mapSource(item.getAppSource())); + } + return getDataTable(list); + } + + private String mapSource(String code) { + if (code == null || code.trim().isEmpty()) return "未知"; + switch (code.trim()) { + case "1": return "OPPO"; + case "2": return "vivo"; + case "3": return "华为"; + case "4": return "小米"; + case "5": return "应用宝"; + case "6": return "百度"; + default: return code; + } + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/MaterialStatsDailyViewController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/MaterialStatsDailyViewController.java new file mode 100644 index 00000000..6b153fea --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/MaterialStatsDailyViewController.java @@ -0,0 +1,16 @@ +package com.ruoyi.web.controller.system; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/system/material") +public class MaterialStatsDailyViewController { + + @GetMapping("/statsPage") + public String statsPage() { + return "system/material/stats"; + } +} + diff --git a/ruoyi-admin/src/main/resources/templates/system/material/stats.html b/ruoyi-admin/src/main/resources/templates/system/material/stats.html new file mode 100644 index 00000000..48ad8a14 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/system/material/stats.html @@ -0,0 +1,82 @@ + + + + + + + +
+
+
+
+
+
    +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • +  搜索 +  重置 +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/MaterialStatsDaily.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/MaterialStatsDaily.java new file mode 100644 index 00000000..ef264078 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/MaterialStatsDaily.java @@ -0,0 +1,100 @@ +package com.ruoyi.system.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; +import java.util.Date; + +public class MaterialStatsDaily extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键 */ + private Long id; + + /** 素材ID */ + @Excel(name = "素材ID") + private Long materialId; + + /** 应用名称 */ + @Excel(name = "应用") + private String appName; + + /** APP来源 */ + @Excel(name = "APP来源") + private String appSource; + + /** 统计日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "统计日期", width = 30, dateFormat = "yyyy-MM-dd") + private Date statDate; + + /** 素材标题 */ + @Excel(name = "素材标题") + private String title; + + /** 素材标签 */ + @Excel(name = "素材标签") + private String labels; + + /** 点击数 */ + @Excel(name = "点击数") + private Integer clickCnt; + + /** 提交数 */ + @Excel(name = "提交数") + private Integer submitCnt; + + /** 转化率 */ + @Excel(name = "转化率(%)") + private Double conversionRate; + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public Long getMaterialId() { return materialId; } + public void setMaterialId(Long materialId) { this.materialId = materialId; } + + public String getAppName() { return appName; } + public void setAppName(String appName) { this.appName = appName; } + + public String getAppSource() { return appSource; } + public void setAppSource(String appSource) { this.appSource = appSource; } + + public Date getStatDate() { return statDate; } + public void setStatDate(Date statDate) { this.statDate = statDate; } + + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + + public String getLabels() { return labels; } + public void setLabels(String labels) { this.labels = labels; } + + public Integer getClickCnt() { return clickCnt; } + public void setClickCnt(Integer clickCnt) { this.clickCnt = clickCnt; } + + public Integer getSubmitCnt() { return submitCnt; } + public void setSubmitCnt(Integer submitCnt) { this.submitCnt = submitCnt; } + + public Double getConversionRate() { return conversionRate; } + public void setConversionRate(Double conversionRate) { this.conversionRate = conversionRate; } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("materialId", getMaterialId()) + .append("appName", getAppName()) + .append("appSource", getAppSource()) + .append("statDate", getStatDate()) + .append("title", getTitle()) + .append("labels", getLabels()) + .append("clickCnt", getClickCnt()) + .append("submitCnt", getSubmitCnt()) + .append("conversionRate", getConversionRate()) + .append("createTime", getCreateTime()) + .toString(); + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/MaterialStatsDailyMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/MaterialStatsDailyMapper.java new file mode 100644 index 00000000..d7af4c43 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/MaterialStatsDailyMapper.java @@ -0,0 +1,41 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.MaterialStatsDaily; +import org.apache.ibatis.annotations.Param; + +public interface MaterialStatsDailyMapper +{ + /** + * 插入或更新日统计数据(MySQL 唯一键冲突时更新) + */ + int insertOrUpdate(MaterialStatsDaily record); + + /** + * 按条件查询统计列表 + */ + List selectList(@Param("appName") String appName, + @Param("appSource") String appSource, + @Param("startDate") String startDate, + @Param("endDate") String endDate); + + /** + * 点击数+1(存在即更新,不存在则插入 0,1,0) + */ + int incrClick(@Param("materialId") Long materialId, + @Param("appName") String appName, + @Param("appSource") String appSource, + @Param("statDate") String statDate, + @Param("title") String title, + @Param("labels") String labels); + + /** + * 提交数+1(存在即更新,不存在则插入 1,0,0) + */ + int incrSubmit(@Param("materialId") Long materialId, + @Param("appName") String appName, + @Param("appSource") String appSource, + @Param("statDate") String statDate, + @Param("title") String title, + @Param("labels") String labels); +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IMaterialStatsDailyService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IMaterialStatsDailyService.java new file mode 100644 index 00000000..964e1864 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IMaterialStatsDailyService.java @@ -0,0 +1,12 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.domain.MaterialStatsDaily; + +public interface IMaterialStatsDailyService +{ + /** + * 按条件查询统计列表 + */ + List selectStats(String appName, String appSource, String startDate, String endDate); +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MaterialStatsDailyServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MaterialStatsDailyServiceImpl.java new file mode 100644 index 00000000..cad1fedb --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MaterialStatsDailyServiceImpl.java @@ -0,0 +1,21 @@ +package com.ruoyi.system.service.impl; + +import java.util.List; +import com.ruoyi.system.domain.MaterialStatsDaily; +import com.ruoyi.system.mapper.MaterialStatsDailyMapper; +import com.ruoyi.system.service.IMaterialStatsDailyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class MaterialStatsDailyServiceImpl implements IMaterialStatsDailyService +{ + @Autowired + private MaterialStatsDailyMapper statsMapper; + + @Override + public List selectStats(String appName, String appSource, String startDate, String endDate) + { + return statsMapper.selectList(appName, appSource, startDate, endDate); + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/resources/mapper/system/MaterialStatsDailyMapper.xml b/ruoyi-system/src/main/resources/mapper/system/MaterialStatsDailyMapper.xml new file mode 100644 index 00000000..64b8a119 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/MaterialStatsDailyMapper.xml @@ -0,0 +1,54 @@ + + + + + + + INSERT INTO material_stats_daily + (material_id, app_name, app_source, stat_date, title, labels, click_cnt, submit_cnt, conversion_rate) + VALUES + (#{materialId}, #{appName}, #{appSource}, #{statDate}, #{title}, #{labels}, #{clickCnt}, #{submitCnt}, #{conversionRate}) + + + + + + + + + INSERT INTO material_stats_daily + (material_id, app_name, app_source, event_type, stat_date, event_time, title, labels, click_cnt, submit_cnt, conversion_rate) + VALUES + (#{materialId}, #{appName}, #{appSource}, 'click', #{statDate}, NOW(), #{title}, #{labels}, 1, 0, 0.00) + + + + + INSERT INTO material_stats_daily + (material_id, app_name, app_source, event_type, stat_date, event_time, title, labels, click_cnt, submit_cnt, conversion_rate) + VALUES + (#{materialId}, #{appName}, #{appSource}, 'submit', #{statDate}, NOW(), #{title}, #{labels}, 0, 1, 0.00) + + + diff --git a/ruoyi-system/src/main/resources/sql/material_stats_daily_alter.sql b/ruoyi-system/src/main/resources/sql/material_stats_daily_alter.sql new file mode 100644 index 00000000..8b756e97 --- /dev/null +++ b/ruoyi-system/src/main/resources/sql/material_stats_daily_alter.sql @@ -0,0 +1,11 @@ +ALTER TABLE `material_stats_daily` + DROP INDEX `uk_material_day`; + +ALTER TABLE `material_stats_daily` + ADD COLUMN `event_type` varchar(16) NOT NULL COMMENT '事件类型: click/submit' AFTER `app_source`, + ADD COLUMN `event_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '事件时间' AFTER `stat_date`; + +-- 说明: +-- 1. 取消唯一键,允许同一天多条记录 +-- 2. 每次点击/提交都插入一条事件,click_cnt/submit_cnt分布为(1,0)或(0,1) +-- 3. 区间统计按SUM(click_cnt)/SUM(submit_cnt)计算转化率 diff --git a/sql/add_click_count_to_clew_material.sql b/sql/add_click_count_to_clew_material.sql new file mode 100644 index 00000000..c7846456 --- /dev/null +++ b/sql/add_click_count_to_clew_material.sql @@ -0,0 +1,2 @@ +-- 在clew_material表中增加点击数字段 +ALTER TABLE clew_material ADD COLUMN click_count INT DEFAULT 0 COMMENT '点击次数' AFTER apply_num; \ No newline at end of file diff --git a/sql/add_submit_count_and_efficiency_rate.sql b/sql/add_submit_count_and_efficiency_rate.sql new file mode 100644 index 00000000..2e8c6de6 --- /dev/null +++ b/sql/add_submit_count_and_efficiency_rate.sql @@ -0,0 +1,4 @@ +-- 在clew_material表中增加提交次数和有效率字段 +ALTER TABLE clew_material +ADD COLUMN submit_count INT DEFAULT 0 COMMENT '提交次数' AFTER click_count, +ADD COLUMN efficiency_rate DECIMAL(5,2) DEFAULT 0.00 COMMENT '有效率(提交次数/点击次数)' AFTER submit_count; \ No newline at end of file diff --git a/test_manual_service.md b/test_manual_service.md new file mode 100644 index 00000000..d8a1c16a --- /dev/null +++ b/test_manual_service.md @@ -0,0 +1,52 @@ +# 转人工服务功能测试说明 + +## 修复内容 + +### 1. 修复session_id字段缺失问题 +- **问题**: 在acceptManualRequest和rejectManualRequest方法中,创建ManualServiceSessions对象时缺少manualSessionId字段 +- **修复**: 将setUserId(requestId)改为setManualSessionId(requestId) +- **影响**: 确保更新操作能正确定位到要修改的记录 + +### 2. 修复status字段数据截断问题 +- **问题**: status字段使用长字符串值("PENDING", "ACCEPTED", "REJECTED")导致数据截断 +- **修复**: 统一使用单字符状态码 + - "0" - 待处理 (原PENDING) + - "1" - 已接受 (原ACCEPTED) + - "2" - 已拒绝 (原REJECTED) +- **影响**: 避免"Data truncated for column 'status'"错误 + +## 测试步骤 + +### 1. 创建转人工请求 +``` +POST /customer/transfer +参数: sessionId=123, reason="需要人工协助" +预期: 成功创建请求,status=0 +``` + +### 2. 接受转人工请求 +``` +POST /customer/manual-requests/{requestId}/accept +预期: 成功更新状态为1,设置serviceId +``` + +### 3. 拒绝转人工请求 +``` +POST /customer/manual-requests/{requestId}/reject +预期: 成功更新状态为2,设置serviceId +``` + +## 验证要点 + +1. 插入操作不再报"Field 'session_id' doesn't have a default value"错误 +2. 更新操作不再报"Data truncated for column 'status'"错误 +3. 状态值正确保存和查询 +4. 主键字段正确设置,更新操作能找到对应记录 + +## 状态码对照表 + +| 数字码 | 含义 | 原字符串值 | +|--------|------|------------| +| 0 | 待处理 | PENDING | +| 1 | 已接受 | ACCEPTED | +| 2 | 已拒绝 | REJECTED | \ No newline at end of file