no message
This commit is contained in:
parent
a6c588d411
commit
57bc8ab4c9
|
|
@ -14,6 +14,10 @@ import com.ruoyi.common.core.controller.BaseController;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
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
|
* 素材Controller
|
||||||
|
|
@ -30,6 +34,9 @@ public class ClewMaterialController extends BaseController
|
||||||
@Autowired
|
@Autowired
|
||||||
private IClewMaterialService clewMaterialService;
|
private IClewMaterialService clewMaterialService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MaterialStatsDailyMapper materialStatsDailyMapper;
|
||||||
|
|
||||||
@RequiresPermissions("system:material:view")
|
@RequiresPermissions("system:material:view")
|
||||||
@GetMapping()
|
@GetMapping()
|
||||||
public String material()
|
public String material()
|
||||||
|
|
@ -138,9 +145,16 @@ public class ClewMaterialController extends BaseController
|
||||||
*/
|
*/
|
||||||
@PostMapping("/app/click/{id}")
|
@PostMapping("/app/click/{id}")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AjaxResult incrementClickCount(@PathVariable("id") Long id)
|
public AjaxResult incrementClickCount(@PathVariable("id") Long id, HttpServletRequest request)
|
||||||
{
|
{
|
||||||
System.out.println("点击统计接口被调用,素材ID: " + id);
|
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);
|
int result = clewMaterialService.incrementClickCount(id);
|
||||||
System.out.println("点击统计结果: " + result);
|
System.out.println("点击统计结果: " + result);
|
||||||
return toAjax(result);
|
return toAjax(result);
|
||||||
|
|
@ -151,11 +165,22 @@ public class ClewMaterialController extends BaseController
|
||||||
*/
|
*/
|
||||||
@PostMapping("/app/submit/{id}")
|
@PostMapping("/app/submit/{id}")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AjaxResult incrementSubmitCount(@PathVariable("id") Long id)
|
public AjaxResult incrementSubmitCount(@PathVariable("id") Long id, HttpServletRequest request)
|
||||||
{
|
{
|
||||||
System.out.println("提交统计接口被调用,素材ID: " + id);
|
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);
|
int result = clewMaterialService.incrementSubmitCount(id);
|
||||||
System.out.println("提交统计结果: " + result);
|
System.out.println("提交统计结果: " + result);
|
||||||
return toAjax(result);
|
return toAjax(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String defaultString(String val, String def) {
|
||||||
|
return (val == null || val.trim().isEmpty()) ? def : val.trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<MaterialStatsDaily> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
|
||||||
|
<head>
|
||||||
|
<th:block th:include="include :: header('素材转化统计')" />
|
||||||
|
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||||
|
</head>
|
||||||
|
<body class="gray-bg">
|
||||||
|
<div class="container-div">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 search-collapse">
|
||||||
|
<form id="formId">
|
||||||
|
<div class="select-list">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<label>应用:</label>
|
||||||
|
<select name="appName">
|
||||||
|
<option value="">全部</option>
|
||||||
|
<option value="黑猫搞定逾期">黑猫搞定逾期</option>
|
||||||
|
<option value="大象债务处理">大象债务处理</option>
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label>来源:</label>
|
||||||
|
<select name="appSource">
|
||||||
|
<option value="">全部</option>
|
||||||
|
<option value="1">OPPO</option>
|
||||||
|
<option value="2">vivo</option>
|
||||||
|
<option value="3">华为</option>
|
||||||
|
<option value="4">小米</option>
|
||||||
|
<option value="5">应用宝</option>
|
||||||
|
<option value="6">百度</option>
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label>开始日期:</label>
|
||||||
|
<input type="date" name="startDate"/>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label>结束日期:</label>
|
||||||
|
<input type="date" name="endDate"/>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i> 搜索</a>
|
||||||
|
<a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i> 重置</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 select-table table-striped">
|
||||||
|
<table id="bootstrap-table"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div id="summary" style="padding:10px"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<th:block th:include="include :: footer" />
|
||||||
|
<script th:inline="javascript">
|
||||||
|
var prefix = ctx + "system/material/stats";
|
||||||
|
$(function() {
|
||||||
|
var options = {
|
||||||
|
url: prefix + "/list",
|
||||||
|
modalName: "素材转化统计",
|
||||||
|
columns: [
|
||||||
|
{ field: 'statDate', title: '日期' },
|
||||||
|
{ field: 'appName', title: '应用' },
|
||||||
|
{ field: 'appSource', title: '来源' },
|
||||||
|
{ field: 'title', title: '标题' },
|
||||||
|
{ field: 'labels', title: '标签' },
|
||||||
|
{ field: 'clickCnt', title: '点击数' },
|
||||||
|
{ field: 'submitCnt', title: '提交数' },
|
||||||
|
{ field: 'conversionRate', title: '转化率(%)' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
$.table.init(options);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<MaterialStatsDaily> 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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.ruoyi.system.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.ruoyi.system.domain.MaterialStatsDaily;
|
||||||
|
|
||||||
|
public interface IMaterialStatsDailyService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 按条件查询统计列表
|
||||||
|
*/
|
||||||
|
List<MaterialStatsDaily> selectStats(String appName, String appSource, String startDate, String endDate);
|
||||||
|
}
|
||||||
|
|
@ -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<MaterialStatsDaily> selectStats(String appName, String appSource, String startDate, String endDate)
|
||||||
|
{
|
||||||
|
return statsMapper.selectList(appName, appSource, startDate, endDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.ruoyi.system.mapper.MaterialStatsDailyMapper">
|
||||||
|
|
||||||
|
<!-- 插入或更新日统计数据(已废弃,仅保留兼容,改为简单插入) -->
|
||||||
|
<insert id="insertOrUpdate" parameterType="com.ruoyi.system.domain.MaterialStatsDaily">
|
||||||
|
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>
|
||||||
|
|
||||||
|
<!-- 按条件查询统计列表(区间聚合) -->
|
||||||
|
<select id="selectList" resultType="com.ruoyi.system.domain.MaterialStatsDaily">
|
||||||
|
SELECT
|
||||||
|
stat_date AS statDate,
|
||||||
|
app_name AS appName,
|
||||||
|
app_source AS appSource,
|
||||||
|
title,
|
||||||
|
labels,
|
||||||
|
SUM(click_cnt) AS clickCnt,
|
||||||
|
SUM(submit_cnt) AS submitCnt,
|
||||||
|
CASE WHEN SUM(click_cnt) > 0 THEN ROUND(SUM(submit_cnt) * 100.0 / SUM(click_cnt), 2) ELSE 0.00 END AS conversionRate
|
||||||
|
FROM material_stats_daily
|
||||||
|
<where>
|
||||||
|
<if test="appName != null and appName != ''"> AND app_name = #{appName} </if>
|
||||||
|
<if test="appSource != null and appSource != ''"> AND app_source = #{appSource} </if>
|
||||||
|
<if test="startDate != null and startDate != ''"> AND stat_date >= #{startDate} </if>
|
||||||
|
<if test="endDate != null and endDate != ''"> AND stat_date <= #{endDate} </if>
|
||||||
|
</where>
|
||||||
|
GROUP BY stat_date, app_name, app_source, title, labels
|
||||||
|
ORDER BY stat_date DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 点击事件:每次插入一条记录 -->
|
||||||
|
<insert id="incrClick">
|
||||||
|
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>
|
||||||
|
|
||||||
|
<!-- 提交事件:每次插入一条记录 -->
|
||||||
|
<insert id="incrSubmit">
|
||||||
|
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)
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
|
@ -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)计算转化率
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- 在clew_material表中增加点击数字段
|
||||||
|
ALTER TABLE clew_material ADD COLUMN click_count INT DEFAULT 0 COMMENT '点击次数' AFTER apply_num;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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 |
|
||||||
Loading…
Reference in New Issue