Commit 6334f89e authored by 姜登's avatar 姜登

yys

parents
'use strict';
module.exports = {
write: true,
prefix: '^',
plugin: 'autod-egg',
test: [
'test',
'benchmark',
],
dep: [
'egg',
'egg-scripts',
],
devdep: [
'egg-ci',
'egg-bin',
'egg-mock',
'autod',
'autod-egg',
'eslint',
'eslint-config-egg',
'webstorm-disable-index',
],
exclude: [
'./test/fixtures',
'./dist',
],
};
{
"extends": [
"eslint-config-egg"
],
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
},
"rules": {
"indent": ["error", 2],
"array-bracket-spacing": ["error", "never"],
"linebreak-style": "off"
}
}
\ No newline at end of file
logs/
npm-debug.log
yarn-error.log
node_modules/
package-lock.json
yarn.lock
coverage/
.idea/
run/
.DS_Store
*.sw*
*.un~
sudo: false
language: node_js
node_js:
- '8'
install:
- npm i npminstall && npminstall
script:
- npm run ci
after_script:
- npminstall codecov && codecov
FROM t-docker.51gjj.com/tools/node:8.12.0
ENV LANG C.UTF-8
ENV NODE_ENV production
ENV PATH $PATH:/usr/local/node/bin/
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/
RUN yarn config set registry "https://registry.npm.taobao.org/"
RUN yarn install
COPY . /usr/src/app
EXPOSE 7001
CMD [ "yarn", "docker" ]
# yys_h5_server
运营商H5认证服务
## QuickStart
<!-- add docs here for user -->
see [egg docs][egg] for more detail.
### Development
```bash
$ npm i
$ npm run dev
$ open http://localhost:7001/
```
### Deploy
```bash
$ npm start
$ npm stop
```
### npm scripts
- Use `npm run lint` to check code style.
- Use `npm test` to run unit test.
- Use `npm run autod` to auto detect dependencies upgrade, see [autod](https://www.npmjs.com/package/autod) for more detail.
[egg]: https://eggjs.org
\ No newline at end of file
# hf_h5_server
公积金H5认证服务
## 快速入门
<!-- 在此次添加使用文档 -->
如需进一步了解,参见 [egg 文档][egg]
### 本地开发
```bash
$ npm i
$ npm run dev
$ open http://localhost:7001/
```
### 部署
```bash
$ npm start
$ npm stop
```
### 单元测试
- [egg-bin] 内置了 [mocha], [thunk-mocha], [power-assert], [istanbul] 等框架,让你可以专注于写单元测试,无需理会配套工具。
- 断言库非常推荐使用 [power-assert]
- 具体参见 [egg 文档 - 单元测试](https://eggjs.org/zh-cn/core/unittest)
### 内置指令
- 使用 `npm run lint` 来做代码风格检查。
- 使用 `npm test` 来执行单元测试。
- 使用 `npm run autod` 来自动检测依赖更新,详细参见 [autod](https://www.npmjs.com/package/autod)
[egg]: https://eggjs.org
'use strict';
const Controller = require('egg').Controller;
class OrderController extends Controller {
constructor(ctx) {
super(ctx);
this.createRule = {
appKey: 'string',
userId: {
type: 'string',
required: false,
},
orderId: {
type: 'string',
required: false,
format: /^(\w{8})-(\w{4})-(\w{4})-(\w{4})-(\w{12})$/,
message: '订单号格式错误',
},
phone: {
type: 'string',
format: /^(((13[0-9]{1})|(14[0-9]{1})|(15[4-9]{1})|(16[0-9]{1})|(17[0-9]{1})|(18[0-9]{1})|(19[0-9]{1}))+\d{8})$/,
message: 'phone格式错误',
required: true,
},
};
this.showRule = {
sign: 'string',
params: {
type: 'object',
rule: {
token: 'string',
orderId: {
type: 'string',
required: false,
},
orderSn: {
type: 'string',
required: false,
},
appKey: 'string',
timestamp: 'string',
},
},
};
this.fetchRule = {
sign: 'string',
params: {
type: 'object',
rule: {
appKey: 'string',
timestamp: 'string',
token: 'string',
},
},
};
}
async create() {
const { ctx, service } = this;
ctx.validate(this.createRule);
const { appKey, userId, notifyUrl, backUrl, orderId, phone } = ctx.request.body;
// const appKeyInfo = await service.partner.fetchInfo(appKey);
// if (!(appKeyInfo && appKeyInfo.valid === true && appKeyInfo.enableYys === true)) {
// return ctx.fail('未开通此服务');
// }
const areaInfo = await service.task.phoneArea(phone);
const object = {
orderId,
userId: userId || '',
notifyUrl: notifyUrl || (ctx.app.notifyMap && ctx.app.notifyMap.get(appKey) && ctx.app.notifyMap.get(appKey).notifyUrl) || '',
backUrl: backUrl || '',
appKey,
status: 'init',
phone,
city: areaInfo.province,
operator: areaInfo.operator,
};
if (orderId) {
await service.order.update(object);
} else {
object.orderId = ctx.helper.getUuid();
await service.order.create(object);
}
ctx.success({ orderId: object.orderId });
}
async show() {
const { ctx, service } = this;
ctx.validate(this.showRule);
const { orderId } = ctx.params;
await service.signature.signatureCheck(ctx.request.body);
const data = await service.order.getOneByOrderId(orderId);
if (data) {
if (data.status === 'success') {
const result = await service.storage.read(orderId);
ctx.success(result);
return;
}
ctx.success({
status: data.status,
});
return;
}
ctx.fail('无此订单号');
}
async partnerShow() {
const { ctx, service } = this;
try {
ctx.validate(this.showRule);
let { appKey, orderId, orderSn } = ctx.request.body.params;
orderId = orderId || orderSn;
await service.signature.signatureCheck(ctx.request.body);
const appKeyInfo = await service.partner.fetchInfo(appKey);
if (!(appKeyInfo && appKeyInfo.valid === true && appKeyInfo.enableHfData === true)) {
return ctx.fail('未开通此服务');
}
const data = await service.order.getOneByOrderId(orderId);
if (data) {
if (data.status === 'success') {
const result = await service.storage.read(orderId, appKey);
ctx.body = {
code: 0,
data: result,
};
return;
}
}
ctx.body = {
code: -1,
msg: '无此订单号',
};
} catch (err) {
ctx.logger.error('partnerShow', JSON.stringify(err));
ctx.error(err);
}
}
async orderShow() {
const { ctx, service } = this;
const { appKey, orderId } = ctx.params;
const appKeyInfo = await service.partner.fetchInfo(appKey);
if (!(appKeyInfo && appKeyInfo.valid === true && appKeyInfo.enableHfView === true)) {
return ctx.fail('未开通此服务');
}
const data = await service.order.getOneByOrderId(orderId);
if (data) {
if (data.status === 'success' && (data.appKey === appKey)) {
const result = await service.storage.read(orderId, appKey);
const ret = service.washData.dealData(result);
ctx.success(ret);
return;
}
}
ctx.fail('无此订单号');
}
async fetchOrderId() {
const { ctx, service } = this;
try {
ctx.validate(this.fetchRule);
const { appKey } = ctx.request.body.params;
const orderId = await service.signature.createOrderId(ctx.request.body);
await service.order.create({
orderId,
notifyUrl: ctx.app.notifyMap.get(appKey) && ctx.app.notifyMap.get(appKey).notifyUrl || '',
appKey,
status: 'init',
});
ctx.body = {
code: 0,
data: {
orderSn: orderId,
},
msg: '',
};
} catch (err) {
ctx.logger.error('fetchOrderId', JSON.stringify(err));
ctx.error(err);
}
}
}
module.exports = OrderController;
'use strict';
const Controller = require('egg').Controller;
class PartnerController extends Controller {
// constructor(ctx) {
// super(ctx);
// }
async show() {
const { ctx, service } = this;
const { appKey } = ctx.params;
const ret = await service.partner.fetchTheme(appKey);
if (ret && ret.appKey === appKey) {
ctx.success(ret);
return;
}
ctx.fail('尚未配置主题');
}
async fetchAgreements() {
const { ctx, service } = this;
const { id } = ctx.params;
const ret = await service.partner.fetchAgreements(id);
if (ret && String(ret.id) === id) {
ctx.success(ret);
return;
}
ctx.fail('未获取到协议');
}
}
module.exports = PartnerController;
'use strict';
const Controller = require('egg').Controller;
class ScriptController extends Controller {
constructor(ctx) {
super(ctx);
this.hubsRule = {
phone: {
type: 'string',
format: /^(((13[0-9]{1})|(14[0-9]{1})|(15[4-9]{1})|(16[0-9]{1})|(17[0-9]{1})|(18[0-9]{1})|(19[0-9]{1}))+\d{8})$/,
message: 'phone格式错误',
required: true,
},
};
}
async fetchScripts() {
const { ctx, service } = this;
const { appKey } = ctx.query;
let limitScriptsList = false;
if (appKey) {
const ret = await service.partner.fetchInfo(appKey);
if (ret) {
limitScriptsList = ret.hfExcludeScripts;
}
}
let data = await service.scripts.fetchScripts();
if (limitScriptsList) {
data = data.filter(item => {
return !(limitScriptsList.includes(item.id));
});
}
ctx.success(data);
}
async fetchOneScripts() {
const { ctx, service } = this;
let { scriptId } = ctx.params;
if (scriptId === 'auto') {
const ret = await service.scripts.fetchScriptIdByIp();
scriptId = ret.scriptId;
}
const data = await service.scripts.fetchOneScripts(scriptId);
ctx.success(data);
}
async fetchParamsInfo() {
const { ctx, service } = this;
const { refresh = false } = ctx.query;
const data = await service.scripts.fetchParams(refresh);
ctx.success(data);
}
async fetchHelpInfo() {
const { ctx, service } = this;
const { scriptId } = ctx.params;
const data = await service.scripts.fetchHelp(scriptId);
ctx.success(data);
}
async fetchQueryButtonInfo() {
const { ctx, service } = this;
const { scriptId } = ctx.params;
const data = await service.scripts.fetchQueryButton(scriptId);
ctx.success(data);
}
async fetchNoticeInfo() {
const { ctx, service } = this;
const { scriptId } = ctx.params;
const data = await service.scripts.fetchNotice(scriptId);
ctx.success(data);
}
async fetchHubSeripts() {
const { ctx, service } = this;
ctx.validate(this.hubsRule, ctx.params);
const { phone } = ctx.params;
const areaInfo = await service.task.phoneArea(phone);
const hubId = await service.scripts.fetchScriptByCityName(areaInfo.province);
let data = await service.scripts.fetchHubSeripts(hubId.hubId);
let result = '';
data = data.filter(item => {
if (item.name === areaInfo.operator) {
result = item;
return false;
}
return true;
});
if (result) {
data.unshift(result);
}
ctx.success(data);
}
}
module.exports = ScriptController;
'use strict';
const Controller = require('egg').Controller;
class TaskController extends Controller {
constructor(ctx) {
super(ctx);
this.createRule = {
orderId: {
type: 'string',
format: /^(\w{8})-(\w{4})-(\w{4})-(\w{4})-(\w{12})$/,
message: 'orderId格式错误',
required: true,
},
scriptId: {
type: 'number',
required: true,
},
};
this.submitRule = {
phone: { type: 'string', format: /^1\d{10}$/, required: false },
ID: { type: 'string', format: /^\d{14}(\d{3})?[\dXx]$/, required: false },
};
this.fetchCaptureRule = {
type: { type: 'enum', values: ['phone_code'] },
};
this.taskIdRule = {
taskId: { type: 'string', format: /\d+/ },
};
this.cityListRule = {
sign: 'string',
params: {
type: 'object',
rule: {
token: 'string',
appKey: 'string',
timestamp: 'string',
},
},
};
}
async create() {
const { ctx, service } = this;
ctx.validate(this.createRule);
const { scriptId, orderId } = ctx.request.body;
const taskId = await service.task.create(scriptId);
await service.order.update({ orderId, cityId: scriptId, taskId });
await service.cache.set({
key: taskId,
value: { status: 'init', note: { message: 'init' } },
});
ctx.success({ taskId });
}
async submit() {
const { ctx, service, config } = this;
ctx.validate(this.submitRule);
const { taskId } = ctx.params;
await service.cache.set({
key: taskId,
value: { status: 'login', note: { message: 'login' } },
});
await service.task.submit({
taskId,
data: ctx.request.body,
callbackUrl: config.callbackUrl,
});
ctx.success({ taskId });
}
async fetchCapture() {
const { ctx, service } = this;
ctx.validate(this.fetchCaptureRule);
const { taskId } = ctx.params;
const { type, data } = ctx.request.body;
const result = await service.task.fetchCapture({
taskId,
type,
data,
});
ctx.success(result);
}
async show() {
const { ctx, service } = this;
ctx.validate(this.taskIdRule, ctx.params);
const { taskId } = ctx.params;
const data = await service.cache.get({ key: taskId });
ctx.success(data);
}
async handleCallback() {
const { ctx, service } = this;
const { taskId } = ctx.request.body;
const result = await service.task.fetchTask({ taskId });
ctx.success();
let taskNote = {
status: 'init',
note: { message: 'init' },
};
switch (result.code) {
case -1:
case 106:
case 102:
case 204:
taskNote = {
status: 'failure',
note: { message: result.msg },
};
break;
case 1:
if (result.data.data) {
result.data = {
data: JSON.parse(JSON.parse(result.data.data).post_data.strForNextStep),
loginParam: result.data.loginParam,
};
}
taskNote = {
status: 'next',
note: { message: 'waiting', nextStep: result.data },
};
break;
case 110:
taskNote = {
status: 'query',
note: { message: 'login success' },
};
break;
case 0:
taskNote = {
status: 'success',
note: { message: 'task success' },
};
try {
const insertData = await service.washData.wash(result);
const order = await service.order.getOneByTaskId(taskId);
if (!order) {
throw new Error('任务已经结束了');
}
const { orderId, appKey } = order;
insertData.orderId = orderId;
insertData.cityName = await service.scripts.fetchScriptName(insertData.cid);
insertData.taskId = taskId;
insertData.appKey = appKey;
delete insertData.code;
await service.storage.write(insertData);
await service.cache.set({
key: taskId,
value: taskNote,
});
await service.partner.notice(order);
return;
} catch (err) {
ctx.logger.error('handleCallback', JSON.stringify(err), JSON.stringify(result));
taskNote = {
status: 'failure',
note: { message: err.message },
};
}
break;
default:
ctx.logger.warn('handleCallback', JSON.stringify(result));
break;
}
await service.cache.set({
key: taskId,
value: taskNote,
});
}
}
module.exports = TaskController;
'use strict';
const Controller = require('egg').Controller;
class TokenController extends Controller {
constructor(ctx) {
super(ctx);
this.createRule = {
sign: 'string',
params: {
type: 'object',
rule: {
appKey: 'string',
timestamp: 'string',
},
},
};
}
async create() {
const { ctx, service } = this;
ctx.validate(this.createRule);
const token = await service.signature.createToken(ctx.request.body);
ctx.success({ data: token });
}
async partnerCreate() {
const { ctx, service } = this;
try {
ctx.validate(this.createRule);
const token = await service.signature.createToken(ctx.request.body);
ctx.body = {
code: 0,
data: { token },
msg: '',
};
} catch (err) {
ctx.logger.error('partnerCreate', JSON.stringify(err));
ctx.error(err);
}
}
}
module.exports = TokenController;
'use strict';
const NODE_CACHE = Symbol('Context#NodeCache');
const NodeCache = require('node-cache');
class Cache {
constructor(app) {
this.app = app;
this.name = 'unknown-cache';
}
async val(key, next, ttl) {
let data = await this.get(key);
if (data) {
return data;
}
data = await next(key);
await this.set(key, data, ttl);
return data;
}
async get(key) {
const startTime = +new Date();
const ret = await this._get(key);
let jsonText = JSON.stringify(ret);
if (jsonText === undefined) {
jsonText = 'undefined';
} else if (jsonText.length >= 128) {
if (/^\{/.test(jsonText)) {
jsonText = '{...}';
} else if (/^\[/.test(jsonText)) {
jsonText = '[...]';
} else {
jsonText = jsonText.substr(0, 125) + '...';
}
}
this.app.logger.info(`[cache] get (${+new Date() - startTime}ms) ${this.name}.${key}: ${jsonText}`);
return ret;
}
async set(key, value, ttl = 60) {
this.app.logger.info(`[cache] set (ms)${this.name}.${key}: ${value}`);
return await this._set(key, value, ttl);
}
async del(key) {
return await this._del(key);
}
}
class NodeCacheWrap extends Cache {
constructor(app) {
super(app);
this.cache = new NodeCache();
this.name = 'node-cache';
}
async _get(key) {
return this.cache.get(key);
}
async _set(key, value, ttl) {
const { cache } = this;
value = JSON.parse(JSON.stringify(value));
if (ttl > 0) {
cache.set(key, value, ttl);
} else {
cache.set(key, value);
}
}
async _del(key) {
const { cache } = this;
cache.del(key);
}
}
module.exports = {
get cache() {
if (!this[NODE_CACHE]) {
this[NODE_CACHE] = new NodeCacheWrap(this);
}
return this[NODE_CACHE];
},
};
'use strict';
module.exports = {
success(data = false) {
const method = this.request.method.toLowerCase();
if (method === 'get') {
this.status = 200;
this.body = data || {};
} else if (method === 'post') {
this.status = 201;
this.body = data || {};
} else if (method === 'put' || method === 'delete') {
this.status = data ? 200 : 204;
this.body = data ? data : '';
} else {
this.status = 204;
this.body = '';
}
},
fail(error = '') {
this.status = 400;
this.body = {
error,
};
},
error(err = '') {
this.status = 200;
if (err.code === 'invalid_param') {
this.body = { code: -1, msg: '请求参数有误' };
return;
}
if (/[a-zA-Z]+/.test(err.message)) {
this.body = { code: err.code || -1, msg: '系统错误, 请稍后再试' };
return;
}
this.body = { code: err.code || -1, msg: err.message || '' };
},
};
'use strict';
const querystring = require('querystring');
const crypto = require('crypto');
const uuid = require('uuid/v1');
const iconv = require('iconv-lite');
function process(params) {
const keys = Object.keys(params)
.filter(key => {
return (
params[key] !== undefined &&
params[key] !== '' &&
['appSecret', 'partner_key', 'sign', 'key'].indexOf(key) < 0
);
})
.sort();
const result = {};
for (const key of keys) {
result[key] = params[key];
}
return result;
}
module.exports.buildRequestBody = function(params, needNonceStr = false) {
const { app } = this;
const { appKey, appSecret } = app.config.GJJ_OpenAPI;
params = params || {};
params.appKey = appKey;
params.timestamp = Date.now();
if (needNonceStr) {
params.nonce_str = this.genRandomStr(16);
}
const signStr = this.paramSign(appSecret, params);
return { sign: signStr, params };
};
module.exports.genRandomStr = function(length) {
return crypto.randomBytes(length).toString('hex');
};
module.exports.paramSign = function(appSecret, params) {
if (!params) {
const err = new Error('parameter params missing');
err.name = 'ParameterSignError';
throw err;
}
if (!appSecret) {
const err = new Error('parameter appSecret missing');
err.name = 'ParamSignError';
throw err;
}
const newParams = process(params);
let query = querystring.stringify(newParams);
query += '&appSecret=' + appSecret;
const signStr = crypto
.createHash('md5')
.update(query)
.digest('hex')
.toUpperCase();
return signStr;
};
module.exports.getUuid = function() {
return uuid();
};
module.exports.decode = function(data) {
return iconv.decode(data, 'gb2312');
};
'use strict';
module.exports = (options, app) => {
return async function errorHandler(ctx, next) {
try {
if (ctx.request.method === 'POST') {
app.logger.info(JSON.stringify(ctx.request.body));
}
await next();
} catch (err) {
// 所有的异常都在 app 上触发一个 error 事件,框架会记录一条错误日志
ctx.app.emit('error', err, ctx);
const status = err.status || 500;
// 生产环境时 500 错误的详细错误内容不返回给客户端,因为可能包含敏感信息
const error = status === 500 && ctx.app.config.env === 'prod'
? 'Internal Server Error'
: err.message;
// 从 error 对象上读出各个属性,设置到响应中
ctx.fail(error);
if (status === 422) {
ctx.body.detail = err.errors;
}
ctx.status = status;
}
};
};
'use strict';
module.exports = (options, app) => {
return async function(ctx, next) {
const { request } = ctx;
const { header } = request;
const ipStr = header['x-real-ip'] || header['x-forwarded-for'];
if (ipStr) {
request.ip = ipStr;
}
const start = new Date();
let ms = 0;
await next();
ms = new Date() - start;
app.logger.info(
`[middleware-response-time](${ms}ms) ${request.method} ${request.protocol}://${request.ip}${
request.originalUrl
} ${ctx.response.status}`
);
};
};
'use strict';
module.exports = app => {
const { DataTypes } = app.Sequelize;
const cusDatas = app.model.define('cusDatas', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
field: 'id',
},
orderId: {
type: DataTypes.STRING(255),
allowNull: false,
defaultValue: '',
primaryKey: true,
field: 'orderId',
},
appKey: {
type: DataTypes.STRING(255),
allowNull: false,
field: 'appKey',
},
type: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'type',
},
date: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: app.Sequelize.literal('CURRENT_TIMESTAMP'),
field: 'date',
},
text1: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'text1',
},
text2: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'text2',
},
text3: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'text3',
},
text4: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'text4',
},
date1: {
type: DataTypes.DATE,
allowNull: true,
field: 'date1',
},
date2: {
type: DataTypes.DATE,
allowNull: true,
field: 'date2',
},
},
{
tableName: 'cus_data',
timestamps: false,
});
return cusDatas;
};
'use strict';
module.exports = app => {
const { DataTypes } = app.Sequelize;
const taskStatus = app.model.define('taskStatus', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
field: 'id',
},
orderId: {
type: DataTypes.STRING(50),
allowNull: false,
field: 'orderId',
},
taskId: {
type: DataTypes.STRING(50),
allowNull: true,
field: 'taskId',
},
userId: {
type: DataTypes.STRING(500),
allowNull: true,
field: 'userId',
},
phone: {
type: DataTypes.STRING(11),
allowNull: true,
field: 'phone',
},
city: {
type: DataTypes.STRING(20),
allowNull: true,
field: 'city',
},
cityId: {
type: DataTypes.STRING(10),
allowNull: true,
field: 'cityId',
},
operator: {
type: DataTypes.STRING(10),
allowNull: true,
field: 'operator',
},
appKey: {
type: DataTypes.STRING(50),
allowNull: false,
field: 'appKey',
},
notifyUrl: {
type: DataTypes.STRING(500),
allowNull: true,
field: 'notifyUrl',
},
backUrl: {
type: DataTypes.STRING(500),
allowNull: true,
field: 'backUrl',
},
status: {
type: DataTypes.STRING(20),
allowNull: true,
field: 'status',
},
note: {
type: DataTypes.STRING(8000),
allowNull: true,
field: 'note',
get() {
const note = this.getDataValue('note');
if (note) {
try {
return JSON.parse(note);
} catch (error) {
return {};
}
}
return {};
},
set(val) {
this.setDataValue('note', JSON.stringify(val));
},
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: app.Sequelize.literal('CURRENT_TIMESTAMP'),
field: 'createDate',
},
updated_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: app.Sequelize.literal('CURRENT_TIMESTAMP'),
field: 'updateDate',
},
text1: {
type: DataTypes.STRING(255),
allowNull: true,
field: 'text1',
},
notice: {
type: DataTypes.STRING(2),
allowNull: true,
field: 'notice',
},
},
{
tableName: 'yys_status',
});
return taskStatus;
};
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
const gjjRouter = router.namespace(app.config.projectRootPath);
gjjRouter.post('/tasks', controller.task.create); // 创建任务
gjjRouter.get('/tasks/:taskId', controller.task.show); // 获取任务状态
gjjRouter.post('/tasks/:taskId/submit', controller.task.submit); // 提交任务参数
gjjRouter.post('/tasks/:taskId/capture', controller.task.fetchCapture); // 获取验证码
gjjRouter.post('/callback', controller.task.handleCallback); // 处理回调结果,不对外
// gjjRouter.get('/scripts', controller.script.fetchScripts); // 获取所有脚本信息
// gjjRouter.get('/scripts/:phone');// 手机号获取脚本信息
// gjjRouter.get('/scripts/:scriptId', controller.script.fetchOneScripts); // 获取单一脚本信息
gjjRouter.get('/help/:scriptId', controller.script.fetchHelpInfo); // 获取帮助信息
gjjRouter.get('/notice/:scriptId', controller.script.fetchNoticeInfo);// 获取提示信息
gjjRouter.get('/query_button/:scriptId', controller.script.fetchQueryButtonInfo); // 获取查询按钮信息
gjjRouter.get('/params', controller.script.fetchParamsInfo); // 获取登录参数字典
gjjRouter.post('/tokens', controller.token.create); // 创建token
gjjRouter.post('/orders', controller.order.create); // 创建订单号
gjjRouter.get('/hubs/:phone/scripts', controller.script.fetchHubSeripts);// 根据phone 获取脚本数据(数组)
gjjRouter.get('/theme/:appKey', controller.partner.show);// 根据appkey查询合作方主题
gjjRouter.get('/agreements/:id', controller.partner.fetchAgreements);// 查询协议
gjjRouter.post('/getToken', controller.token.partnerCreate);// 合作方创建token
gjjRouter.post('/getOrderSn', controller.order.fetchOrderId);// 合作方获取订单号
gjjRouter.post('/getThxdData', controller.order.partnerShow);// 合作方获取订单数据
// gjjRouter.get('/orderData/:appKey/:orderId', controller.order.orderShow);// 获取展示页面数据
};
'use strict';
module.exports = {
schedule: {
interval: '5m', // 5分钟间隔
type: 'all', // 所有woker
immediate: true,
},
async task(ctx) {
try {
const { host, customerUrl } = ctx.app.config.signatureAPI;
const notifyMap = new Map();
const ret = await ctx.curl(host + customerUrl, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
});
// ctx.logger.info(JSON.stringify(ret.data));
if (ret.data.code === 0) {
ret.data.data.customerList.map(customer => {
if ('callBackUrl' in customer) {
notifyMap.set(customer.appKey, { notifyUrl: customer.callBackUrl });
}
});
ctx.app.notifyMap = notifyMap;
}
} catch (e) {
ctx.logger.error('【schedule/notifyUrlTask】catch error:', JSON.stringify(e));
}
},
};
'use strict';
const Service = require('egg').Service;
class CacheService extends Service {
constructor(ctx) {
super(ctx);
const { config } = this;
const { taskPrefix } = config.lockKeys;
this.taskPrefix = taskPrefix;
}
/**
* 将taskId状态缓存到redis和数据库
* @param {Object} key taskId
* - value: 状态 提示信息 status 、note={}
* - exprie: 过期时间
*/
async set({ key, value = {}, exprie = 300 }) {
const { ctx, app, taskPrefix } = this;
const data = await app.redis.get(taskPrefix + key);
if (!data || (data && data.status !== 'success')) {
await app.redis.set(taskPrefix + key, JSON.stringify(value), 'EX', exprie);
}
const order = await ctx.model.TaskStatus.findOne({
where: { taskId: key },
});
if (order && order.status !== 'success') {
await order.update({ ...value });
} else {
ctx.logger.error('【Cache】set no order or already success', key);
}
ctx.logger.info(`【Cache】set ${key} value:`, JSON.stringify(value));
}
/**
* 获取task状态 优先redis
* @param {Object} key taskId
* @return {Object} status note
*/
async get({ key }) {
const { ctx, app, taskPrefix } = this;
const data = await app.redis.get(taskPrefix + key);
if (data) {
ctx.logger.info(`【Cache】get From redis ${key} data:`, data);
return JSON.parse(data);
}
const order = await ctx.model.TaskStatus.findOne({
where: { taskId: key },
});
if (order) {
ctx.logger.info(`【Cache】get From Model ${key} order:`, JSON.stringify({ status: order.status, note: order.note }));
return { status: order.status, note: order.note };
}
ctx.logger.error(`【Cache】get No Result ${key} `);
this.ctx.throw(400, { message: 'no taskId' });
}
}
module.exports = CacheService;
'use strict';
const Service = require('egg').Service;
class OrderService extends Service {
async getOneByOrderId(orderId) {
const { ctx } = this;
const order = await ctx.model.TaskStatus.findOne({
where: { orderId },
});
return order;
}
async getOneByTaskId(taskId) {
const { ctx } = this;
const order = await ctx.model.TaskStatus.findOne({
where: { taskId },
});
return order;
}
async create(params) {
const { ctx } = this;
await ctx.model.TaskStatus.create(params);
return;
}
/*
@desc 更新task
*/
async update(params) {
const { ctx } = this;
const order = await ctx.model.TaskStatus.findAll({
where: { orderId: params.orderId },
order: [['createDate', 'DESC']],
});
if (order.length === 0) {
ctx.throw(400, { message: 'no order' });
return;
}
for (const item of order) {
if (item.status === 'success') {
ctx.throw(400, { message: 'orderId success' });
return;
}
}
const { appKey, taskId, notifyUrl, backUrl, userId } = order[0];
if (taskId) {
await ctx.model.TaskStatus.create({ appKey, status: 'init', notifyUrl, backUrl, userId, ...params });
} else {
await order[0].update(params);
}
return order[0];
}
}
module.exports = OrderService;
'use strict';
const Service = require('egg').Service;
class PartnerService extends Service {
constructor(ctx) {
super(ctx);
const { config: { partnerAPI } } = this;
this.partnerAPI = partnerAPI;
}
async fetchTheme(appKey) {
const { ctx, partnerAPI: { fetchTheme, host, redisThemePrefix } } = this;
if (appKey) {
const data = await this.app.redis.get(redisThemePrefix + appKey);
if (data) {
try {
return JSON.parse(data);
} catch (err) {
ctx.logger.error('【Scripts】fetchParams', redisThemePrefix + appKey, 'result:', data, err);
await this.app.redis.del(redisThemePrefix + appKey);
}
}
}
const ret = await ctx.curl(`${host + fetchTheme}`, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
method: 'GET',
data: {
appKey,
subject: 'hf',
},
});
ctx.logger.info(`【Partner】 fetchTheme ${host + fetchTheme}/${appKey}`, ret.data);
if (ret.status === 200 && ret.data && ret.data.length > 0 && ret.data[0].appKey === appKey) {
await this.app.redis.set(redisThemePrefix + appKey, JSON.stringify(ret.data[0]), 'EX', 300);
}
return ret.data[0];
}
async fetchInfo(appKey) {
const { ctx, partnerAPI: { fetchInfo, host, redisInfoPrefix } } = this;
if (appKey) {
const data = await this.app.redis.get(redisInfoPrefix + appKey);
if (data) {
try {
return JSON.parse(data);
} catch (err) {
ctx.logger.error('【Scripts】fetchInfo', redisInfoPrefix + appKey, 'result:', data, err);
await this.app.redis.del(redisInfoPrefix + appKey);
}
}
}
const ret = await ctx.curl(`${host + fetchInfo}`, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
method: 'GET',
data: {
appKey,
},
});
ctx.logger.info(`【Partner】 fetchTheme ${host + fetchInfo}?appKey=${appKey}`, ret.data);
if (ret.status === 200 && ret.data && ret.data.length > 0 && ret.data[0].appKey === appKey) {
await this.app.redis.set(redisInfoPrefix + appKey, JSON.stringify(ret.data[0]), 'EX', 300);
}
return ret.data[0];
}
async fetchScripts(appKey) {
const { ctx, partnerAPI: { fetchScripts, host, redisScriptsPrefix } } = this;
if (appKey) {
const data = await this.app.redis.get(redisScriptsPrefix + appKey);
if (data) {
try {
return JSON.parse(data);
} catch (err) {
ctx.logger.error('【Partner】 fetchScripts', redisScriptsPrefix + appKey, 'result:', JSON.stringify(data), err);
await this.app.redis.del(redisScriptsPrefix + appKey);
}
}
}
const url = `${host + fetchScripts}/${appKey}`;
const ret = await ctx.curl(url, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
method: 'GET',
});
ctx.logger.info(`【Partner】 fetchTheme ${url}`, JSON.stringify(ret.data));
if (ret.status === 200 && ret.data && ret.data.id === appKey) {
await this.app.redis.set(redisScriptsPrefix + appKey, JSON.stringify(ret.data), 'EX', 300);
}
return ret.data;
}
async fetchAgreements(id) {
const { ctx, partnerAPI: { fetchAgreements, host, redisAgreementsPrefix } } = this;
const data = await this.app.redis.get(redisAgreementsPrefix + id);
if (data) {
try {
return JSON.parse(data);
} catch (err) {
ctx.logger.error('【Partner】 fetchAgreements', redisAgreementsPrefix + id, 'result:', JSON.stringify(data), err);
await this.app.redis.del(redisAgreementsPrefix + id);
}
}
const url = `${host + fetchAgreements}/${id}`;
const ret = await ctx.curl(url, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
method: 'GET',
});
ctx.logger.info(`【Partner】 fetchAgreements ${url}`, JSON.stringify(ret.data));
if (ret.status === 200 && ret.data && ret.data.id === id) {
await this.app.redis.set(redisAgreementsPrefix + id, JSON.stringify(ret.data), 'EX', 300);
}
return ret.data;
}
async notice(order) {
const { ctx } = this;
const { orderId, notifyUrl, userId, notice } = order;
if (notifyUrl && notice !== '1') {
const ret = await ctx.curl(notifyUrl, {
charset: 'utf-8',
timeout: [30000, 30000],
contentType: 'json',
method: 'POST',
data: {
orderId,
userId,
status: 'success',
},
}
);
ctx.logger.info(`【Partner】 notice ${notifyUrl}`, 'orderId:', orderId, 'result:', ret.status, JSON.stringify(ret.data));
if (ret.status === 200) {
await order.update({ notice: '1' });
}
}
return;
}
}
module.exports = PartnerService;
'use strict';
const Service = require('egg').Service;
class ScriptsService extends Service {
constructor(ctx) {
super(ctx);
const { config } = this;
const { scriptsAPI } = config;
this.scriptsAPI = scriptsAPI;
this.baseURL = scriptsAPI.host;
this.fetchScriptsUrl = scriptsAPI.fetchScriptsUrl;
this.fetchOneScriptUrl = scriptsAPI.fetchOneScriptUrl;
this.fetchParamsInfoUrl = scriptsAPI.fetchParamsInfoUrl;
this.fetchHelpUrl = scriptsAPI.fetchHelpUrl;
this.redisScriptsKey = scriptsAPI.redisScriptsKey;
this.redisParamsKey = scriptsAPI.redisParamsKey;
this.redisScriptListKey = scriptsAPI.redisScriptListKey;
this.cityListUrl = scriptsAPI.cityListUrl;
}
async fetchScripts() {
const { baseURL, fetchScriptsUrl, redisScriptsKey, ctx } = this;
const data = await this.app.redis.get(redisScriptsKey);
if (data) {
try {
return JSON.parse(data);
} catch (err) {
ctx.logger.error('【Scripts】fetchScriptsFromRedis', 'result:', data, err);
await this.app.redis.del(redisScriptsKey);
}
}
const result = await ctx.curl(baseURL + fetchScriptsUrl, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
});
ctx.logger.info(`【Scripts】fetchScripts,${baseURL + fetchScriptsUrl}`, 'result:', result.data);
if (result.data && result.data.length > 0) {
await this.app.redis.set(redisScriptsKey, JSON.stringify(result.data), 'EX', 300);
}
return result.data;
}
async fetchOneScripts(scriptId) {
const { baseURL, fetchOneScriptUrl, redisScriptListKey, ctx } = this;
const data = await this.app.redis.get(redisScriptListKey + scriptId);
if (data) {
try {
return JSON.parse(data);
} catch (err) {
ctx.logger.error('【Scripts】fetchOneScriptsFromRedis', 'result:', data, err);
await this.app.redis.del(redisScriptListKey + scriptId);
}
}
const result = await ctx.curl(baseURL + fetchOneScriptUrl + '/' + scriptId, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
});
if (result.data && (String(result.data.id) === scriptId)) {
await this.app.redis.set(redisScriptListKey + scriptId, JSON.stringify(result.data), 'EX', 60);
}
return result.data;
}
async fetchParams(refresh = false) {
const { baseURL, fetchParamsInfoUrl, redisParamsKey, ctx } = this;
if (!refresh) {
const data = await this.app.redis.get(redisParamsKey);
if (data) {
try {
return JSON.parse(data);
} catch (err) {
ctx.logger.error('【Scripts】fetchParams', 'result:', data, err);
await this.app.redis.del(redisParamsKey);
}
}
}
const result = await ctx.curl(baseURL + fetchParamsInfoUrl, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
});
ctx.logger.info(`【Scripts】fetchParams,${baseURL + fetchParamsInfoUrl}`, 'result:', result.data);
if (result.data && result.data.length > 0) {
await this.app.redis.set(redisParamsKey, JSON.stringify(result.data), 'EX', 300);
}
return result.data;
}
async fetchHelp(scriptId) {
const { baseURL, scriptsAPI: { fetchHelpUrl }, ctx } = this;
const result = await ctx.curl(baseURL + fetchHelpUrl + '/' + scriptId, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
});
return result.data;
}
async fetchQueryButton(scriptId) {
const { baseURL, scriptsAPI: { fetchQueryButtonUrl }, ctx } = this;
const result = await ctx.curl(baseURL + fetchQueryButtonUrl + '/' + scriptId, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
});
return result.data;
}
async fetchNotice(scriptId) {
const { baseURL, scriptsAPI: { fetchNoticeUrl }, ctx } = this;
const result = await ctx.curl(baseURL + fetchNoticeUrl + '/' + scriptId, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
});
return result.data;
}
async fetchHubSeripts(hubId) {
const { baseURL, scriptsAPI: { fetchHubSeriptsUrl }, ctx } = this;
const result = await ctx.curl(baseURL + fetchHubSeriptsUrl + '/' + hubId + '/scripts', {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
});
return result.data;
}
async fetchScriptByCityName(name) {
const { baseURL, scriptsAPI: { fetchScriptByCityNameUrl }, ctx } = this;
const result = await ctx.curl(baseURL + fetchScriptByCityNameUrl + '?name=' + encodeURIComponent(name) + '&type=query', {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
});
ctx.logger.info(`fetchScriptByCityName,${baseURL + fetchScriptByCityNameUrl + '?name=' + name}`, 'result:', JSON.stringify(result.data));
return result.data;
}
async fetchScriptName(scriptId) {
try {
const city = await this.fetchOneScripts(scriptId);
return city.name || '未知';
} catch (err) {
return '未知';
}
}
// eslint-disable-next-line no-empty-function
async getCityList(params) {
try {
const { cityListUrl, ctx } = this;
const result = await ctx.curl(cityListUrl, {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
contentType: 'json',
method: 'POST',
data: params,
});
return result.data;
} catch (err) {
this.ctx.logger.error(err);
return { code: -1, msg: '系统错误,请稍后重试' };
}
}
}
module.exports = ScriptsService;
'use strict';
const Service = require('egg').Service;
class SignatureService extends Service {
constructor(ctx) {
super(ctx);
const { config } = this;
const { signatureAPI, lockKeys } = config;
this.baseURL = signatureAPI.host;
this.fetchTokenUrl = signatureAPI.fetchTokenUrl;
this.fetchOrderIdUrl = signatureAPI.fetchOrderIdUrl;
this.signatureUrl = signatureAPI.signatureUrl;
this.signatureType = signatureAPI.signatureType;
this.LOCK_KEY = lockKeys.fecteToken;
this.SCRIPTS_KEY = lockKeys.token;
}
_request(url, opts) {
const { ctx, baseURL } = this;
url = `${baseURL}${url}`;
opts = {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
...opts,
};
ctx.logger.info('signnature', url, opts);
return ctx.curl(url, opts);
}
_checkSuccess(result) {
if (result.status !== 200) {
const errorMsg = result.data && result.data.error_msg ? result.data.error_msg : 'unknown error';
this.ctx.throw(result.status, errorMsg);
}
if (result.data.code !== 0) {
this.ctx.throw(400, { message: result.data.msg, code: result.data.code });
}
}
async createToken(params) {
const { fetchTokenUrl, ctx } = this;
const result = await this._request(fetchTokenUrl, {
method: 'post',
data: params,
contentType: 'json',
});
ctx.logger.info('【Signature】createToken params', JSON.stringify(params), 'result:', JSON.stringify(result.data));
this._checkSuccess(result);
return result.data.data.token;
}
async createOrderId(params) {
const { fetchOrderIdUrl, ctx } = this;
const result = await this._request(fetchOrderIdUrl, {
method: 'post',
data: params,
contentType: 'json',
});
ctx.logger.info('【Signature】createOrderId params', JSON.stringify(params), 'result:', JSON.stringify(result.data));
this._checkSuccess(result);
return result.data.data.orderSn;
}
async signatureCheck(params) {
const { signatureUrl, signatureType, ctx } = this;
const result = await this._request(signatureUrl, {
method: 'post',
data: { ...params, type: signatureType },
contentType: 'json',
});
ctx.logger.info('【Signature】signatureCheck params', JSON.stringify(params), 'result:', JSON.stringify(result.data));
this._checkSuccess(result);
return result.data.data;
}
}
module.exports = SignatureService;
'use strict';
const Service = require('egg').Service;
class StorageService extends Service {
constructor(ctx) {
super(ctx);
const { config } = this;
const { storageAPI } = config;
this.baseURL = storageAPI.host;
this.writeUrl = storageAPI.writeUrl;
this.readUrl = storageAPI.readUrl;
this.writeType = storageAPI.writeType;
this.readDataKey = storageAPI.readDataKey;
}
_request(url, opts) {
const { ctx, baseURL } = this;
url = `${baseURL}${url}`;
opts = {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
...opts,
};
return ctx.curl(url, opts);
}
async write(data) {
const { writeUrl, writeType, ctx } = this;
const result = await this._request(writeUrl, {
method: 'post',
data: { ...data, serviceType: writeType },
contentType: 'json',
});
ctx.logger.info(`【Storage】write url:${writeUrl} params`, JSON.stringify({ ...data, serviceType: writeType }), 'result:', JSON.stringify(result.data));
if (result.data.code !== '0') {
throw new Error('存储数据出错');
}
return;
}
async read(orderId, appKey) {
const { readUrl, readDataKey, ctx } = this;
const result = await this._request(`${readUrl}/${orderId}`, {
method: 'get',
contentType: 'json',
});
ctx.logger.info(`【Storage】read url:${readUrl}/${orderId} write result:`, JSON.stringify(result.data));
if (result && result.data && result.data.code !== 0) {
ctx.logger.error(`storageAPI read ${readUrl}/${orderId}`, JSON.stringify(result.data));
ctx.throw(400, { message: result.data.msg });
}
await ctx.model.Cusdata.create({
appKey,
orderId,
type: 'gjj',
});
return result.data.data[readDataKey];
}
}
module.exports = StorageService;
'use strict';
const Service = require('egg').Service;
class TaskService extends Service {
constructor(ctx) {
super(ctx);
const { config: { taskAPI, LOCK_KEY, phoneAreaAPI } } = this;
this.taskAPI = taskAPI;
this.phoneAreaAPI = phoneAreaAPI;
this.baseURL = taskAPI.host;
this.citylistURL = taskAPI.citylist;
this.LOCK_KEY = LOCK_KEY;
}
_request(url, opts) {
const { ctx, baseURL } = this;
url = `${baseURL}${url}`;
opts = {
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
...opts,
};
return ctx.curl(url, opts);
}
_checkSuccess(result) {
if (result.status !== 200) {
const errorMsg = result.data && result.data.error_msg ? result.data.error_msg : 'unknown error';
this.ctx.throw(result.status, errorMsg);
}
if (result.data.code !== 0) {
this.ctx.throw(400, { message: result.data.msg || result.data.data.img, code: result.data.code || -1 });
}
}
async create(data) {
const { ctx, taskAPI } = this;
const { createTaskUrl } = taskAPI;
const result = await this._request(createTaskUrl, {
method: 'post',
data: { cityId: data },
contentType: 'json',
});
ctx.logger.info(`【Task】create ${createTaskUrl} cityId: ${data} result:`, JSON.stringify(result.data));
this._checkSuccess(result);
return result.data.data.taskId;
}
async fetchCapture({ taskId, type, data }) {
const { taskAPI, ctx } = this;
const { fetchCodeUrl } = taskAPI;
const result = await this._request(fetchCodeUrl, {
method: 'post',
data: {
taskId,
type,
data,
},
contentType: 'json',
});
ctx.logger.info(`【Task】fetchCapture ${fetchCodeUrl} params`, JSON.stringify({
taskId,
type,
}), JSON.stringify(result.data));
this._checkSuccess(result);
return result.data.data;
}
async submit(data) {
const { taskAPI, ctx } = this;
const { submitTaskUrl } = taskAPI;
const result = await this._request(submitTaskUrl, {
method: 'post',
data,
contentType: 'json',
});
ctx.logger.info(`【Task】submit ${submitTaskUrl} params`, JSON.stringify(data), JSON.stringify(result.data));
this._checkSuccess(result);
return result;
}
async fetchTask(data) {
const { taskAPI, ctx } = this;
const { fetchTaskUrl } = taskAPI;
const result = await this._request(fetchTaskUrl, {
method: 'post',
data,
contentType: 'json',
});
ctx.logger.info(`【Task】fetchTask ${fetchTaskUrl} params`, JSON.stringify(data), JSON.stringify(result.data));
return result.data;
}
async phoneArea(phone) {
const { ctx, phoneAreaAPI } = this;
const { bdhost, alhost } = phoneAreaAPI;
const phoneInfo = {
phone,
province: '',
operator: '',
};
let result = await ctx.curl(bdhost + phone, {
method: 'get',
timeout: [3000, 3000],
dataType: 'json',
});
ctx.logger.info('phoneArea', bdhost + phone, JSON.stringify(result), phone);
if (result.status !== 200 || result.data.responseHeader.status !== 200 || !result.data.response[phone]) {
result = await ctx.curl(alhost + phone, {
method: 'get',
timeout: [3000, 3000],
});
if (result.status !== 200) {
ctx.throw('400', '请检查手机号是否有效');
}
const html = ctx.helper.decode(result.data);
if (!html.match(/province:'(.*?)'/) || !html.match(/catName:'(.*?)'/)) {
ctx.throw('400', '请检查手机号是否有效');
}
phoneInfo.province = html.match(/province:'(.*?)'/)[1];
phoneInfo.operator = html.match(/catName:'(.*?)'/)[1];
ctx.logger.info('phoneArea', alhost + phone, JSON.stringify(phoneInfo), html, phone);
} else {
phoneInfo.province = result.data.response[phone].detail.province;
phoneInfo.operator = result.data.response[phone].detail.operator;
}
if (phoneInfo.province === '香港') {
phoneInfo.province = '广东';
}
if (phoneInfo.operator.match(/移动|联通|电信/)) {
phoneInfo.operator = phoneInfo.operator.match(/移动|联通|电信/)[0];
} else {
phoneInfo.operator = '虚拟运营商';
}
ctx.logger.info('phoneArea result', JSON.stringify(phoneInfo), phone);
return phoneInfo;
}
}
module.exports = TaskService;
'use strict';
const Service = require('egg').Service;
class WashDataService extends Service {
constructor(ctx) {
super(ctx);
const { config } = this;
this.washUrl = config.washAPI.host + config.washAPI.washUrl;
this.clearGjj = ['ID', 'phone', 'birthday', 'email', 'address', 'card', 'deposit_base', 'person_rate', 'company_rate', 'marriage', 'sex', 'company_id'];
this.clearLoan = ['name', 'ID', 'warning_rate', 'fund_date', 'bank', 'phone', 'address', 'past_due', 'past_principle', 'past_interest', 'past_period', 'history_past_period', 'history_past_amount', 'assure_style', 'house_type', 'debit_account', 'left_period'];
}
async wash(data) {
const { app, washUrl, ctx } = this;
const rawdata = this._switchData(data);
const washData = await app.curl(washUrl,
{
charset: 'utf-8',
timeout: [30000, 30000],
dataType: 'json',
data: rawdata,
method: 'post',
contentType: 'json',
});
if (washData.status !== 200) {
ctx.logger.error(`【washData】url${washUrl} ,params`, rawdata, washData);
throw new Error('清洗数据出错');
}
if (washData.data.code !== 0) {
ctx.logger.error(`【washData】url${washUrl} ,params`, rawdata, washData.data);
throw new Error('清洗数据出错');
}
washData.data.data.general_analyzed_data.overdueClassify = {};
washData.data.data.general_analyzed_data.loanClassify = {};
washData.data.data.general_analyzed_data.blacklist = {};
return washData.data;
}
_switchData(data) {
const tmp = data.data;
const bar = {};
bar.taskId = tmp.taskId;
bar.cityId = tmp.cityId;
bar.data = JSON.parse(tmp.data);
bar.orderID = 'ttt';
bar.appKey = '';
return bar;
}
dealData(data, passID = false) {
const { clearGjj, clearLoan } = this;
delete data.data.general_analyzed_data;
for (const gjjItem of data.data.gjj_data) {
for (const text of clearGjj) {
if (!(passID && text === 'ID')) {
delete gjjItem.gjj_brief[text];
}
}
delete gjjItem.gjj_account_analyzed_data;
}
for (const loanItem of data.data.loan_data) {
for (const text of clearLoan) {
delete loanItem.loan_brief[text];
}
}
return data;
}
}
module.exports = WashDataService;
environment:
matrix:
- nodejs_version: '8'
install:
- ps: Install-Product node $env:nodejs_version
- npm i npminstall && node_modules\.bin\npminstall
test_script:
- node --version
- npm --version
- npm run test
build: off
'use strict';
module.exports = appInfo => {
const config = exports = {};
// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1542452126322_5140';
// add your config here
config.middleware = ['requestLog', 'errorHandler'];
config.logrotator = {
maxDays: 5,
}
// 是否启用csrf安全
config.security = {
csrf: {
enable: false,
},
domainWhiteList: [],
};
config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',
credentials: true,
};
return config;
};
'use strict';
module.exports = () => {
const config = exports = {};
config.debug = true;
config.projectRootPath = '/yysh5';
config.redis = {
client: {
port: 6379,
host: '127.0.0.1',
password: 'DEV8redis',
db: 0,
},
};
config.taskAPI = {
host: 'http://tm.51gjj.com:4829',
createTaskUrl: '/thxdServices/createThxdTask',
fetchCodeUrl: '/thxdServices/queryThxdCode',
submitTaskUrl: '/thxdServices/queryThxd',
fetchTaskUrl: '/thxdServices/getThxdData',
};
config.partnerAPI = {
host: 'https://uat-nginx.jianbing.com/zeus-api/v1',
fetchTheme: '/chaos/theme',
fetchScripts: '/chaos/partners/scripts',
fetchAgreements: '/chaos/agreements',
redisThemePrefix: 'URANUS.YYS.PARNTERS.THEME',
redisScriptsPrefix: 'URANUS.YYS.PARNTERS.SCRIPTS',
redisAgreementsPrefix: 'URANUS.YYS.PARNTERS.Agreements',
fetchInfo: '/chaos/partner',
redisInfoPrefix: 'URANUS.YYS.PARNTERS.Info',
};
config.scriptsAPI = {
host: 'https://uat-nginx.jianbing.com/zeus-api/v1',
fetchScriptsUrl: '/chaos/hf/two_dimension_array/queries',
fetchOneScriptUrl: '/chaos/hf/two_dimension_array/info',
fetchParamsInfoUrl: '/chaos/hf/login_param_map',
fetchQueryButtonUrl: '/chaos/hf/query_button',
fetchHelpUrl: '/chaos/hf/help',
fetchNoticeUrl: '/chaos/hf/notice',
fetchHubSeriptsUrl: '/chaos/hf/hubs',
fetchScriptByCityNameUrl: '/chaos/hf/city_scripts',
redisScriptsKey: 'URANUS.YYS.SCRIPTS',
redisParamsKey: 'URANUS.YYS.PARAMS',
redisScriptListKey: 'URANUS.YYS.SCRIPTLIST',
cityListUrl: 'https://t.51gjj.com/gjj/getCityConfig',
};
config.phoneAreaAPI = {
bdhost: 'http://mobsec-dianhua.baidu.com/dianhua_api/open/location?tel=',
alhost: 'https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=',
};
// config.storageAPI = {
// host: 'http://tv.51gjj.com:11252',
// writeUrl: '/data',
// readUrl: '/gjj',
// writeType: 'gjj',
// readDataKey: 'gjjData',
// };
config.washAPI = {
host: 'http://t.51gjj.com:3007',
washUrl: '/dataProcessing',
};
config.signatureAPI = {
host: 'http://tj3.51gjj.com:5118',
fetchTokenUrl: '/Access/GetToken',
fetchOrderIdUrl: '/Order/GetOrderSn',
signatureUrl: '/Access/SignValidityCheck',
signatureType: 'thxd',
customerUrl: '/customer/query',
};
config.lockKeys = {
fecthHub: 'URANUS.YYS.HUBS.LOCK',
fecteToken: 'URANUS.YYS.TOKEN.LOCK',
token: 'URANUS.YYS.TOKEN',
fecthParnters: 'URANUS.YYS.PARNTERS.LOCK',
taskPrefix: 'URANUS.YYS.TASK',
};
config.sequelize = {
datasources: [{
// 东八时区
timezone: '+08:00',
delegate: 'model',
baseDir: 'model',
dialect: 'mysql',
host: 'rm-bp1272001633qc0x9o.mysql.rds.aliyuncs.com',
database: 'data_service_dev',
username: 'hexin',
password: 'gYUHszn9#q',
port: 3306,
}],
};
config.callbackUrl = 'https://dev-nginx.jianbing.com/yysh5/callback';
return config;
};
'use strict';
module.exports = () => {
const config = exports = {};
config.debug = true;
config.logger = {
dir: '/jianbing/logs/yysh5',
};
config.projectRootPath = '/yysh5';
config.redis = {
client: {
port: 6379,
host: process.env.REDIS_HOST,
password: process.env.REDIS_PWD || 'DEV8redis',
db: 0,
},
};
config.taskAPI = {
host: process.env.TASKAPI_HOST || 'http://tm.51gjj.com:4821',
fetchHubsUrl: '',
createTaskUrl: '/gjjServices/createGjjTask',
fetchCodeUrl: '/gjjServices/queryGjjCode',
submitTaskUrl: '/gjjServices/queryGjj',
fetchTaskUrl: '/gjjServices/getGjjData',
};
config.scriptsAPI = {
host: process.env.SCRIPTSAPI_HOST || 'https://uat-nginx.jianbing.com/zeus-api/v1',
fetchScriptsUrl: '/chaos/hf/two_dimension_array/queries',
fetchOneScriptUrl: '/chaos/hf/two_dimension_array/info',
fetchParamsInfoUrl: '/chaos/hf/login_param_map',
fetchQueryButtonUrl: '/chaos/hf/query_button',
fetchHelpUrl: '/chaos/hf/help',
fetchNoticeUrl: '/chaos/hf/notice',
fetchHubSeriptsUrl: '/chaos/hf/hubs',
fetchScriptByCityNameUrl: '/chaos/hf/city_scripts',
redisScriptsKey: 'URANUS.HF.SCRIPTS',
redisParamsKey: 'URANUS.HF.PARAMS',
redisScriptListKey: 'URANUS.HF.SCRIPTLIST',
cityListUrl: 'https://t.51gjj.com/gjj/getCityConfig',
};
config.storageAPI = {
host: process.env.STORAGEAPI_HOST || 'http://tv.51gjj.com:11252',
writeUrl: '/data',
readUrl: '/gjj',
writeType: 'gjj',
readDataKey: 'gjjData',
};
config.washAPI = {
host: process.env.WASHAPI_HOST || 'http://tt.51gjj.com:11101',
washUrl: '/gjj/analyzeGjj',
};
config.signatureAPI = {
host: process.env.SIGNATUREAPI_HOST || 'http://tj3.51gjj.com:5118',
fetchTokenUrl: '/Access/GetToken',
fetchOrderIdUrl: '/Order/GetOrderSn',
signatureUrl: '/Access/SignValidityCheck',
fetchParnterUrl: '',
signatureType: 'gjj',
customerUrl: '/customer/query',
};
config.partnerAPI = {
host: process.env.PARTNERAPI_HOST || 'https://uat-nginx.jianbing.com/zeus-api/v1',
fetchTheme: '/chaos/theme',
fetchScripts: '/chaos/partners/scripts',
fetchAgreements: '/chaos/agreements',
redisThemePrefix: 'URANUS.HF.PARNTERS.THEME',
redisScriptsPrefix: 'URANUS.HF.PARNTERS.SCRIPTS',
redisAgreementsPrefix: 'URANUS.HF.PARNTERS.Agreements',
fetchInfo: '/chaos/partner',
redisInfoPrefix: 'URANUS.HF.PARNTERS.Info',
};
config.lockKeys = {
fecthHub: 'URANUS.HF.HUBS.LOCK',
fecteToken: 'URANUS.HF.TOKEN.LOCK',
token: 'URANUS.HF.TOKEN',
fecthParnters: 'URANUS.PARNTERS.LOCK',
taskPrefix: 'URANUS.HFH5.TASK',
};
config.sequelize = {
datasources: [{
// 东八时区
timezone: '+08:00',
delegate: 'model',
baseDir: 'model',
dialect: 'mysql',
host: process.env.MYSQL_PACHONG_HOST || 'rm-bp1272001633qc0x9o.mysql.rds.aliyuncs.com',
database: process.env.MYSQL_DATA_SERVER_DB_NAME || 'data_service_dev',
username: process.env.MYSQL_USER || 'kf_jiandeng',
password: process.env.MYSQL_PWD || 'Zg23Is9c7d2uKz15abZcV',
port: process.env.MYSQL_PORT || 3306,
}],
};
config.callbackUrl = process.env.CALLBACK_URL || 'https://dev-nginx.jianbing.com/gjjh5/callback';
return config;
};
'use strict';
// had enabled by egg
// exports.static = true;
exports.mysql = {
enable: false,
package: 'egg-mysql',
};
exports.sequelize = {
enable: true,
package: 'egg-sequelize',
};
exports.redis = {
enable: true,
package: 'egg-redis',
};
exports.routerPlus = {
enable: true,
package: 'egg-router-plus',
};
exports.cors = {
enable: true,
package: 'egg-cors',
};
exports.validate = {
enable: true,
package: 'egg-validate',
};
{
"name": "yys_h5_server",
"version": "1.0.0",
"description": "运营商H5认证服务",
"private": true,
"dependencies": {
"egg": "^2.2.1",
"egg-cors": "^2.1.1",
"egg-mysql": "^3.0.0",
"egg-redis": "^2.3.0",
"egg-router-plus": "^1.3.0",
"egg-scripts": "^2.5.0",
"egg-sequelize": "^4.2.0",
"egg-validate": "^2.0.2",
"iconv-lite": "^0.4.24",
"mysql2": "^1.6.4",
"node-cache": "^4.2.0",
"node-uuid": "^1.4.8"
},
"devDependencies": {
"autod": "^3.0.1",
"autod-egg": "^1.0.0",
"egg-bin": "^4.3.5",
"egg-ci": "^1.8.0",
"egg-mock": "^3.14.0",
"eslint": "^4.11.0",
"eslint-config-egg": "^6.0.0",
"webstorm-disable-index": "^1.2.0"
},
"engines": {
"node": ">=8.9.0"
},
"scripts": {
"start": "egg-scripts start --daemon --title=egg-server-yys_h5_server",
"stop": "egg-scripts stop --title=egg-server-yys_h5_server",
"docker": "eggctl start --title=egg-server-yys_h5_serverr",
"dev": "egg-bin dev",
"debug": "egg-bin debug",
"test": "npm run lint -- --fix && npm run test-local",
"test-local": "egg-bin test",
"cov": "egg-bin cov",
"lint": "eslint .",
"ci": "npm run lint && npm run cov",
"autod": "autod"
},
"ci": {
"version": "8"
},
"repository": {
"type": "git",
"url": ""
},
"author": "jd",
"license": "MIT"
}
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