风控 e-charts分析

master
james.zhao 6 years ago
parent 799cc6da48
commit d643f8cea7

@ -38,6 +38,10 @@ public interface TransactionMapper {
@AdvanceSelect(addonWhereClause = "refund_id is null and system_generate=0 and transaction_type = 'Credit'") @AdvanceSelect(addonWhereClause = "refund_id is null and system_generate=0 and transaction_type = 'Credit'")
JSONObject findIncomeByOrderId(@Param("order_id") String orderId); JSONObject findIncomeByOrderId(@Param("order_id") String orderId);
@AutoSql(type = SqlType.SELECT)
@AdvanceSelect(addonWhereClause = "transaction_type = 'Credit'")
JSONObject findByOrderId(@Param("order_id") String orderId);
@AutoSql(type = SqlType.SELECT) @AutoSql(type = SqlType.SELECT)
@AdvanceSelect(addonWhereClause = "refund_id is null and system_generate=1") @AdvanceSelect(addonWhereClause = "refund_id is null and system_generate=1")
JSONObject findSystemIncomeByOrderId(@Param("order_id") String orderId); JSONObject findSystemIncomeByOrderId(@Param("order_id") String orderId);

@ -28,6 +28,10 @@ public interface RiskEventMapper {
PageList<JSONObject> listRisksByPage(JSONObject params, PageBounds pageBounds); PageList<JSONObject> listRisksByPage(JSONObject params, PageBounds pageBounds);
List<JSONObject> analysisByIndustry(JSONObject params);
List<JSONObject> analysisByAmount(JSONObject params);
@AutoSql(type = SqlType.SELECT) @AutoSql(type = SqlType.SELECT)
JSONObject findById(@Param("risk_id") String riskId); JSONObject findById(@Param("risk_id") String riskId);

@ -0,0 +1,16 @@
package au.com.royalpay.payment.manage.mappers.riskbusiness;
import cn.yixblog.support.mybatis.autosql.annotations.AutoMapper;
import cn.yixblog.support.mybatis.autosql.annotations.AutoSql;
import cn.yixblog.support.mybatis.autosql.annotations.SqlType;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.annotations.Param;
@AutoMapper(tablename = "risk_orders", pkName = "risk_order_id")
public interface RiskOrdersMapper {
@AutoSql(type= SqlType.INSERT)
void save(JSONObject params);
@AutoSql(type = SqlType.DELETE)
void clearOrders(@Param("risk_id") String riskId);
}

@ -38,9 +38,17 @@ public class RiskEventQuery {
// 收到调单邮件日期 // 收到调单邮件日期
private String receiveEmailDate; private String receiveEmailDate;
private String receiveEmailDateBegin;
private String receiveEmailDateEnd;
// 邮件回复截止日期 // 邮件回复截止日期
private String replyEmailDate; private String replyEmailDate;
private String replyEmailDateBegin;
private String replyEmailDateEnd;
private Integer page = 1; private Integer page = 1;
// 金额区间 // 金额区间
@ -135,6 +143,38 @@ public class RiskEventQuery {
this.replyEmailDate = replyEmailDate; this.replyEmailDate = replyEmailDate;
} }
public String getReceiveEmailDateBegin() {
return receiveEmailDateBegin;
}
public void setReceiveEmailDateBegin(String receiveEmailDateBegin) {
this.receiveEmailDateBegin = receiveEmailDateBegin;
}
public String getReceiveEmailDateEnd() {
return receiveEmailDateEnd;
}
public void setReceiveEmailDateEnd(String receiveEmailDateEnd) {
this.receiveEmailDateEnd = receiveEmailDateEnd;
}
public String getReplyEmailDateBegin() {
return replyEmailDateBegin;
}
public void setReplyEmailDateBegin(String replyEmailDateBegin) {
this.replyEmailDateBegin = replyEmailDateBegin;
}
public String getReplyEmailDateEnd() {
return replyEmailDateEnd;
}
public void setReplyEmailDateEnd(String replyEmailDateEnd) {
this.replyEmailDateEnd = replyEmailDateEnd;
}
public Integer getPage() { public Integer getPage() {
return page; return page;
} }
@ -184,6 +224,22 @@ public class RiskEventQuery {
params.put("reply_email_date", replyEmailDate); params.put("reply_email_date", replyEmailDate);
} }
if (receiveEmailDateBegin != null) {
params.put("receive_email_date_begin", receiveEmailDateBegin);
}
if (receiveEmailDateEnd != null) {
params.put("receive_email_date_end", receiveEmailDateEnd);
}
if (replyEmailDateBegin != null) {
params.put("reply_email_date_begin", replyEmailDateBegin);
}
if (replyEmailDateEnd != null) {
params.put("reply_email_date_end", replyEmailDateEnd);
}
if (page != null && page > 0) { if (page != null && page > 0) {
params.put("page", page); params.put("page", page);
} }

@ -27,6 +27,20 @@ public interface RiskBusinessService {
*/ */
JSONObject getRiskEventsByPage(JSONObject params, JSONObject manager); JSONObject getRiskEventsByPage(JSONObject params, JSONObject manager);
/**
*
* @param params
* @return
*/
List<JSONObject> analysisByIndustry(JSONObject params, JSONObject manager);
/**
*
* @param params
* @return
*/
List<JSONObject> analysisByAmount(JSONObject params, JSONObject manager);
/** /**
* *
* @param riskId * @param riskId
@ -115,4 +129,6 @@ public interface RiskBusinessService {
JSONObject riskEventMaterialPass(JSONObject params, JSONObject manager); JSONObject riskEventMaterialPass(JSONObject params, JSONObject manager);
JSONObject updateIsSendClient(String riskId); JSONObject updateIsSendClient(String riskId);
void completeOrderAmount();
} }

@ -10,6 +10,7 @@ import au.com.royalpay.payment.manage.mappers.payment.TransactionMapper;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskEventMapper; import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskEventMapper;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskFileMapper; import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskFileMapper;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskMaterialMapper; import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskMaterialMapper;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskOrdersMapper;
import au.com.royalpay.payment.manage.mappers.system.ClientDeviceTokenMapper; import au.com.royalpay.payment.manage.mappers.system.ClientDeviceTokenMapper;
import au.com.royalpay.payment.manage.mappers.system.ClientMapper; import au.com.royalpay.payment.manage.mappers.system.ClientMapper;
import au.com.royalpay.payment.manage.mappers.system.ClientBDMapper; import au.com.royalpay.payment.manage.mappers.system.ClientBDMapper;
@ -107,6 +108,8 @@ public class RiskBusinessServiceImpl implements RiskBusinessService, ManagerTodo
@Resource @Resource
private RiskFileMapper riskFileMapper; private RiskFileMapper riskFileMapper;
@Resource @Resource
private RiskOrdersMapper riskOrdersMapper;
@Resource
private ClientDeviceTokenMapper clientDeviceTokenMapper; private ClientDeviceTokenMapper clientDeviceTokenMapper;
@Resource @Resource
private AppMessageLogMapper appMessageLogMapper; private AppMessageLogMapper appMessageLogMapper;
@ -179,6 +182,49 @@ public class RiskBusinessServiceImpl implements RiskBusinessService, ManagerTodo
return PageListUtils.buildPageListResult(riskEvents); return PageListUtils.buildPageListResult(riskEvents);
} }
@Override
public List<JSONObject> analysisByIndustry(JSONObject params, JSONObject manager) {
List<JSONObject> industryAnalysis = riskEventMapper.analysisByIndustry(params);
for(JSONObject industry:industryAnalysis){
if(StringUtils.isBlank(industry.getString("industry"))){
industry.put("industry","未知行业");
}
}
return industryAnalysis;
}
private List<String> industryArray(){
List<String> industryArray = new ArrayList<>();
industryArray.add("鞋包服饰");
industryArray.add("机票行业");
industryArray.add("软件服务");
industryArray.add("旅游票务");
industryArray.add("国际租车");
industryArray.add("医疗服务(出国)");
industryArray.add("医疗服务(不出国)");
industryArray.add("留学教育(网络教育)");
industryArray.add("留学教育(一年及以下)");
industryArray.add("其它货物贸易行业");
industryArray.add("文具/办公用品");
industryArray.add("综合商城");
industryArray.add("酒店行业");
industryArray.add("教育行业");
industryArray.add("国际物流");
industryArray.add("数码电器");
industryArray.add("母婴");
industryArray.add("化妆品");
industryArray.add("食品");
industryArray.add("留学教育(一年以上)");
industryArray.add("其它服务行业");
industryArray.add("未知行业");
return industryArray;
}
@Override
public List<JSONObject> analysisByAmount(JSONObject params, JSONObject manager) {
return riskEventMapper.analysisByAmount(params);
}
@Override @Override
public JSONObject getRiskEventDetail(String riskId) { public JSONObject getRiskEventDetail(String riskId) {
@ -266,7 +312,7 @@ public class RiskBusinessServiceImpl implements RiskBusinessService, ManagerTodo
// 将订单order_id存入数据库方便后面快速查询 // 将订单order_id存入数据库方便后面快速查询
JSONObject orderInfo = transactionList.get(0); JSONObject orderInfo = transactionList.get(0);
realOrderIdList.add(orderInfo.getString("order_id")); realOrderIdList.add(orderInfo.getString("order_id"));
orderAmountList.add(orderInfo.getString("transaction_amount")); orderAmountList.add(orderInfo.getString("clearing_amount"));
} }
params.put("order_amounts", StringUtils.join(orderAmountList, ",")); params.put("order_amounts", StringUtils.join(orderAmountList, ","));
params.put("real_order_ids", StringUtils.join(realOrderIdList, ",")); params.put("real_order_ids", StringUtils.join(realOrderIdList, ","));
@ -278,6 +324,7 @@ public class RiskBusinessServiceImpl implements RiskBusinessService, ManagerTodo
public void addRiskEvent(JSONObject params, JSONObject manager) { public void addRiskEvent(JSONObject params, JSONObject manager) {
params = getEvent(params); params = getEvent(params);
riskEventMapper.save(params); riskEventMapper.save(params);
setRiskOrders(params);
params = riskEventMapper.findAll(params).get(0); params = riskEventMapper.findAll(params).get(0);
riskProcessLogService.addRiskProcessLog(params.getString("risk_id"), riskProcessLogService.addRiskProcessLog(params.getString("risk_id"),
params.getString("fillin_id"), params.getString("fillin_id"),
@ -287,10 +334,27 @@ public class RiskBusinessServiceImpl implements RiskBusinessService, ManagerTodo
RiskResultTypeEnum.NOT_HANDLED.getResultType()); RiskResultTypeEnum.NOT_HANDLED.getResultType());
} }
private void setRiskOrders(JSONObject params){
if(StringUtils.isNotBlank(params.getString("order_ids"))){
String riskId = params.getString("risk_id");
String orderIds = params.getString("real_order_ids");
for(String orderId : orderIds.split(",")){
JSONObject order = transactionMapper.findByOrderId(orderId);
JSONObject riskOrder = new JSONObject();
riskOrder.put("risk_id",riskId);
riskOrder.put("order_id",orderId);
riskOrder.put("clearing_amount",order.getString("clearing_amount"));
riskOrdersMapper.save(riskOrder);
}
}
}
@Override @Override
public void updateRiskEvent(JSONObject params) { public void updateRiskEvent(JSONObject params) {
params = getEvent(params); params = getEvent(params);
riskEventMapper.update(params); riskEventMapper.update(params);
riskOrdersMapper.clearOrders(params.getString("risk_id"));
setRiskOrders(params);
} }
@Override @Override
@ -930,4 +994,23 @@ public class RiskBusinessServiceImpl implements RiskBusinessService, ManagerTodo
event = riskEventMapper.findById(riskId); event = riskEventMapper.findById(riskId);
return event; return event;
} }
@Override
public void completeOrderAmount() {
List<JSONObject> riskEventList = getRiskEvents(null);
for(JSONObject riskEvent:riskEventList){
if(riskEvent.getIntValue("order_type")==4 || StringUtils.isBlank(riskEvent.getString("real_order_ids"))){
continue;
}
String[] order_ids=riskEvent.getString("real_order_ids").split(",");
for(String orderId : order_ids){
JSONObject transaction = transactionMapper.findByOrderId(orderId);
JSONObject riskOrder = new JSONObject();
riskOrder.put("risk_id",riskEvent.getString("risk_id"));
riskOrder.put("order_id",transaction.getString("order_id"));
riskOrder.put("clearing_amount",transaction.getString("clearing_amount"));
riskOrdersMapper.save(riskOrder);
}
}
}
} }

@ -46,6 +46,18 @@ public class RiskBusinessController {
return riskBusinessService.getRiskEventsByPage(params, manager); return riskBusinessService.getRiskEventsByPage(params, manager);
} }
@GetMapping(value = "events/analysis/industry")
public List<JSONObject> analysisByIndustry(RiskEventQuery riskEventQuery, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
JSONObject params = riskEventQuery.toJSON();
return riskBusinessService.analysisByIndustry(params, manager);
}
@GetMapping(value = "events/analysis/amount")
public List<JSONObject> analysisByAmount(RiskEventQuery riskEventQuery, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
JSONObject params = riskEventQuery.toJSON();
return riskBusinessService.analysisByAmount(params, manager);
}
@GetMapping(value = "events/{risk_id}") @GetMapping(value = "events/{risk_id}")
public JSONObject getRiskEventDetail(@PathVariable("risk_id") String riskId, public JSONObject getRiskEventDetail(@PathVariable("risk_id") String riskId,
@ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) { @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
@ -160,5 +172,11 @@ public class RiskBusinessController {
public JSONObject updateRiskEventIsSendClient(@RequestParam("risk_id") String riskId) { public JSONObject updateRiskEventIsSendClient(@RequestParam("risk_id") String riskId) {
return riskBusinessService.updateIsSendClient(riskId); return riskBusinessService.updateIsSendClient(riskId);
} }
@GetMapping(value = "/complete/event/order_amount")
public String completeOrderAmount() {
riskBusinessService.completeOrderAmount();
return "SUCCESS";
}
} }

@ -33,26 +33,11 @@
LEFT JOIN sys_clients sc LEFT JOIN sys_clients sc
ON re.client_moniker = sc.client_moniker ON re.client_moniker = sc.client_moniker
<if test="start_amount != null || end_amount != null"> <if test="start_amount != null || end_amount != null">
RIGHT JOIN( RIGHT JOIN
SELECT distinct re.risk_id (SELECT DISTINCT(risk_id) FROM risk_orders
FROM WHERE #{start_amount} &lt;= clearing_amount AND #{end_amount} &gt; clearing_amount) ro
risk_event re, ON re.risk_id = ro.risk_id
risk_event_help reh
<where>
reh.risk_event_help_id &lt; (LENGTH(re.order_amounts) - LENGTH(REPLACE(re.order_amounts, ',' , ''))) + 1
<if test="start_amount != null">
AND cast(SUBSTRING_INDEX(SUBSTRING_INDEX(order_amounts,',',reh.risk_event_help_id + 1),',',-1) as signed) &gt;= #{start_amount}
</if>
<if test="end_amount != null">
AND cast(SUBSTRING_INDEX(SUBSTRING_INDEX(order_amounts,',',reh.risk_event_help_id + 1),',',-1) as signed) &lt;= #{end_amount}
</if>
</where>
) temp
on re.risk_id = temp.risk_id
</if> </if>
<if test="bd_id != null"> <if test="bd_id != null">
INNER JOIN( INNER JOIN(
SELECT DISTINCT client_id SELECT DISTINCT client_id
@ -184,25 +169,93 @@
LEFT JOIN sys_clients sc LEFT JOIN sys_clients sc
ON re.client_moniker = sc.client_moniker ON re.client_moniker = sc.client_moniker
<if test="start_amount != null || end_amount != null"> <if test="start_amount != null || end_amount != null">
RIGHT JOIN( RIGHT JOIN
SELECT distinct re.risk_id (SELECT DISTINCT(risk_id) FROM risk_orders
FROM WHERE #{start_amount} &lt;= clearing_amount AND #{end_amount} &gt; clearing_amount) ro
risk_event re, ON re.risk_id = ro.risk_id
risk_event_help reh </if>
<where> <where>
reh.risk_event_help_id &lt; (LENGTH(re.order_amounts) - LENGTH(REPLACE(re.order_amounts, ',' , ''))) + 1 <if test="risk_id != null">
<if test="start_amount != null"> AND re.risk_id = #{risk_id}
AND cast(SUBSTRING_INDEX(SUBSTRING_INDEX(order_amounts,',',reh.risk_event_help_id + 1),',',-1) as signed) &gt;= #{start_amount}
</if> </if>
<if test="end_amount != null"> <if test="client_moniker != null">
AND cast(SUBSTRING_INDEX(SUBSTRING_INDEX(order_amounts,',',reh.risk_event_help_id + 1),',',-1) as signed) &lt;= #{end_amount} AND re.client_moniker = #{client_moniker}
</if>
<if test="is_send_client != null">
AND re.is_send_client = #{is_send_client}
</if>
<if test="order_types != null">
<foreach collection="order_types" item="order_type_item" open="and re.order_type in (" close=")" separator=",">
#{order_type_item}
</foreach>
</if>
<if test="order_type != null">
AND re.order_type = #{order_type}
</if>
<if test="result_types != null">
<foreach collection="result_types" item="result_type_item" open="AND re.result_type IN (" close=")" separator=",">
#{result_type_item}
</foreach>
</if>
<if test="result_type != null">
AND re.result_type = #{result_type}
</if>
<if test="order_ids != null">
AND re.order_ids LIKE CONCAT('%', #{order_ids}, '%')
</if>
<if test="sub_merchant_id != null">
AND sc.sub_merchant_id = #{sub_merchant_id}
</if>
<if test="industry != null">
AND sc.industry = #{industry}
</if> </if>
</where>
) temp <if test="receive_email_date_begin != null">
on re.risk_id = temp.risk_id AND re.receive_email_date &gt;= #{receive_email_date_begin}
</if>
<if test="receive_email_date_end != null">
AND re.receive_email_date &lt;= #{receive_email_date_end}
</if>
<if test="reply_email_date_begin != null">
AND re.reply_email_date &gt;= #{reply_email_date_begin}
</if> </if>
<if test="reply_email_date_end != null">
AND re.reply_email_date &lt;= #{reply_email_date_begin}
</if>
<if test="real_order_ids != null">
AND re.real_order_ids = #{real_order_ids}
</if>
</where>
GROUP BY sc.industry
</select>
<select id="analysisByAmount" resultType="com.alibaba.fastjson.JSONObject">
SELECT
ELT(INTERVAL(ro.clearing_amount,0, 500, 1000, 1500,2000,2500,3000,3500,4000,4500,5000,5500,6000,6500,7000,7500,8000,8500,9000,999999),
'0-500','500-1000','1000-1500','1500-2000','2000-2500','2500-3000','3000-3500','3500-4000','4000-4500','4500-5000','5000-5500','5500-6000',
'6000-6500','6500-7000','7000-7500','7500-8000','8000-8500','8500-9000','>9000') intervals,COUNT(ro.order_id) amount
FROM risk_event re
LEFT JOIN sys_clients sc
ON re.client_moniker = sc.client_moniker
RIGHT JOIN
(SELECT * FROM risk_orders
<if test="start_amount != null || end_amount != null">
WHERE #{start_amount} &lt;= clearing_amount AND #{end_amount} &gt; clearing_amount
</if>
) ro
ON re.risk_id = ro.risk_id
<where> <where>
<if test="risk_id != null"> <if test="risk_id != null">
AND re.risk_id = #{risk_id} AND re.risk_id = #{risk_id}
@ -268,9 +321,9 @@
AND re.real_order_ids = #{real_order_ids} AND re.real_order_ids = #{real_order_ids}
</if> </if>
</where> </where>
GROUP BY sc.industry GROUP BY ELT(INTERVAL(ro.clearing_amount,0, 500, 1000, 1500,2000,2500,3000,3500,4000,4500,5000,5500,6000,6500,7000,7500,8000,8500,9000,999999),
'0-500','500-1000','1000-1500','1500-2000','2000-2500','2500-3000','3000-3500','3500-4000','4000-4500','4500-5000','5000-5500','5500-6000',
'6000-6500','6500-7000','7000-7500','7500-8000','8000-8500','8500-9000','>9000')
ORDER BY intervals
</select> </select>
<!--<select id="analysisByAmount" resultType="com.alibaba.fastjson.JSONObject">-->
<!--</select>-->
</mapper> </mapper>

@ -166,6 +166,10 @@ define(['angular', 'jquery', 'uiRouter', './monitoring/analysis-monitoring'],
$scope.riskEventsByIndustry = resp.data; $scope.riskEventsByIndustry = resp.data;
$scope.risk_industry_chart = chartParser.parse(industryAmount(industries),$scope.riskEventsByIndustry); $scope.risk_industry_chart = chartParser.parse(industryAmount(industries),$scope.riskEventsByIndustry);
}); });
$http.get('/risk/business/events/analysis/amount', {params: params}).then(function (resp) {
$scope.riskEventsByAmount = resp.data;
$scope.risk_amount_chart = chartParser.parse(intervalsAmount(),$scope.riskEventsByAmount);
});
}; };
@ -187,7 +191,7 @@ define(['angular', 'jquery', 'uiRouter', './monitoring/analysis-monitoring'],
basic: { basic: {
name: '风控事件单量', type: 'pie', name: '风控事件单量', type: 'pie',
radius: '80%', radius: '80%',
center: ['50%', '60%'], center: ['50%', '58%'],
label:{ //饼图图形上的文本标签 label:{ //饼图图形上的文本标签
normal:{ normal:{
show:true, show:true,
@ -212,6 +216,50 @@ define(['angular', 'jquery', 'uiRouter', './monitoring/analysis-monitoring'],
} }
}; };
var intervalsAmount = function () {
return {
chart: {
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b} : {c}"
},
// color: colors,
legend: {
orient: 'vertical',
left: 'right',
data: [ '0-500','500-1000','1000-1500','1500-2000','2000-2500','2500-3000','3000-3500','3500-4000','4000-4500','4500-5000','5000-5500','5500-6000',
'6000-6500','6500-7000','7000-7500','7500-8000','8000-8500','8500-9000','>9000']
}
},
series: [{
basic: {
name: '风控事件单量', type: 'pie',
radius: '80%',
center: ['50%', '58%'],
label:{ //饼图图形上的文本标签
normal:{
show:true,
position:'outer', //标签的位置
textStyle : {
fontWeight : 300 ,
fontSize : 16 //文字的字体大小
},
formatter:'{d}%'
}
},
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
},
column: {key: 'amount', name: 'intervals'}
}]
}
};
$scope.loadRiskEvents(1); $scope.loadRiskEvents(1);
} }
]); ]);

@ -303,12 +303,12 @@
<div class="col-sm-6 col-xs-6"> <div class="col-sm-6 col-xs-6">
<p class="text-center">行业占比</p> <p class="text-center">行业占比</p>
<div class="chart" style="height: 400px" echarts="risk_industry_chart" <div class="chart" style="height: 400px" echarts="risk_industry_chart"
ng-class="{nodata:analysis.risk_industry_chart.nodata}"></div> ng-class="{nodata:risk_industry_chart.nodata}"></div>
</div> </div>
<div class="col-sm-6 col-xs-6"> <div class="col-sm-6 col-xs-6">
<p class="text-center">金额分布</p> <p class="text-center">金额分布</p>
<div class="chart" style="height: 250px" echarts="analysis.partners_type_chart" <div class="chart" style="height: 400px" echarts="risk_amount_chart"
ng-class="{nodata:analysis.partners_type_chart.nodata}"></div> ng-class="{nodata:risk_amount_chart.nodata}"></div>
</div> </div>
</div> </div>
</div> </div>

Loading…
Cancel
Save