Commit 3d37542f authored by Hsinli's avatar Hsinli

Merge branch 'master' of t-git.51gjj.com:fangbin/51business

parents b93f9b76 beb64607
Pipeline #8796 passed with stage
in 12 seconds
......@@ -3,30 +3,32 @@
const Controller = require('egg').Controller;
class ProductController extends Controller {
// 筛选项列表
async getOptionProducts() {
// 筛选项列表
async getOptionProducts() {
const { ctx } = this;
const type = ctx.params.type || 'credit';
const { ctx } = this;
const type = ctx.params.type || 'credit';
const keys = ctx.query.keys ? eval(ctx.query.keys) : [];
const results = await ctx.service.gjj.product.getRecommendOptions(type, keys);
let suit_options;
let credit_loans = [];
let common_loans = [];
let common_credits = [];
if (type == 'loan') {
suit_options = await ctx.service.gjj.product.getLoanChannelSuitOptions();
if (suit_options) {
results.unshift(suit_options);
}
credit_loans = await ctx.service.gjj.product.getAllProductsByType(1);
common_loans = await ctx.service.gjj.product.getAllProductsByType(4);
} else {
common_credits = await ctx.service.gjj.product.getAllProductsByType(3);
}
ctx.success({ results: results, credit_loans: credit_loans, common_loans: common_loans, common_credits: common_credits });
const keys = ctx.query.keys ? ctx.query.keys.split(',') : [];
const results = await ctx.service.gjj.product.getRecommendOptions(type, keys);
let suit_options;
let credit_loans = [];
let common_loans = [];
let common_credits = [];
let credit_cards = [];
if (type === 'loan') {
suit_options = await ctx.service.gjj.product.getLoanChannelSuitOptions();
if (suit_options) {
results.unshift(suit_options);
}
credit_loans = await ctx.service.gjj.product.getAllProductsByType(1);
common_loans = await ctx.service.gjj.product.getAllProductsByType(4);
} else {
credit_cards = await ctx.service.gjj.product.getAllProductsByType(2);
common_credits = await ctx.service.gjj.product.getAllProductsByType(3);
}
ctx.success({ results, credit_loans, common_loans, common_credits, credit_cards });
}
}
module.exports = ProductController;
......@@ -39,6 +39,36 @@ module.exports = {
}
},
isEmpty(data) {
const type = typeof (data);
let ret = false;
switch (type) {
case 'undefined':
ret = true;
break;
case 'string':
ret = !(data.length > 0);
break;
case 'number':
ret = !(data > 0);
break;
case 'boolean':
ret = false;
break;
case 'object':
// 判断是否为数组
if (data instanceof Array) {
ret = !(data.length > 0);
} else {
ret = JSON.stringify(data) === '{}' || !data;
}
break;
default:
break;
}
return ret;
},
login(params) {
const { cookies, session } = this;
const moment = require('moment');
......
......@@ -4,6 +4,6 @@ module.exports = app => {
const router = app.router.namespace(app.config.projectRootPath + '/product');
router.get('/recommend/channel/options/:type', 'gjj.product.getOptionProducts');//
router.get('third_options', '/recommend/channel/options/:type', 'gjj.product.getOptionProducts');//
};
'use strict';
const Service = require('egg').Service;
const R = require('ramda')
const R = require('ramda');
class ProductService extends Service {
//通过 type=loan/credit 频道 option_ids 筛选项数组 all_product_ids
// async getProductsByOptions(option_ids, all_product_ids = []) {
// const { ctx } = this;
// if (!Array.isArray(option_ids) || !option_ids || option_ids.length === 0) {
// return all_product_ids;
// }
// let product_ids = all_product_ids;
// for (let i in option_ids) {
// const option_id = option_ids[i];
// const products = await ctx.service.RecommendChannelProduct.all({ where: { option_id: option_id } });
// if (!products || products.length === 0 || Object.keys(products).length === 0) {
// continue;
// }
// const recommend_product_ids = R.pluck(products, 'product_id');
// product_ids = R.intersection(product_ids, recommend_product_ids);
// }
// return product_ids;
// }
//获取筛选项列表 带 product_id
//return : [{"id":3,"title":"银行分类","description":"信用卡银行分类","_children":[{"id":12,"title":"招商银行","quality":["1"],"normal":["1"]},{"id":16,"title":"广发银行","quality":[],"normal":[]}]},{"id":4,"title":"主题分类","description":"信用卡主题分类","_children":[]},{"id":5,"title":"信用卡筛选项","description":"信用卡筛选项","_children":[]}]
async getRecommendOptions(type = 'credit', keys = []) {
const { ctx } = this;
// const type = 'credit';
// keys = ['loan_organization', 'loan_filter', 'credit_bank', 'credit_theme', 'credit_filter'];
// console.info(keys);
let classifies = await ctx.blockModel.RecommendChannelClassify.all({ where: { type: type, valid: 1, key: { $in: keys } } });
// return classifies;
classifies = R.project(['id', 'key', 'title', 'description'])(classifies);
const classify_ids = R.pluck('id', classifies);
let options = await ctx.blockModel.RecommendChannelOption.all({ where: { classify_id: { $in: classify_ids }, status: 'online', valid: 1 }, order: [['order', 'asc']] });
options = R.project(['id', 'title', 'classify_id'])(options);
const option_ids = R.pluck('id', options);
let option_products = await ctx.blockModel.RecommendChannelProduct.all({ where: { option_id: { $in: option_ids }, valid: 1 }, order: [['order', 'asc']] });
option_products = R.project(['option_id', 'product_id', 'type'])(option_products);
let ret = [];
for (let i in classifies) {
let classify = classifies[i];
const classify_id = classify.id;
let temp_options = options.filter(option => parseInt(option.classify_id) === parseInt(classify_id));
temp_options = R.project(['id', 'title'])(temp_options);
for (let j in temp_options) {
let temp_option = temp_options[j];
const temp_option_id = temp_option.id;
let temp_option_products = option_products.filter(v => parseInt(v.option_id) === parseInt(temp_option_id));
temp_option_products = R.groupBy(v => { return v.type === 'quality' ? 'quality' : 'normal' })(temp_option_products);
const quality_product_ids = R.pluck('product_id', temp_option_products.quality ? temp_option_products.quality : []);
const normal_product_ids = R.pluck('product_id', temp_option_products.normal ? temp_option_products.normal : []);
temp_options[j].quality = quality_product_ids;
temp_options[j].normal = normal_product_ids;
}
// 通过 type=loan/credit 频道 option_ids 筛选项数组 all_product_ids
// async getProductsByOptions(option_ids, all_product_ids = []) {
classify._children = temp_options;
ret.push(classify);
}
// const { ctx } = this;
// if (!Array.isArray(option_ids) || !option_ids || option_ids.length === 0) {
// return all_product_ids;
// }
// let product_ids = all_product_ids;
// for (let i in option_ids) {
// const option_id = option_ids[i];
// const products = await ctx.service.RecommendChannelProduct.all({ where: { option_id: option_id } });
// if (!products || products.length === 0 || Object.keys(products).length === 0) {
// continue;
// }
// const recommend_product_ids = R.pluck(products, 'product_id');
// product_ids = R.intersection(product_ids, recommend_product_ids);
// }
// return product_ids;
// }
// 获取筛选项列表 带 product_id
// return : [{"id":3,"title":"银行分类","description":"信用卡银行分类","_children":[{"id":12,"title":"招商银行","quality":["1"],"normal":["1"]},{"id":16,"title":"广发银行","quality":[],"normal":[]}]},{"id":4,"title":"主题分类","description":"信用卡主题分类","_children":[]},{"id":5,"title":"信用卡筛选项","description":"信用卡筛选项","_children":[]}]
async getRecommendOptions(type = 'credit', keys = []) {
const { ctx } = this;
// const type = 'credit';
// keys = ['loan_organization', 'loan_filter', 'credit_bank', 'credit_theme', 'credit_filter'];
// console.info(keys);
let classifies = await ctx.blockModel.RecommendChannelClassify.all({ where: { type, valid: 1, key: { $in: keys } } });
// return classifies;
classifies = R.project([ 'id', 'key', 'title', 'description' ])(classifies);
const classify_ids = R.pluck('id', classifies);
let options = await ctx.blockModel.RecommendChannelOption.all({ where: { classify_id: { $in: classify_ids }, status: 'online', valid: 1 }, order: [[ 'order', 'asc' ]] });
options = R.project([ 'id', 'title', 'classify_id' ])(options);
const option_ids = R.pluck('id', options);
let option_products = await ctx.blockModel.RecommendChannelProduct.all({ where: { option_id: { $in: option_ids }, valid: 1 }, order: [[ 'order', 'asc' ]] });
option_products = R.project([ 'option_id', 'product_id', 'type' ])(option_products);
const ret = [];
for (const i in classifies) {
const classify = classifies[i];
const classify_id = classify.id;
let temp_options = options.filter(option => parseInt(option.classify_id) === parseInt(classify_id));
temp_options = R.project([ 'id', 'title' ])(temp_options);
for (const j in temp_options) {
const temp_option = temp_options[j];
const temp_option_id = temp_option.id;
let temp_option_products = option_products.filter(v => parseInt(v.option_id) === parseInt(temp_option_id));
temp_option_products = R.groupBy(v => { return v.type === 'quality' ? 'quality' : 'normal'; })(temp_option_products);
const quality_product_ids = R.pluck('product_id', temp_option_products.quality ? temp_option_products.quality : []);
const normal_product_ids = R.pluck('product_id', temp_option_products.normal ? temp_option_products.normal : []);
temp_options[j].quality = quality_product_ids;
temp_options[j].normal = normal_product_ids;
}
return ret;
classify._children = temp_options;
ret.push(classify);
}
//
async getLoanChannelSuitOptions() {
const { ctx } = this;
const user_id = ctx.userId;
const app_user_id = ctx.appUserId;
const credit_loans = await this.getAllProductsByType(1);
const common_loans = await this.getAllProductsByType(4);
const credit_loans_ids = R.pluck('business_id', credit_loans);
const common_loans_ids = R.pluck('business_id', common_loans);
const default_options = {
id: -1,
key: 'loan_all',
title: '全部',
description: '全部',
_children: [],
}
let children = [{ id: -2, title: '全部', quality: credit_loans_ids, normal: common_loans_ids, }];
if (user_id && app_user_id) {
children.push({
id: -3,
title: '最适合您的',
quality: [7, 8, 29],//TODO
normal: [],
});
return ret;
}
} else {
children.push({
id: -4,
title: '51公积金贷',
quality: credit_loans_ids,
normal: [],
});
children.push({
id: -5,
title: '普通贷',
quality: [],
normal: common_loans_ids,
});
//
async getLoanChannelSuitOptions() {
const { ctx } = this;
const user_id = ctx.userId;
const app_user_id = ctx.appUserId;
const credit_loans = await this.getAllProductsByType(1);
const common_loans = await this.getAllProductsByType(4);
const credit_loans_ids = R.pluck('business_id', credit_loans);
const common_loans_ids = R.pluck('business_id', common_loans);
const default_options = {
id: -1,
key: 'loan_all',
title: '全部',
description: '全部',
_children: [],
};
const children = [{ id: -2, title: '全部', quality: credit_loans_ids, normal: common_loans_ids }];
if (user_id && app_user_id) {
children.push({
id: -3,
title: '最适合您的',
quality: [ 7, 8, 29 ], // TODO
normal: [],
});
} else {
children.push({
id: -4,
title: '51公积金贷',
quality: credit_loans_ids,
normal: [],
});
children.push({
id: -5,
title: '普通贷',
quality: [],
normal: common_loans_ids,
});
}
default_options._children = children;
return default_options;
}
// 1 授信贷;2 信用卡;3 普通信用卡;4 普通贷款
async getAllProductsByType(type) {
const { ctx } = this;
const url = this.config.NODE_BASE_URL + '/cassandra-server/bu_basic/list?type=' + type;
const products_results = await ctx.helper.send_request(url, {}, { method: 'GET' });
//ctx.logger.info(JSON.stringify({ url, products_results }));
if (type !== 1) {
console.log(products_results.data.ret);
}
let products = [];
if (products_results.status !== 200 || !products_results.data || !products_results.data.ret) {
return products;
}
products = products_results.data.ret;
return products;
}
// 最适合您的(推荐)贷款
async getSuitLoans() {
const ret = await this.getBusinessRecommendList();
return ret;
}
// 获取用户贷款分组
async getBusinessClassList() {
const { ctx } = this;
const userId = '58f1af6b-9018-4d69-b839-a26aaa368445';
const appUserId = '9CEB848A-2F87-4C5F-A50A-D65882C04CA6';
const url = ctx.app.config.NODE_BASE_URL + '/cassandra-server/loan_list/bu_class/list';
const param = { uid: userId, app_uid: appUserId };
const resp = await ctx.helper.send_request(url, param, { method: 'GET' });
if (resp.status !== 200) {
ctx.failed('[bu_class]内部接口错误');
}
return resp.data.ret;
}
// 获取用户贷款通过率
async getBusinessPassRate(businessList) {
const { ctx } = this;
const userId = '58f1af6b-9018-4d69-b839-a26aaa368445';
const appUserId = '9CEB848A-2F87-4C5F-A50A-D65882C04CA6';
const url = ctx.app.config.NODE_BASE_URL + '/cassandra-server/loan_list/recommend_sort/list';
const param = { uid: userId, app_uid: appUserId, business_arr: businessList };
// 判断列表是否为空
if (businessList.length === 0) {
return [];
}
const resp = await ctx.helper.send_request(url, param, { method: 'POST' });
if (resp.status !== 201) {
ctx.failed('[recommend_sort]内部接口错误');
}
return resp.data.ret;
}
// 获取普通贷款
async getCommonBusinessList() {
const { ctx } = this;
const url = ctx.app.config.NODE_BASE_URL + '/cassandra-server/bu_basic/list';
const param = { type: 3 };
const resp = await ctx.helper.send_request(url, param, { method: 'GET' });
if (resp.status !== 200) {
ctx.failed('[bu_basic]内部接口错误');
}
return resp.data.ret;
}
// 获取推荐列表,按照ABC分组顺序推荐
async getBusinessRecommendList() {
const { ctx, service } = this;
const userId = ctx.userId;
const R = require('ramda');
const limit = 10;
const recommendSort = function(a, b) {
return a.recommend_sorter - b.recommend_sorter;
};
let ret = [];
// 如果未登录,则推荐普通贷款
if (ctx.isEmpty(userId)) {
const commonLoanList = await this.getCommonBusinessList();
ret = this.formatLoanList(R.take(limit)(R.sort(recommendSort)(commonLoanList)));
} else {
// 先获取分组
const classList = await this.getBusinessClassList();
let result = [];
// 先取A
if (classList.hasOwnProperty('class_A') && !ctx.isEmpty(classList.class_A)) {
result = R.take(limit)(R.sort(recommendSort)(classList.class_A));
result = R.map(function(e) {
e.class = 'A';
e.rule = 2;
return e;
})(result);
}
// 再取B
if (classList.hasOwnProperty('class_B') && !ctx.isEmpty(classList.class_B)) {
let classB = R.take(limit - result.length)(R.sort(recommendSort)(classList.class_B));
classB = R.map(function(e) {
e.class = 'B';
e.rule = 2;
return e;
})(classB);
result = R.insertAll(result.length, classB)(result);
}
// 如果数量不够,再取C
if (result.length < limit) {
// 判断C组是否有值
if (classList.hasOwnProperty('class_C') && !ctx.isEmpty(classList.class_C)) {
// 获取开关状态,判断是自动推荐or手动推荐orABTest
const rule = 1;
// 是否需要计算模型
let isNeedCalc = false;
let userInfo = {};
switch (rule) {
case 1:
isNeedCalc = true;
break;
case 2:
isNeedCalc = false;
classList.class_C = R.map(function(e) {
e.class = 'C';
e.rule = rule;
e.hasPassRate = 0;
e.needCalc = 0;
return e;
})(classList.class_C);
break;
case 3:
// 获取不到手机号则默认使用手动推荐
isNeedCalc = false;
// 获取用户手机号,根据手机号末尾判断是否自动推荐
userInfo = await service.user.get_user(ctx.appUserId);
if (!ctx.isEmpty(userInfo) && !ctx.isEmpty(userInfo.user) && !ctx.isEmpty(userInfo.user.phone) && (Number(userInfo.user.phone) % 2 === 0)) {
isNeedCalc = true;
} else {
classList.class_C = R.map(function(e) {
e.class = 'C';
e.rule = rule;
e.hasPassRate = 0;
e.needCalc = 0;
return e;
})(classList.class_C);
}
break;
default:
break;
}
if (isNeedCalc) {
const businessArr = R.pluck('business_id')(classList.class_C);
const passRateList = await this.getBusinessPassRate(businessArr);
if (!ctx.isEmpty(passRateList)) {
classList.class_C = R.map(function(e) {
e.class = 'C';
e.rule = rule;
e.hasPassRate = 0;
e.needCalc = 1;
e.pass_rate = 0;
return e;
})(classList.class_C);
for (const v of passRateList) {
for (let i = 0; i < classList.class_C.length; i++) {
if (Number(classList.class_C[i].business_id) === Number(v.business_id)) {
classList.class_C[i].pass_rate = v.pass_rate;
classList.class_C[i].hasPassRate = 1;// 是否有通过率返回值
break;
}
}
}
// 根据通过率降序排序
const passRateSort = function(a, b) {
return b.pass_rate - a.pass_rate;
};
classList.class_C = R.sort(passRateSort)(classList.class_C);
} else {
// 模型计算参数不够,仍然采用手动推荐
classList.class_C = R.map(function(e) {
e.class = 'C';
e.rule = rule;
e.hasPassRate = 0;
e.needCalc = 1;
return e;
})(classList.class_C);
isNeedCalc = false;
}
}
if (!isNeedCalc) {
const tmp = R.sort(recommendSort)(classList.class_C);
classList.class_C = tmp;
}
}
default_options._children = children;
}
return default_options;
result = R.insertAll(result.length, R.take(limit - result.length)(classList.class_C))(result);
ret = await this.formatLoanList(result);
}
//1 授信贷;2 信用卡;3 普通信用卡;4 普通贷款
async getAllProductsByType(type, elements = ['business_id', 'logo', 'url', 'name', 'alias', 'rate', 'rate_title', 'min_amount', 'max_amount','feature','abridge_desc','recommend_sorter']) {
return ret;
}
const { ctx } = this;
const url = this.config.NODE_BASE_URL + '/cassandra-server/bu_basic/list?type=' + type;
let products_results = await ctx.helper.send_request(url, {}, { method: 'GET' });
ctx.logger.info(JSON.stringify({ url: url, products_results: products_results }));
let products = [];
if (products_results.status !== 200 || !products_results.data || !products_results.data.ret) {
return products;
async formatLoanList(loanList) {
const ret = [];
for (const v of loanList) {
// 处理C组
let url = v.url;
if (v.hasOwnProperty('class')) {
if (url.includes('?')) {
url = url + '&class=' + v.class + '&rule=' + String(v.rule);
} else {
url = url + '?class=' + v.class + '&rule=' + String(v.rule);
}
products = products_results.data.ret;
if (elements && elements.length !== 0) {
products = R.project(elements)(products);
if (v.class === 'C') {
url = url + '&hasPassRate=' + String(v.hasPassRate) + '&needCalc=' + String(v.needCalc) + '&passRate=' + String(v.pass_rate);
}
}
const tmp = {
type: v.type,
business_id: v.business_id,
name: v.name,
logo: v.logo,
alias: v.alias,
rate_title: v.rate_title,
rate: v.rate,
min_amount: v.min_amount,
max_amount: v.max_amount,
sort: v.recommend_sorter,
state: v.state,
url,
business_notice: v.business_notice,
feature: v.feature,
abridge_desc: v.abridge_desc,
};
ret.push(tmp);
}
return ret;
}
return products;
async formatProducts(products) {
const ret = [];
for (const v of products) {
const rate = v.rate.includes('元') ? v.rate : v.rate + '%';
const channel_rate = v.channel_rate.includes('元') ? v.channel_rate : v.channel_rate + '%';
let url = v.url;
if (Number(v.type) === 4) {
url = url.includes('?') ? url + '&from=51gjj_loan_channel' : url + '?from=51gjj_loan_channel';
}
url = this.config.PHP_URL + '/app/track/url?url=' + encodeURI(url) + '&source=51gjj&location=loan_channel';
const tmp = {
type: v.type,
business_id: v.business_id,
name: v.name,
logo: v.logo,
alias: v.alias,
rate_title: v.rate_title,
rate: v.rate,
min_amount: v.min_amount,
max_amount: v.max_amount,
sort: v.recommend_sorter,
state: v.state,
url,
business_notice: v.business_notice,
feature: v.feature,
abridge_desc: v.abridge_desc,
};
ret.push(tmp);
}
return ret;
}
}
module.exports = ProductService;
......@@ -90,13 +90,13 @@ module.exports = appInfo => {
};
config.PHP_URL = 'https://kaifa.jianbing.com';
config.NODE_URL = 'https://dev-nginx.jianbing.com/user_api/v1';
config.NODE_BASE_URL = 'https://dev-nginx.jianbing.com';
config.NODE_URL = 'https://uat-nginx.jianbing.com/user_api/v1';
config.NODE_BASE_URL = 'https://uat-nginx.jianbing.com';
config.HOUSE_SERVICE_API = 'https://uat-nginx.jianbing.com/house-service';
config.CDN_BASE_URL = 'https://r.51gjj.com/image/';
config.USER_CENTER_API_URI = 'https://dev-nginx.jianbing.com/usercenter-service';
config.USER_CENTER_API_URI = 'https://uat-nginx.jianbing.com/usercenter-service';
return config;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment