Commit a23710e5 authored by 何娜's avatar 何娜

taxApi new

parent a1489e62
'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~
variables:
DOCKER_REGISTRY: 't-docker.51gjj.com'
before_script:
- docker login -u pengtianzi -p 4dc8b3a4d91fa7fa $DOCKER_REGISTRY
stages:
- pre_deploy
build_docker_image:
stage: pre_deploy
script:
- export IMAGE_TAG=${CI_COMMIT_TAG:-latest}
- docker build -t $DOCKER_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$IMAGE_TAG .
- docker push $DOCKER_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$IMAGE_TAG
tags:
- docker-image-builder
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" ]
# gjj_api
公积金API查询服务
## 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
# gjj_api_server
公积金API认证服务
## 快速入门
<!-- 在此次添加使用文档 -->
如需进一步了解,参见 [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.showRule = {
sign: 'string',
params: {
type: 'object',
rule: {
token: 'string',
orderSn: {
type: 'string',
format: /^(\w{8})-(\w{4})-(\w{4})-(\w{4})-(\w{12})$/,
message: '订单号格式错误',
},
appKey: 'string',
timestamp: 'string',
},
},
};
this.fetchRule = {
signParams: {
type: 'object',
rule: {
sign: 'string',
params: {
type: 'object',
rule: {
appKey: 'string',
timestamp: 'string',
token: 'string',
},
},
}
},
cityId: 'string'
};
}
//拉取数据接口
async partnerShow() {
const { ctx, service } = this;
try {
ctx.validate(this.showRule);
const { appKey, orderSn } = ctx.request.body.params;
// await service.signature.signatureCheck(ctx.request.body);
let data = await service.cache.get({ key: orderSn });
let result = { code: 2, msg: '任务还在执行或未输入', data: {} };
if (data) {
if (data.status === 'success') {
const result = await service.storage.read(orderSn, appKey);
ctx.body = {
code: 0,
data: result
};
return;
} else if (data.note) {
result = data.note;
}
ctx.body = result;
return;
}
} catch (err) {
ctx.logger.error('partnerShow', err);
ctx.status = 200;
if (err.code == 'invalid_param') {
return ctx.body = { code: -1, msg: err.message || '' };
}
return ctx.body = { code: err.code || -1, msg: err.message || '' };
}
}
//创建订单号接口
async fetchOrderId() {
const { ctx, service } = this;
try {
ctx.validate(this.fetchRule);
const { appKey } = ctx.request.body.signParams.params;
const { cityId } = ctx.request.body;
const orderId = await service.signature.createOrderId(ctx.request.body.signParams);
const taskId = await service.task.create(cityId);
await service.order.create({
orderId,
taskId,
cityId: cityId,
notifyUrl: ctx.app.notifyMap.get(appKey) && ctx.app.notifyMap.get(appKey).notifyUrl || '',
appKey: appKey,
status: 'init',
});
ctx.body = {
code: 0,
data: {
orderSn: orderId
},
msg: ''
}
} catch (err) {
ctx.logger.error('fetchOrderId', err);
ctx.status = 200;
if (err.code == 'invalid_param') {
return ctx.body = { code: -1, msg: err.message || '' };
}
if (/[a-zA-Z]+/.test(err.message)) {
return ctx.body = { code: err.code || -1, msg: '系统错误, 请稍后再试' };
}
return ctx.body = { code: err.code || -1, msg: err.message || '' };
}
}
}
module.exports = OrderController;
'use strict';
const Controller = require('egg').Controller;
class TaskController extends Controller {
constructor(ctx) {
super(ctx);
this.createRule = {
scriptId: 'number',
orderId: 'string',
};
this.submitRule = {
orderSn: {
type: 'string',
format: /^(\w{8})-(\w{4})-(\w{4})-(\w{4})-(\w{12})$/,
message: 'orderSn格式错误',
},
params: {
type: 'object',
rule: {
phone: { type: 'string', format: /^1\d{10}$/, required: false, message: '手机号格式错误' },
ID: { type: 'string', format: /^\d{14}(\d{3})?[\dXx]$/, required: false, message: '身份证格式错误' },
},
}
};
this.fetchCaptureRule = {
orderSn: {
type: 'string',
format: /^(\w{8})-(\w{4})-(\w{4})-(\w{4})-(\w{12})$/,
message: 'orderSn格式错误',
},
type: { type: 'enum', values: ['code', '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 } = ctx.request.body;
const taskId = await service.task.create(scriptId);
ctx.success({ taskId });
}
//提交任务接口
async submit() {
const { ctx, service, config } = this;
try {
ctx.validate(this.submitRule);
const { orderSn } = ctx.request.body;
let order = await service.cache.get({ key: orderSn });
if (order.status == 'success' || order.status == 'failure') {
return ctx.body = {
code: -1,
msg: '此任务已结束'
}
}
await service.cache.set({
key: orderSn, value: {
status: 'submit',
note: { code: 3, msg: '任务已提交', data: { data: null, loginParam: null, cityId: order.cityId, orderSn } },
}
});
await service.task.submit({
taskId: order.taskId,
data: ctx.request.body.params,
callbackUrl: config.callbackUrl,
});
ctx.body = {
msg: null,
code: 0,
data: {
cityId: order.cityId,
orderSn
}
};
} catch (err) {
ctx.logger.error('submit', err);
ctx.status = 200;
if (err.code == 'invalid_param') {
return ctx.body = { code: -1, msg: err.message || '' };
}
if (/[a-zA-Z]+/.test(err.message)) {
return ctx.body = { code: err.code || -1, msg: '系统错误, 请稍后再试' };
}
return ctx.body = { code: err.code || -1, msg: err.message || '' };
}
}
//获取验证码接口
async fetchCapture() {
const { ctx, service } = this;
try {
ctx.validate(this.fetchCaptureRule);
const { type, orderSn } = ctx.request.body;
const order = await service.cache.get({ key: orderSn });
if (order.status == 'success' || order.status == 'failure') {
return ctx.body = {
code: -1,
msg: '此任务已结束'
}
}
const result = await service.task.fetchCapture({
taskId: order.taskId,
type,
});
delete result.taskId;
ctx.body = {
code: 0,
data: { ...result, orderSn }
};
} catch (err) {
ctx.logger.error('submit', err);
ctx.status = 200;
if (err.code == 'invalid_param') {
return ctx.body = { code: -1, msg: err.message || '' };
}
if (/[a-zA-Z]+/.test(err.message)) {
return ctx.body = { code: err.code || -1, msg: '系统错误, 请稍后再试' };
}
return ctx.body = { code: err.code || -1, msg: err.message || '' };
}
}
//任务回调接口
async handleCallback() {
const { ctx, service } = this;
const { taskId } = ctx.request.body;
const result = await service.task.fetchTask({ taskId });
ctx.success();
const order = await service.order.getOneByTaskId(taskId);
if (!order) {
ctx.logger.error('handleCallback', taskId, '未查询到此任务');
return
}
const { orderId, appKey, cityId } = order;
let taskNote = {
status: 'init',
note: { code: 2, msg: '任务正在执行', data: { data: null, loginParam: null, cityId, orderSn: orderId } },
};
switch (result.code) {
case -1:
case 106:
case 102:
case 204:
taskNote = {
status: 'failure',
note: { code: -1, msg: result.msg, data: { data: null, loginParam: null, cityId, orderSn: orderId } },
};
await service.cache.set({
key: orderId,
value: taskNote,
});
await service.partner.notice(order);
break;
case 1:
taskNote = {
status: 'next',
note: { code: 1, msg: null, data: { data: null, loginParam: result.loginParam, cityId, orderSn: orderId } },
};
await service.cache.set({
key: orderId,
value: taskNote,
});
await service.partner.notice(order);
break;
case 110:
taskNote = {
status: 'query',
note: { code: 110, msg: '任务提交成功', data: { data: null, loginParam: null, cityId, orderSn: orderId } },
};
break;
case 0:
taskNote = {
status: 'success',
note: { code: 0, msg: '任务成功', data: { data: null, loginParam: null, cityId, orderSn: orderId } },
};
try {
const insertData = await service.washData.wash(result);
insertData.orderId = orderId;
insertData.cityName = await service.scripts.fetchScriptName(insertData.cid);
insertData.taskId = Number(taskId);
insertData.appKey = appKey;
delete insertData.code;
await service.storage.write(insertData);
await service.cache.set({
key: orderId,
value: taskNote,
});
await service.partner.notice(order);
} catch (err) {
ctx.logger.error('handleCallback', err, JSON.stringify(result));
taskNote = {
status: 'failure',
note: { code: -1, msg: '系统错误', data: { data: null, loginParam: null, cityId: order.cityId, orderSn: order.orderId } },
};
}
break;
default:
ctx.logger.warn('handleCallback', JSON.stringify(result));
break;
}
}
//获取城市配置
async cityConfigs() {
const {ctx, service} = this;
const result = await service.task.getCityList();
ctx.success({
code: 0,
data: result
});
}
}
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',
},
},
};
}
//获取token
async partnerCreate() {
const { ctx, service } = this;
try {
ctx.validate(this.createRule);
const token = await service.signature.createToken(ctx.request.body);
return ctx.body = {
code: 0,
data: { token },
msg: ''
}
} catch (err) {
ctx.logger.error('partnerCreate', err);
ctx.status = 200;
if (err.code == 'invalid_param') {
return ctx.body = { code: -1, msg: err.message || '' };
}
return ctx.body = { code: err.code || -1, msg: err.message || '' };
}
}
}
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,
};
},
};
'use strict';
const querystring = require('querystring');
const crypto = require('crypto');
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;
};
\ No newline at end of file
'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;
}
\ No newline at end of file
'use strict';
module.exports = app => {
const { DataTypes } = app.Sequelize;
const taskStatsu = app.model.define('taskStatsu', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
field: 'id',
},
orderId: {
type: DataTypes.STRING(255),
allowNull: false,
defaultValue: '',
primaryKey: true,
field: 'orderId',
},
taskId: {
type: DataTypes.STRING(255),
allowNull: false,
defaultValue: '',
field: 'taskId',
},
userId: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'userId',
},
cityId: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'cityId',
},
appkey: {
type: DataTypes.STRING(255),
allowNull: false,
field: 'appKey',
},
notifyUrl: {
type: DataTypes.STRING(500),
allowNull: true,
defaultValue: '',
field: 'notifyUrl',
},
callbackUrl: {
type: DataTypes.STRING(255),
allowNull: false,
defaultValue: '',
field: 'callbackUrl',
},
status: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'status',
},
note: {
type: DataTypes.STRING(8000),
allowNull: true,
defaultValue: '',
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: true,
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,
defaultValue: '',
field: 'text1',
},
text2: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'text2',
},
text3: {
type: DataTypes.STRING(255),
allowNull: true,
defaultValue: '',
field: 'text3',
},
}, {
tableName: 'taxh5_status',
// timestamps: false,
});
return taskStatsu;
};
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
const taxRouter = router.namespace(app.config.projectRootPath);
taxRouter.post('/getToken', controller.token.partnerCreate);// 合作方创建token
taxRouter.post('/getorderSn', controller.order.fetchOrderId);// 合作方获取订单号
taxRouter.get('/getCity', controller.task.cityConfigs);// 获取城市基础配置项
taxRouter.post('/getCode', controller.task.fetchCapture);// 获取验证码
taxRouter.post('/query', controller.task.submit);// 提交任务查询参数
taxRouter.post('/getData', controller.order.partnerShow);// 合作方获取订单数据
taxRouter.post('/callback', controller.task.handleCallback); // 处理回调结果,不对外
taxRouter.get('/helpInfo', controller.task.fetchCapture);// 获取帮助信息
};
'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: ['30s', '30s'],
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));
}
}
}
\ No newline at end of file
'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;
}
/**
* 将orderId状态缓存到redis和数据库
* @param {Object} key orderId
* - 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: { orderId: 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));
}
/**
* 获取orderSn状态 优先redis
* @param {Object} key orderSn
* @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: { orderId: key },
});
if (order) {
ctx.logger.info(`【Cache】get From Model ${key} order:`, JSON.stringify({ status: order.status, note: order.note }));
return order;
}
ctx.logger.error(`【Cache】get No Result ${key} `);
this.ctx.throw(400, { message: '无此订单号' });
}
}
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;
}
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 notice(order) {
const { ctx } = this;
const { orderId, notifyUrl, notice } = order;
if (notifyUrl && notice !== '1') {
const ret = await ctx.curl(notifyUrl, {
charset: 'utf-8',
timeout: ['30s', '30s'],
contentType: 'json',
method: 'POST',
data: {
orderSn: orderId
},
}
)
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, cityListAPI } = config;
this.cityListAPI = cityListAPI;
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;
}
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: ['30s', '30s'],
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: ['30s', '30s'],
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: ['30s', '30s'],
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: ['30s', '30s'],
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: ['30s', '30s'],
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: ['30s', '30s'],
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: ['30s', '30s'],
dataType: 'json',
contentType: 'json',
});
return result.data;
}
async fetchCityFormIp() {
const { ctx } = this;
const { ip } = ctx.request;
ctx.logger.info(ctx.request);
const url = `https://api.map.baidu.com/location/ip?ak=3TBenWOhPygtFFazaR5kSibU&ip=${ip}`;
const result = await ctx.curl(url, {
charset: 'utf-8',
timeout: ['30s', '30s'],
dataType: 'json',
contentType: 'json',
});
if (result.data.status === 0) {
return result.data.content.address_detail.city;
}
ctx.logger.error('fetchCityFormIp', url, JSON.stringify(result.data));
return '北京市';
}
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: ['30s', '30s'],
dataType: 'json',
contentType: 'json',
});
ctx.logger.info(`fetchScriptByCityName,${baseURL + fetchScriptByCityNameUrl + '?name=' + name}`, 'result:', JSON.stringify(result.data));
return result.data;
}
async fetchScriptIdByIp() {
const city = await this.fetchCityFormIp();
const scriptList = await this.fetchScriptByCityName(city);
return scriptList;
}
async fetchScriptName(scriptId) {
try {
const city = await this.fetchOneScripts(scriptId);
return city.name || '未知';
} catch (err) {
return '未知';
}
}
async fetchScriptList() {
const { cityListAPI, ctx } = this;
const result = await ctx.curl(cityListAPI, {
charset: 'utf-8',
timeout: ['30s', '30s'],
dataType: 'json',
contentType: 'json',
});
ctx.logger.info(`fetchScriptList,${cityListAPI}`, 'result:', JSON.stringify(result.data));
return result.data;
}
}
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: ['30s', '30s'],
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, signatureType } = this;
const result = await this._request(fetchOrderIdUrl, {
method: 'post',
data: { ...params, type: signatureType },
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: ['30s', '30s'],
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} = this;
const {taskAPI, LOCK_KEY} = config;
this.baseURL = taskAPI.host;
this.newbaseURL = taskAPI.newhost;
this.createTaskUrl = taskAPI.createTaskUrl;
this.submitTaskUrl = taskAPI.submitTaskUrl;
this.fetchCodeUrl = taskAPI.fetchCodeUrl;
this.fetchTaskUrl = taskAPI.fetchTaskUrl;
this.cityConfigUrl = taskAPI.cityConfigUrl;
this.LOCK_KEY = LOCK_KEY;
}
_request(url, type, opts) {
const {ctx, baseURL, newbaseURL} = this;
url = (type === 'gsgj') ? `${newbaseURL}${url}` : `${baseURL}${url}`;
opts = {
charset: 'utf-8',
timeout: ['30s', '30s'],
dataType: 'json',
contentType: 'json',
...opts,
};
ctx.logger.info('_request', url, type);
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 create(data) {
const {createTaskUrl, ctx} = this;
const result = await this._request(createTaskUrl, ctx.app.channelType, {
method: 'post',
data: {cityId: data},
});
ctx.logger.info(`【Task】create ${createTaskUrl} cityId: ${data} result:`, JSON.stringify(result.data));
ctx.logger.info('channelType', ctx.app.channelType);
this._checkSuccess(result);
return result.data.data.taskId;
}
async fetchCapture({taskId, type}) {
const {fetchCodeUrl, ctx} = this;
let channelType = taskId.length > 20 ? 'gsgj' : '51gs';
const result = await this._request(fetchCodeUrl, channelType, {
method: 'post',
data: {
taskId,
type,
},
});
ctx.logger.info(`【Task】fetchCapture ${fetchCodeUrl} params`, JSON.stringify({
taskId,
type,
}), result.data.code);
this._checkSuccess(result);
return result.data.data;
}
async submit(data) {
const {submitTaskUrl, ctx} = this;
let channelType = data.taskId.length > 20 ? 'gsgj' : '51gs';
const result = await this._request(submitTaskUrl, channelType, {
method: 'post',
data,
});
ctx.logger.info(`【Task】submit ${submitTaskUrl} params`, JSON.stringify(data), JSON.stringify(result.data));
this._checkSuccess(result);
return result;
}
async fetchTask(data) {
const {fetchTaskUrl, ctx} = this;
let channelType = data.taskId.length > 20 ? 'gsgj' : '51gs';
const result = await this._request(fetchTaskUrl, channelType, {
method: 'post',
data,
});
ctx.logger.info(`【Task】fetchTask ${fetchTaskUrl} params`, JSON.stringify(data), JSON.stringify(result.data));
return result.data;
}
async getCityList() {
const {cityConfigUrl, ctx} = this;
let cityLists = [];//对外城市列表
let cityTypeLists = [];//不对外城市列表,含渠道(51/管家)
let newCityMap = new Map();
const newret = await this._request(cityConfigUrl, 'gsgj', {method: 'get'});
ctx.logger.info(`【Task】getCityList params gsgj`, newret.status, newret.data.data.length);
this._checkSuccess(newret);
newret.data.data.map(Prov => {
Prov.citys.map(city => {
newCityMap.set(String(city.id), city)
})
});
const ret = await this._request(cityConfigUrl, '51gs', {method: 'get'});
ctx.logger.info(`【Task】getCityList params 51gs`, ret.status, ret.data.data.length);
this._checkSuccess(ret);
ret.data.data.map(Prov => {
let newProv = {provinceName: Prov.provinceName, citys: []};
Prov.citys.map(city => {
city.type = "51gs";
if (city.state === -1 && newCityMap.get(String(city.id)) && newCityMap.get(String(city.id)).state === 1) {
city = newCityMap.get(String(city.id));
city.type = "gsgj";
ctx.logger.info('city', city)
}
if (city.state != 1) {
city.state = -1;
}
newProv.citys.push({
province: city.province,
name: city.name,
id: city.id,
state: city.state,
queryParam: city.queryParam
});
cityTypeLists.push({
province: city.province,
name: city.name,
id: city.id,
state: city.state,
type: city.type,
});
});
cityLists.push(newProv);
});
ctx.app.cityTypeLists = cityTypeLists;
// ctx.logger.info('-------------', JSON.stringify(ctx.app.cityTypeLists))
return cityLists;
}
}
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: ['30s', '30s'],
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 (let gjjItem of data.data.gjj_data) {
for (let text of clearGjj) {
if (!(passID && text == 'ID')) {
delete gjjItem.gjj_brief[text];
}
}
delete gjjItem.gjj_account_analyzed_data;
}
for (let loanItem of data.data.loan_data) {
for (let 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
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAkh7eUVgeY17P4Q4p6ORhHMwQjIXf7Xvmol1Hm969lRv4LPGb
AOpcZ7MjAm41th2eaajOyMkuKOcPymzGFusZlteLq34iUrYwPUGt55GvMMs2uuCb
iDYOFXt6hXMMa06PyTRukQbhCyzld/Ndhm9YvE+Y7X+C6f/mnzAGbfIftV/nEjgZ
3l1CHv96gACzO8z3ALe6MgHBxBF5LyS2b+++v6vd9V+kCPFI8x0AE9GZz1+QOAvO
w+uSd6j6NcLuH8aWaAyXuT1jubUQZtLnp3TqaSS2Md0UOJCQUfdanDWdempzo+E9
f5tWC8xEjthLsS9DZruzyF1FoSmxJkeOScmcZQIDAQABAoIBAARdk7rObSn+3SsW
Jz5kBFq95gisv0HzH7LeIpOPlg5sZX/CQCVI2zXl7jfWXxhvzhnOB0+MYyqprJkZ
otlwcLVG/09CV3gtJUfPPIjcm2VTzPDMYRkytD0EEWcHRum10SnrvRnsILEayEhL
JxIrJXWK00DVPG4NTTCYWLjUMQpUJWNsXVs/t8bX6c1utViJo3cR/5obQWrNXNYM
qHUfeUHInthHQOhv26dSSAzbDNg2m8tVYyDQc8bNd7MPyMLQvlS9YeFezviP6iV6
oMjI5cLJHQLYBTeiGz4tMSo3r4He9Ib3+yfP5KRqi6ZgZ4gtp0Of3CZCckB5HyTP
GDuvXIkCgYEA7Ct9osme4NWljtczzX6vLdwlNXmLws0t4W77MaN3ZCKxkAR7Ti1j
pBSbgsuFgto1jeXmK8VyLpdu0Aa/vkgBjSxhfhNW6AO+rJGH4mAavuygBTvrlOdv
uWIrbe2tCKa3e86weoyp8YEwCpghFKzVeluSGHyOo47jgyTCwQ0rB8cCgYEAnmPA
5obf+nJyJ6BdqW7NPvuWnUl5+wjUeTum9+Iu00H+quoUjmFWMi6H2OrNC0lvkJRp
TXXE4kYL0K818HvKHbJsQt2CBqUceZ3BcRcEl0MjLntuOH+AK1yFJYCpTcJhVKwR
46mWmImrpVDsT0JuQSmcK1y56I3HqwICtEsN8nMCgYEAsydOuBWAe4g2fgQMHP/T
/dL5OvaIKe8htdhNn1skr4aN8fUkYKqX4plrWq3vCtNjOtBCacPvGR7xBceI3tya
qLAZCN282GY214vSa8yBnYG85huNWzixjQzGay6YS27E05t4To60QCrC+dZridaO
XrJmQkMCpVo4hnx1bKMDmHMCgYATyA+aevPUOqDpNA0ekRkPKarI4Blc8eBfd8TF
prkEZ3Sf8fY5RgzW3ZrXy5NqOnS1kOOJ6hB51he5q3hIHZ3DkboVq8aGf+6Lfdlf
/2jyX08wiffdFId0Yuy6H1SFwqYXRhpB3bdSO7d1QSMSTxCoEMNRYxZQ5gwu3mRq
Egme4wKBgQDM4HREYYu7w7pAJqMnuJQB1BXkJxzg5+ywtNir3ywl8GCn7RPe4VVF
IrGtRXGDPuuxlhcxIaKICs5Cz1XRsqHl8K+coeAKzPXbIh4r/XUigOmUGETmE3vH
g0EYqpMDU40ezdkG3CaxtDlBiyC2gx/lj8rK8rYFcVkzFg1V75HFtQ==
-----END RSA PRIVATE KEY-----
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIFyTCCBLGgAwIBAgIQUE20dduC0RvXQL5iw5XxEjANBgkqhkiG9w0BAQsFADBE
MQswCQYDVQQGEwJDTjEaMBgGA1UECgwRV29TaWduIENBIExpbWl0ZWQxGTAXBgNV
BAMMEFdvU2lnbiBPViBTU0wgQ0EwHhcNMTcwMzIxMTE0NzM4WhcNMTkwMzIxMTE0
NzM4WjB6MQswCQYDVQQGEwJDTjEtMCsGA1UECgwk5p2t5bee54WO6aW8572R57uc
5oqA5pyv5pyJ6ZmQ5YWs5Y+4MRIwEAYDVQQHDAnmna3lt57luIIxEjAQBgNVBAgM
Cea1meaxn+ecgTEUMBIGA1UEAwwLKi41MWdqai5jb20wggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCSHt5RWB5jXs/hDino5GEczBCMhd/te+aiXUeb3r2V
G/gs8ZsA6lxnsyMCbjW2HZ5pqM7IyS4o5w/KbMYW6xmW14urfiJStjA9Qa3nka8w
yza64JuINg4Ve3qFcwxrTo/JNG6RBuELLOV3812Gb1i8T5jtf4Lp/+afMAZt8h+1
X+cSOBneXUIe/3qAALM7zPcAt7oyAcHEEXkvJLZv776/q931X6QI8UjzHQAT0ZnP
X5A4C87D65J3qPo1wu4fxpZoDJe5PWO5tRBm0uendOppJLYx3RQ4kJBR91qcNZ16
anOj4T1/m1YLzESO2EuxL0Nmu7PIXUWhKbEmR45JyZxlAgMBAAGjggJ/MIICezAM
BgNVHRMBAf8EAjAAMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly93b3NpZ24uY3Js
LmNlcnR1bS5wbC93b3NpZ24tb3ZjYS5jcmwwdwYIKwYBBQUHAQEEazBpMC4GCCsG
AQUFBzABhiJodHRwOi8vd29zaWduLW92Y2Eub2NzcC1jZXJ0dW0uY29tMDcGCCsG
AQUFBzAChitodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvd29zaWduLW92Y2Eu
Y2VyMB8GA1UdIwQYMBaAFKETVNxWcywngsrIhO/uvwD9X6tWMB0GA1UdDgQWBBQx
Tqk5iXll02OPy0mts+ag5oVvXTAOBgNVHQ8BAf8EBAMCBaAwggEgBgNVHSAEggEX
MIIBEzAIBgZngQwBAgIwggEFBgwqhGgBhvZ3AgUBDAIwgfQwgfEGCCsGAQUFBwIC
MIHkMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBGoHAVXNhZ2Ugb2Yg
dGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdHJpY3RseSBzdWJqZWN0ZWQgdG8gdGhlIENF
UlRVTSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCAoQ1BTKSBpbmNv
cnBvcmF0ZWQgYnkgcmVmZXJlbmNlIGhlcmVpbiBhbmQgaW4gdGhlIHJlcG9zaXRv
cnkgYXQgaHR0cHM6Ly93d3cuY2VydHVtLnBsL3JlcG9zaXRvcnkuMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAhBgNVHREEGjAYggsqLjUxZ2pqLmNvbYIJ
NTFnamouY29tMA0GCSqGSIb3DQEBCwUAA4IBAQARCLMq8pjDahV05zThImTR9i4j
vfaYxfdQLJP5DyCbiCNi8Lu67XeOXkEaW1UqQ0/qtH39PHppBwobwdP/Au9rwQhU
VLbVP1G32Sg4u6Hs4PvQCnuVvmcsAoDEDXQ6cjLX/jDh4AYAuCCOja3PhVJWWpI4
uQlGEsupuM8mAkqjc4Cy+v7uIRUCjDdcHUR3x3oC5GgKUGEwj0BbW6xEqiHPoYZz
tfE0DQoLAsxvIQBx437XFzxgjp6soq2mtCh38L3rgUnKO8acfZA1h0FgFsK4rQZP
lTUZD1iP6a+ofU1usVlGoLfqhwc7mS7D5yo9mcdN8HxUQuPtjoRQ0sM1asql
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEtTCCA52gAwIBAgIRAO8FGnQaHZQJ/KXkZA+NPJswDQYJKoZIhvcNAQELBQAw
fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu
QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG
A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xNjExMDkwODMzNDRa
Fw0yNjExMDkwODMzNDRaMEQxCzAJBgNVBAYTAkNOMRowGAYDVQQKDBFXb1NpZ24g
Q0EgTGltaXRlZDEZMBcGA1UEAwwQV29TaWduIE9WIFNTTCBDQTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAKRzU7QtbSdi6uUiqewzx81eEdrg0RROHTs1
eXndSwxxUAVDC+FPYvpgWc+bYMVjUJQEIP+SNzsIGvB/YoabRoN7cLBDzPTgYnW8
Pl/wYWXuGNyr1E7bV9Fec37HlvhE39Ntwp31gjMFwTOZ7Zw0QzS7w9PjO4A4anwb
maBJgrRa3GFSgoJ+WIr5brQ6hEgm7rKRNPx6L9Sj2aSl/EWRPPv73j5xeWGcgOPp
U+8eZmqpX+XfCl34o5OQJWi/F7bACetVhvFtWGuLNcZ0eYwU13jOEx3NNsILzIYP
oWJztxd3aPkQOX6cNbJGTvLRcfmGDM0ASq3/BsCrR0o/ruCcd6cCAwEAAaOCAWYw
ggFiMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFKETVNxWcywngsrIhO/u
vwD9X6tWMB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C84oQ3RnX3MA4GA1UdDwEB
/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwNQYDVR0fBC4w
LDAqoCigJoYkaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMGsG
CCsGAQUFBwEBBF8wXTAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2Vy
dHVtLmNvbTAxBggrBgEFBQcwAoYlaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBs
L2N0bmNhLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0
cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQCLBeq0MMgd
qULSuAua1YwHNgbFAAnMXd9iiSxbIKoSfYKsrFggNCFX73ex4b64iIhQ2BBr82/B
MNpC4rEvnr1x0oFv8DBO1GYimQaq8E9hjnO1UYYEPelVsykOpnDLklTsBZ4vhhq/
hq1mbs+6G+vsAjO9jVnuxP6toOTNBqvURRumMF0P165MoFdh0kzSjUts+1d8Llnb
DJaZht0O19k1ZdBBmPD3cwbTI+tChOELAVt4Nb5dDGPWqSxc5Nl2j95T3aK1KL2d
2vV16DSVShJIz04QHatcJlNZLJDbSu70c5fPU8YiJdRpfkubANAmwcDB+uNhtYz+
zEji0KnE2oNA
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEtDCCA5ygAwIBAgIRAJOShUABZXFflH8oj+/JmygwDQYJKoZIhvcNAQELBQAw
PjELMAkGA1UEBhMCUEwxGzAZBgNVBAoTElVuaXpldG8gU3AuIHogby5vLjESMBAG
A1UEAxMJQ2VydHVtIENBMB4XDTA4MTAyMjEyMDczN1oXDTI3MDYxMDEwNDYzOVow
fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu
QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG
A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAOP7faNyusLwyRSH9WsBTuFuQAe6bSddf/dbLbNax1Ff
q6QypmGHtm4PhtIwApf412lXoRg5XWpkecYBWaw8MUo4fNIE0kso6CBfOweizE1z
2/OuT8dW1Vqnlon686to1COGWSfPCSe8rG5ygxwwct/gounS4XR1Gb0qnnsVVAQb
10M5rVUoxeIau/TA5K44STPMdoWfOUXSpJ7yEoxR+HzkLX/1rF/rFp+xLdG6zJFC
d0wlyZA4b9vwzPuOHpdZPtVgTuYFKO1JeRNLukjbL/ly0znK/h/YNHL1tEDPMQHD
7N4RLRddH7hQ0V4Zp2neBzMoylCV+adUy1SGUEWp+UkCAwEAAaOCAWswggFnMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAh2zcsH/yT2xc3tu5C84oQ3RnX3MFIG
A1UdIwRLMEmhQqRAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNw
LiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQYIDAQAgMA4GA1UdDwEB/wQEAwIB
BjAsBgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vY3JsLmNlcnR1bS5wbC9jYS5jcmww
aAYIKwYBBQUHAQEEXDBaMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1j
ZXJ0dW0uY29tMC4GCCsGAQUFBzAChiJodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0u
cGwvY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw
Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAI3m/UBmo0yc
p6uh2oTdHDAH5tvHLeyDoVbkHTwmoaUJK+h9Yr6ydZTdCPJ/KEHkgGcCToqPwzXQ
1aknKOrS9KsGhkOujOP5iH3g271CgYACEnWy6BdxqyGVMUZCDYgQOdNv7C9C6kBT
Yr/rynieq6LVLgXqM6vp1peUQl4E7Sztapx6lX0FKgV/CF1mrWHUdqx1lpdzY70a
QVkppV4ig8OLWfqaova9ML9yHRyZhpzyhTwd9yaWLy75ArG1qVDoOPqbCl60BMDO
TjksygtbYvBNWFA0meaaLNKQ1wmB1sCqXs7+0vehukvZ1oaOGR+mBkdCcuBWCgAc
eLmNzJkEN0k=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQDCG2+xd72ZIC4vpb3Eb0WY6itr0n1ZPCR/lI0UFT16RExI
35Bs/GWcxHWUzEEGweVgeMzRITOmj5bZt3pfMY5XkON4bKmKynONLeNamPYB2bNu
qd7Hl4uy1N6NLTNl4NdWhwgjPxXgSs26FFybgdaVKOXQhSqUSLxfp+2bj1NohQID
AQABoAAwDQYJKoZIhvcNAQELBQADgYEAgo9TpXS0aTB41gEB29/+vP5I+Dttc3i5
T1IHZBiLwZudCShy5ZCDTks195BXbgTQOKDtEQkuzUE4L9L1PkXsLBE3Zvy3S5VF
loXGPBP6iDJjR559QzakAn8dJVV6I+9J3ryoOdN4vyzo1puU8eFnmfsJ57NFk6sX
mf8kdYd0XYo=
-----END CERTIFICATE REQUEST-----
-----BEGIN CERTIFICATE-----
MIICATCCAWoCCQDstPb/4nzmRjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMB4XDTE3MDUxMTA5MzEzN1oXDTE4MDUxMTA5MzEzN1owRTELMAkG
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwhtv
sXe9mSAuL6W9xG9FmOora9J9WTwkf5SNFBU9ekRMSN+QbPxlnMR1lMxBBsHlYHjM
0SEzpo+W2bd6XzGOV5DjeGypispzjS3jWpj2Admzbqnex5eLstTejS0zZeDXVocI
Iz8V4ErNuhRcm4HWlSjl0IUqlEi8X6ftm49TaIUCAwEAATANBgkqhkiG9w0BAQsF
AAOBgQAR4K4Ny36Tnc6jZM4pGRywgcMpjIdBuAhIxexadM1DL1jmUIE0spSK4S8S
60RC387DEa5u2x1NyB0wRaeF6bDgNhVJisglfMuu6QS262XHG4WhVmV5vm06c+ET
0RZv9TqrEjuvWXPHNFU7zvvFMFAj4Y7nxgB2zx9OrSKCCesB3g==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDCG2+xd72ZIC4vpb3Eb0WY6itr0n1ZPCR/lI0UFT16RExI35Bs
/GWcxHWUzEEGweVgeMzRITOmj5bZt3pfMY5XkON4bKmKynONLeNamPYB2bNuqd7H
l4uy1N6NLTNl4NdWhwgjPxXgSs26FFybgdaVKOXQhSqUSLxfp+2bj1NohQIDAQAB
AoGBAKWI5F4CccyupvS3cfidtErOGS2gmomJQs8SjqW732vv5uaW0gI/1SA2Ytf8
wM/Ud5soKfOHTxcSiWEumcuo5WvEmoNHXJfunVErnYG4Ph2FsiBihL2wPrGnq0E5
XZnX0ZNwcBw+dvfDXKiAq4QOrSyldtNuQuw3bZZ+5DOZkgSZAkEA/b69YTjNszX7
9KDiWtIeu5dw6mkzrdL3+M8DpQk1E7ndLKbKKdZMavd/OHkjbJoMriVy57TLz8HL
OtV6GnEo0wJBAMPVBcnlI8A78mEf4/m6SoazTPV1FQfZknC1rKIo1qSNtP/RcjoW
dnK9Ar4dnmuUvKXKoYKlCFcmERNeo7c80kcCQAYBUJwPaxbVrTvR3umFVYLdB6gU
i0uO1Z2G0LBEMoRf/rMC03//+VkCuHkOrN7yGmC4tCp1pekpzfR7fuNHUE8CQQCw
aAia4kreNCIW079tih7wUDwXMK0NMTT1SvKD8P3Jpc1SVL3tDacNnK4HzG6Uwptd
TbdIFJn6x1PCexJHUgapAkB7Jvoweu9Jja1arukVWHIKZbqM3Hmh1GjgkuxoKeZW
ZoaC/ASM0rsc9XHUaSuQjAlwDk/H47vgEuxXu2BklGrJ
-----END RSA PRIVATE KEY-----
module.exports = {
StorageHost:"http://tv.51gjj.com:11250",
SignHost:'http://tj2.51gjj.com:5118',
TaskHost:'http://ts1.51gjj.com:6824',
newTaskHost:'http://tt.51gjj.com:7001',
callbackUrl:'https://t.51gjj.com/IncomeTaxAPI/result',
signType:'incometax',
database: {
"connectionLimit" : 50,
"host": "rm-bp1272001633qc0x9.mysql.rds.aliyuncs.com",
"user": "hexin",
"password": "gYUHszn9#q",
"database": "node_gjj"
},
port: 10017,
log4jsConfig: {
"appenders": {
"console": {
"type": "console"
},
"default": {
"type": "dateFile",
"filename": "./logs/",
"alwaysIncludePattern": true,
"pattern": "IITAPI-yyyyMMdd.log"
}
},
"categories": {
"default": {
"appenders":["console", "default"],
"level": "trace"
}
},
"replaceConsole": true
},
};
'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_5141';
// add your config here
config.middleware = ['requestLog', 'errorHandler'];
// 是否启用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 = '/taxapi';
config.redis = {
client: {
port: 6379,
host: '116.62.55.137',
password: 'DEV8redis',
db: 0,
},
};
config.taskAPI = {
host: 'http://tm.51gjj.com:6824',
newhost: 'http://tt.51gjj.com:7001',
fetchHubsUrl: '',
createTaskUrl: '/IncomeTax/createItTask',
fetchCodeUrl: '/IncomeTax/getItCode',
submitTaskUrl: '/IncomeTax/loginItWeb',
fetchTaskUrl: '/IncomeTax/getItData',
cityConfigUrl: '/IncomeTax/getItSetting'
};
config.partnerAPI = {
host: 'https://dev-nginx.jianbing.com/zeus-api/v1',
fetchTheme: '/chaos/partners/theme',
fetchScripts: '/chaos/partners/scripts',
redisThemePrefix: 'URANUS.HF.PARNTERS.THEME',
redisScriptsPrefix: 'URANUS.HF.PARNTERS.SCRIPTS',
};
config.scriptsAPI = {
host: 'https://dev-nginx.jianbing.com/zeus-api/v1',
fetchScriptsUrl: '/chaos/it/two_dimension_array/queries',
fetchOneScriptUrl: '/chaos/it/two_dimension_array/info',
fetchParamsInfoUrl: '/chaos/it/login_param_map',
fetchQueryButtonUrl: '/chaos/it/query_button',
fetchHelpUrl: '/chaos/it/help',
fetchNoticeUrl: '/chaos/it/notice',
fetchHubSeriptsUrl: '/chaos/it/hubs',
fetchScriptByCityNameUrl: '/chaos/it/city_scripts',
redisScriptsKey: 'URANUS.IT.SCRIPTS',
redisParamsKey: 'URANUS.IT.PARAMS',
};
config.storageAPI = {
host: 'http://tv.51gjj.com:11252',
writeUrl: '/data',
readUrl: '/IncomeTax',
writeType: 'incomeTax',
readDataKey: 'incometaxData',
};
config.washAPI = {
host: '',
washUrl: '',
};
config.signatureAPI = {
host: 'http://tj3.51gjj.com:5118',
fetchTokenUrl: '/Access/GetToken',
fetchOrderIdUrl: '/Order/GetOrderSn',
signatureUrl: '/Access/SignValidityCheck',
fetchParnterUrl: '',
signatureType: 'incomeTax',
customerUrl: '/customer/query'
};
config.lockKeys = {
fecthHub: 'URANUS.IT.HUBS.LOCK',
fecteToken: 'URANUS.IT.TOKEN.LOCK',
token: 'URANUS.IT.TOKEN',
fecthParnters: 'URANUS.PARNTERS.LOCK',
taskPrefix: 'URANUS.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.GJJ_OpenAPI = {
// appKey: '60670203E411FD62BA9E953CFB73F881',
// appSecret: '0BDD1ECC147503C477563E5C1438C366D70E4F80',
// };
config.callbackUrl = 'https://dev-nginx.jianbing.com/taxh5/callback';
return config;
};
'use strict';
module.exports = () => {
const config = exports = {};
config.debug = true;
config.logger = {
dir: '/jianbing/logs/taxapi',
};
config.projectRootPath = '/taxapi';
config.redis = {
client: {
port: 6379,
host: process.env.REDIS_HOST,
password: process.env.REDIS_PWD,
db: 0,
},
};
config.taskAPI = {
host: process.env.TASKAPI_HOST,
newhost: 'http://tt.51gjj.com:7001',
fetchHubsUrl: '',
createTaskUrl: '/IncomeTax/createItTask',
fetchCodeUrl: '/IncomeTax/getItCode',
submitTaskUrl: '/IncomeTax/loginItWeb',
fetchTaskUrl: '/IncomeTax/getItData',
cityConfigUrl: '/IncomeTax/getItSetting'
};
config.partnerAPI = {
host: process.env.PARTNERAPI_HOST,
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.scriptsAPI = {
host: 'https://dev-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: 'DATA_SERVER_SHEBAO.SCRIPTS',
redisParamsKey: 'DATA_SERVER_SHEBAO.PARAMS',
redisScriptListKey: 'DATA_SERVER_SHEBAO.SCRIPTLIST',
};
config.storageAPI = {
host: process.env.STORAGEAPI_HOST,
writeUrl: '/data',
readUrl: '/IncomeTax',
writeType: 'incomeTax',
readDataKey: 'incometaxData',
};
config.washAPI = {
host: '',
washUrl: '',
};
config.signatureAPI = {
host: process.env.SIGNATUREAPI_HOST,
fetchTokenUrl: '/Access/GetToken',
fetchOrderIdUrl: '/Order/GetOrderSn',
signatureUrl: '/Access/SignValidityCheck',
fetchParnterUrl: '',
signatureType: 'incomeTax',
customerUrl: '/customer/query',
};
config.lockKeys = {
fecthHub: 'NEWSB.HF.HUBS.LOCK',
fecteToken: 'NEWSB.HF.TOKEN.LOCK',
token: 'NEWSB.HF.TOKEN',
fecthParnters: 'NEWSB.PARNTERS.LOCK',
taskPrefix: 'NEWSB.TASK',
};
config.sequelize = {
datasources: [{
// 东八时区
timezone: '+08:00',
delegate: 'model',
baseDir: 'model',
dialect: 'mysql',
host: process.env.MYSQL_PACHONG_HOST,
database: process.env.MYSQL_DATA_SERVER_DB_NAME,
username: process.env.MYSQL_USER,
password: process.env.MYSQL_PWD,
port: process.env.MYSQL_PORT,
}],
};
config.callbackUrl = process.env.CALLBACK_URL;
return config;
};
\ No newline at end of file
'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',
};
const signAPI=require('../services/ValidationAPI');
module.exports={
async getToken(ctx){
try{
console.log(ctx.request.body)
let tokenObj= await signAPI.getToken(ctx.request.body);
ctx.body=tokenObj
}catch (err){
console.error(err)
ctx.body={code:-1,msg:"服务出错"}
}
},
};
\ No newline at end of file
const taskAPI=require('../services/taskAPI');
const signAPI=require('../services/ValidationAPI');
const staticVari=require('../services/staticVari');
const MongoIO=require('../services/MongoIO')
const db=require('../utils/db-util');
const log=require('../utils/log');
const config=require('../config');
const OSS = require('ali-oss');
const client = new OSS.Wrapper({
bucket: '51query',
accessKeyId: 'LTAI6Glaum6TDzKf',
accessKeySecret: 'zmNjWhmOD1nIClZ3hoDmGrdNNiBJBi',
secure: true,
region: "oss-cn-hangzhou"
})
function throwServiceError(values) {
this.code=values.code;
this.message=values.message||values.msg||"";
this.toString = function() {
return this.code + this.message
};
}
module.exports={
async getCity(ctx){
try{
let cityList=staticVari.cityList();
ctx.body={
code:0,
data:cityList
}
}catch(err){
log.error(err)
ctx.body={
code:-1,
msg:""
}
}
},
async getHelpInfo(ctx){
try{
let helpInfo=staticVari.helpInfo();
ctx.body={
code:0,
data:helpInfo
}
}catch(err){
log.error(err)
ctx.body={
code:-1,
msg:""
}
}
},
async createTask(ctx){
log.info("createTask",JSON.stringify(ctx.request.body));
try{
const {signParams,cityId}=ctx.request.body;
const appKey=signParams.params.appKey;
let orderSnObj= await signAPI.getOrderSn(signParams);
if(orderSnObj.code!==0){
throw new throwServiceError(orderSnObj)
}
let orderSn=orderSnObj.data.orderSn;
let city=staticVari.getCityById(cityId);
console.log(city)
let taskId= await taskAPI.createTask(cityId,city.type);
let insertParams = {
taskId: taskId,
orderId: orderSn,
appKey: appKey,
status: 'init',
note: JSON.stringify({code: 105, msg: '初始状态'}),
cityId: cityId,
createDate:new Date().toLocaleString(),
updateDate: new Date().toLocaleString()
};
let insertRet= await db.insertObj([insertParams]);
if(insertRet.affectedRows!==1){
throw new throwServiceError({code:-1,msg:"未知错误"})
}
staticVari.setOrderSnMap(orderSn,{
taskId: taskId,
status: 'init',
note:{
code:105,
msg:"init status"
},
appKey:appKey,
});
ctx.body={
code: 0,
orderSn:orderSn,
msg: "任务创建成功"
}
}catch (err){
log.error("createTask",err,ctx.request.body)
if(err.hasOwnProperty('code')){
ctx.body=err
}else{
ctx.body={
code:-1,
msg:'服务器出错'
}
}
}
},
async getCode(ctx){
log.info("getCode",JSON.stringify(ctx.request.body));
const {orderSn,type}=ctx.request.body;
try{
let taskObj= await staticVari.getTaskByOrderSn(orderSn);
let taskId=taskObj.taskId;
let params = {taskId,type:type==="code"?"incometax_code":"incometax_phone_code "};
let CodeObj= await taskAPI.getCode(params);
if (CodeObj.data && CodeObj.data.taskId) {
delete CodeObj.data.taskId;
CodeObj.data.orderSn = orderSn;
}
ctx.body=CodeObj
}catch(err){
log.error('getCode',err,ctx.request.body);
if(err.hasOwnProperty('code')){
ctx.body=err
}else{
ctx.body={
code:-1,
msg:'服务器出错'
}
}
}
},
async query(ctx){
const {orderSn,params}=ctx.request.body;
log.info("query",ctx.request.body)
try{
let taskObj= await staticVari.getTaskByOrderSn(orderSn);
let queryParams = {
taskId: taskObj.taskId,
callbackUrl: config.callbackUrl+"?orderSn="+orderSn,
data: params
};
let queryObj=await taskAPI.submitParams(queryParams);
if (queryObj.data && queryObj.data.taskId) {
delete queryObj.data.taskId;
queryObj.data.orderSn = orderSn;
}
ctx.body=queryObj
}catch(err){
log.error('query',err,ctx.request.body);
if(err.hasOwnProperty('code')){
ctx.body=err
}else{
ctx.body={
code:-1,
msg:'服务器出错'
}
}
}
},
async getData(ctx){
log.info("getData",ctx.request.body)
try{
let orderSn=ctx.request.body.params.orderSn;
let sign=await signAPI.signValidation(ctx.request.body);
if(sign.code!==0){
throw new throwServiceError(sign)
}
let taskObj= await staticVari.getTaskByOrderSn(orderSn);
if(taskObj.status==="success"){
let data=await MongoIO.readData(orderSn)
log.info(data);
ctx.body=data;
}else{
taskObj.note.orderSn=orderSn;
log.info(taskObj.note);
ctx.body=taskObj.note;
}
}catch (err){
log.error('getData',err,ctx.request.body);
if(err.hasOwnProperty('code')){
ctx.body=err
}else{
ctx.body={
code:-1,
msg:'服务器出错'
}
}
}
},
async result(ctx){
try{
ctx.body="success";
const {orderSn} =ctx.query;
if(!orderSn){
throw new Error({code:"noOrderSn"})
}
const {taskId}= ctx.request.body;
log.info("result",taskId)
let taskObj=await staticVari.getTaskByOrderSn(orderSn);
let taskRet= await taskAPI.getData(taskId);
log.info("taskRet Code:",taskRet.code)
let updateObj={};
switch (taskRet.code){
case -1:
case 106:
case 102:
case 204:
taskRet.msg = taskRet.msg.replace(/\'/g, '"').replace(/\ /g, '');
staticVari.setOrderSnMap(orderSn,{
status:"failed",
note:{code:204,msg:taskRet.msg},
taskId,
});
updateObj={
status:"failed",
note:JSON.stringify({code:204,msg:taskRet.msg}),
taskId
};
break;
case 1:
if (taskRet.data && taskRet.data.taskId) {
delete taskRet.data.taskId;
taskRet.data.orderSn = orderSn;
}
staticVari.setOrderSnMap(orderSn, {
status: "next",
note: {code: 1, data: taskRet},
taskId
});
updateObj = {
status: "next",
note: JSON.stringify({code: 1, data: taskRet}),
taskId
};
break;
case 110:
staticVari.setOrderSnMap(orderSn, {
status: "query",
note: {code: 110, msg:"登录成功"},
taskId
});
updateObj = {
status: "query",
note: JSON.stringify({code: 110, msg:"登录成功"}),
taskId,
updateDate:new Date().toLocaleString()
};
break;
case 0:
taskRet.cityId = Number(taskRet.data.cityId);
taskRet.cityName = staticVari.getCityById(taskRet.data.cityId).name;
taskRet.taskId = taskRet.data.taskId;
taskRet.data= JSON.parse(taskRet.data.data);
taskRet.orderSn=orderSn;
taskRet.orderId=orderSn;
taskRet.appKey = taskObj.appKey;
taskRet.serviceType = 'incomeTax';
delete taskRet.code;
delete taskRet.msg;
let InsertMongo=await MongoIO.dataStorage(taskRet)
if(InsertMongo.code===0||InsertMongo.code==="0"){
staticVari.setOrderSnMap(orderSn, {
status: "success",
note: {code: 0, msg:"success"},
taskId,
});
updateObj = {
status: "success",
note: JSON.stringify({code: 0, msg:"success"}),
taskId,
updateDate:new Date().toLocaleString()
};
}else{
log.error("InsertMongo",JSON.stringify(taskRet))
staticVari.setOrderSnMap(orderSn, {
status: "failed",
note: {code: -1, msg:"数据存储出错"},
taskId
});
updateObj = {
status: "failed",
note: JSON.stringify({code: -1, msg:"数据存储出错"}),
taskId,
updateDate:new Date().toLocaleString()
};
}
break;
default:
log.warn('taskAPI.getData',taskRet)
break
}
let upDataDb=await db.updateData([updateObj,orderSn]);
if(upDataDb.affectedRows===1){
if(updateObj.hasOwnProperty('status')){
console.log("WHYUYYYYYYYYYYYYYYY")
console.log("WHYUYYYYYYYYYYYYYYY",taskObj.appKey,{orderSn})
staticVari.ServerSideCall(taskObj.appKey||"",{orderSn})
}
}
}catch (err){
console.error(err)
}
},
async getIncomeProve(ctx) {
log.info("getIncomeProve", ctx.request.body)
try {
let orderSn = ctx.request.body.params.orderSn;
let sign = await signAPI.signValidation(ctx.request.body);
if (sign.code !== 0) {
throw new throwServiceError(sign)
}
let taskObj = await staticVari.getH5TaskByOrderSn(orderSn);
if (taskObj.length > 0) {
let data = await getpage(orderSn,taskObj[0].taskId, ctx.request.body.file);
ctx.body = data;
} else {
taskObj = await staticVari.getapiTaskByOrderSn(orderSn);
if (taskObj[0].status === "success") {
let data = await getpage(orderSn,taskObj[0].taskId, ctx.request.body.file);
ctx.body = data;
} else {
ctx.body = {
code: -1,
msg: "未查询到此订单号",
orderSn:orderSn
};
}
}
} catch (err) {
log.error('getIncomeProve', err, ctx.request.body);
if (err.hasOwnProperty('code')) {
ctx.body = err
} else {
ctx.body = {
code: -1,
msg: '服务器出错'
}
}
}
}
};
async function getpage(orderSn,taskId, file) {
try {
if (file != undefined && /[0-9]{4}/.test(file)) {
return await client.get(`incometaxProve/${taskId}/${file}`).then(files => {
return {code: 0, msg: '获取成功', data: {file: file, data: (new Buffer(files.content).toString('base64'))}};
}).catch(error =>{
log.error("getpage", error);
return {code: -1, msg: '未查询到本年信息', orderSn: orderSn};
})
} else {
let result = await client.list({
prefix: `incometaxProve/${taskId}/`,
delimiter: '/'
});
let data = [];
if (result.objects === undefined) {
return {code: 101, msg: "未查询到此任务", orderSn: orderSn};
} else {
result.objects.map(function (obj, index) {
data[index] = client.get(obj.name).then(file => {
let rgx = new RegExp(`incometaxProve/${taskId}/`, 'g')
return {year: obj.name.replace(rgx, ''), data: (new Buffer(file.content).toString('base64'))};
})
});
let results = await Promise.all(data);
return {code: 0, msg: '获取成功', data: results};
}
}
} catch (e) {
log.error("getpage", e);
return {code: -1, msg: "系统错误", data: ""};
}
}
\ No newline at end of file
const path = require('path');
const Koa = require('koa');
const convert = require('koa-convert');
const views = require('koa-views');
const koaStatic = require('koa-static');
const bodyParser = require('koa-bodyparser');
var cors = require('koa-cors');
const util = require('util');
const cleanLog = require('./utils/cheanLog');
const log = require('./utils/log');
const koaLogger = require('koa-logger');
const config = require('./config');
const routers = require('./routers/index');
const app = new Koa();
// app.use((ctx)=>{
// console.log(ctx.headers);
// })
app.use(cors());
// 配置控制台日志中间件
app.use(koaLogger());
// 配置ctx.body解析中间件
app.use(bodyParser());
// 配置静态资源加载中间件
app.use(koaStatic(
path.join(__dirname , './public/')
));
app.use(async (ctx, next) => {
const token = ctx.header.authorization // 获取jwt
let payload;
if (token) {
try {
payload = await verify(token.split(' ')[1], secret) // // 解密,获取payload
console.log('payload',payload);
console.log(ctx.path)
if(config.authData[ctx.path]){
if(!config.authData[ctx.path].includes(payload.auth)){
ctx.status = 403;
ctx.body={status:'无权限'}
return
}
}
}catch (err){
console.log(err)
}
}
await next()
})
// 配置服务端模板渲染引擎中间件
app.use(views(path.join(__dirname, './views'), {
extension: 'ejs'
}));
// 初始化路由中间件
app.use(routers.routes()).use(routers.allowedMethods());
// 监听启动端口
app.listen( config.port )
log.info(`the server is start at port ${config.port}`);
cleanLog();
// console.log(`the server is start at port ${config.port}`);
This source diff could not be displayed because it is too large. You can view the blob instead.
{ {
"name": "IIT", "name": "tax_api",
"version": "1.0.0", "version": "1.0.0",
"description": "对接API服务web服务", "description": "个税API认证服务",
"main": "index.js", "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",
"mysql2": "^1.6.4",
"node-cache": "^4.2.0",
"node-uuid": "^1.4.8",
"uuid": "^3.3.2"
},
"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": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "start": "egg-scripts start --daemon --title=egg-server-gjj_api_server",
"stop": "egg-scripts stop --title=egg-server-gjj_api_server",
"docker": "eggctl start --title=egg-server-gjj_api_serverr",
"dev": "egg-bin dev --port 7002",
"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"
}, },
"keywords": [ "ci": {
"koa" "version": "8"
], },
"author": "HAYWAEL", "repository": {
"license": "ISC", "type": "git",
"dependencies": { "url": ""
"ali-oss": "^5.2.0", },
"antd-mobile": "^2.1.8", "author": "jd",
"antd-mobile-demo-data": "^0.2.0", "license": "MIT"
"array-tree-filter": "^2.1.0",
"ejs": "^2.5.5",
"jsonwebtoken": "^8.2.1",
"koa": "^2.5.0",
"koa-bodyparser": "^3.2.0",
"koa-cors": "0.0.16",
"koa-jwt": "^3.3.1",
"koa-logger": "^3.0.0",
"koa-mysql-session": "0.0.2",
"koa-router": "^7.0.1",
"koa-send": "^3.2.0",
"koa-session-minimal": "^3.0.3",
"koa-static": "^3.0.0",
"koa-views": "^5.2.0",
"log4js": "^2.6.0",
"moment": "^2.22.1",
"mysql": "^2.15.0",
"node-schedule": "^1.3.0",
"rc-form": "^2.2.0",
"request": "^2.85.0"
}
} }
{
"name" : "IITAPITest", // 应用名称
"script" : "./index.js", // 实际启动脚本
"cwd" : "./" // 当前工作路径
// "watch": [ // 监控变化的目录,一旦变化,自动重启
// "bin",
// "routers"
// ],
// "ignore_watch" : [ // 从监控目录中排除
// "node_modules",
// "logs",
// "public"
// ],
// "watch_options": {
// "followSymlinks": false
// },
// "error_file" : "./logs/app-err.log", // 错误日志路径
// "out_file" : "./logs/app-out.log" // 普通日志路径
// "env": {
// "NODE_ENV": "production" // 环境参数,当前指定为生产环境
// }
}
{
"name" : "nsbapi", // 应用名称
"script" : "./sbapi.js", // 实际启动脚本
"cwd" : "./", // 当前工作路径
"node_args" : "--max-old-space-size=3000"
// "watch": [ // 监控变化的目录,一旦变化,自动重启
// "bin",
// "routers"
// ],
// "ignore_watch" : [ // 从监控目录中排除
// "node_modules",
// "logs",
// "public"
// ],
// "watch_options": {
// "followSymlinks": false
// },
// "error_file" : "./logs/app-err.log", // 错误日志路径
// "out_file" : "./logs/app-out.log" // 普通日志路径
// "env": {
// "NODE_ENV": "production" // 环境参数,当前指定为生产环境
// }
}
!> 特别提醒: <br> 1. 时间戳(timestamp): 采用北京时间, 时间戳误差60秒内有效。
<br> 2. token: 获取token时,注意防并发,保持同步,以防新token生成后,老token还在使用导致失效。
<br> 3. appKey: 测试appKey的使用次数为2000次,请及时申请并更换为正式appKey。
# 文档更新说明
>| 更新日期 | 更新内容|
|:--------|---------|
# **1** 接入网址说明
## **1.1** 协议说明
> 只支持https
## **1.2** 域名说明
>| 名称 | 域名|
|:--------|---------:|
| API| ```https://t.51gjj.com/```|
# **2** API接口
## 2.1 获取个税城市基础配置项
>**请求URL:**
- ` IncomeTaxAPI/getCity `
------------
>**请求方式:**
>- Method: GET
------------
> **参数:**
```json
{
"code": 0,
"data": [
{
"provinceName": "浙江省",
"citys": [
{
"province": 1,
"name": "绍兴",
"id": 57,
"state": 1,
"queryParam": [
{
"loginParam": [
{
"note": "",
"name": "ID",
"type": "string"
},
{
"note": "",
"name": "password",
"type": "string"
},
{
"note": "{\"330601\":\"市本级\",\"330621\":\"柯桥区\",\"330624\":\"新昌县\",\"330681\":\"诸暨市\",\"330682\":\"上虞市\",\"330683\":\"嵊州市\"}",
"name": "menu",
"type": "radio"
}
]
}
]
},
{
"province": 1,
"name": "杭州",
"id": 81,
"state": 1,
"queryParam": [
{
"loginParam": [
{
"note": "",
"name": "ID",
"type": "string"
},
{
"note": "",
"name": "password",
"type": "string"
},
{
"note": "{\"330100\":\"市本级\",\"330109\":\"萧山区\",\"330110\":\"余杭区\",\"330122\":\"桐庐县\",\"330127\":\"淳安县\",\"330182\":\"建德市\",\"330183\":\"富阳区\",\"330185\":\"临安市\"}",
"name": "menu",
"type": "radio"
}
]
}
]
}
]
}
],
"msg": "请求成功"
}
```
**返回参数说明**
>|参数名|类型|说明|
|:----- |:-----|----- |
|provinceName |String |省份名称|
|id |int |城市id|
|province |int |省份id|
|queryParam |String |登录参数|
|state |int |城市状态|
|url |String |网站地址|
|province |String |省份id|
|name |String |城市名称|
**登录参数说明**
>|登录参数|登录参数说明|type|
|:----- |:-----|:-----|
|ID |身份证号|string|
|password |密码|string|
|name |姓名|string|
|phone |手机号|string|
|userName |用户名|string|
|code |验证码|string|
|idNo |证件号|string|
|phoneCode |手机验证码|string|
|taxpayerId |纳税人识别号|string|
|taxId |税务登记证号|string|
|email |邮箱|string|
!> 当登录参数为 type为'radio' 代表该参数类型为下拉菜单;
例如 当参数为
```json
{
"note": "{\"3001\":\"江门市区\",\"3002\":\"新会区\",\"3003\":\"台山市\",\"3004\":\"开平市\",\"3005\":\"鹤山市\",\"3006\":\"恩平市\"}",
"name": "区域",
"type": "radio"
}
```
!> 应将note中的数据解析,最终展示为单选框,或下拉菜单, 若当用户选择江门市区,则传回的登陆参数为 {"区域":"3001"}
## 2.2 获取个税城市查询提示信息
>**请求URL:**
- ` IncomeTaxAPI/getHelpInfo `
------------
>**请求方式:**
>- Method: GET
------------
> **参数:**
> **返回示例:**
- **返回示例**
```json
{
"code": 0,
"data": [
{
"cid": 1,
"city": "杭州",
"help": "[{\"desc\":\"如果您未曾在浙江政务服务网进行注册的,需要前往官网注册并设置相关信息后才可查询\",\"link\":{\"label\":\"立即注册\",\"url\":\"https://puser.zjzwfw.gov.cn/sso/usp.do?action=register&servicecode=njdh\"}},{\"desc\":\"如果您忘记了密码,需要登录浙江政务服务网找回密码\",\"link\":{\"label\":\"忘记密码\",\"url\":\"https://puser.zjzwfw.gov.cn/sso/usp.do?action=forgotPwd&servicecode=njdh\"}}]"
},
{
"cid": 2,
"city": "温州",
"help": "[{\"desc\":\"如果您未曾在浙江政务服务网进行注册的,需要前往官网注册并设置相关信息后才可查询\",\"link\":{\"label\":\"立即注册\",\"url\":\"https://puser.zjzwfw.gov.cn/sso/usp.do?action=register&servicecode=njdh\"}},{\"desc\":\"如果您忘记了密码,需要登录浙江政务服务网找回密码\",\"link\":{\"label\":\"忘记密码\",\"url\":\"https://puser.zjzwfw.gov.cn/sso/usp.do?action=forgotPwd&servicecode=njdh\"}}]"
}
]
}
```
> **返回参数说明**
|参数名|类型|说明|
|:----- |:-----|----- |
|cid |Number |个税中心编号|
|city |String |个税中心名称|
|help |Array |帮助信息内容|
## 2.3 创建访问令牌
>**请求URL:**
- ` IncomeTaxAPI/getToken `
------------
>**请求方式:**
>- Method: POST
- Content-Type: application/json
- Charset: UTF-8
------------
> **参数:**
>
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|sign |是 |String |签名 |
|appKey |是 |String |公钥 |
|timestamp |是 |String | 时间戳 (单位:ms) |
------------
>**请求示例**
``` json
{
"sign":"SDSKKL5KJJKLL6JK1L",
"params":{
"appKey":"3FD179425381644F95424B66BE06E3E4",
"timestamp":"1494828184314"
}
}
```
>**返回示例1**
``` json
{
"code": 0,
"data": {
"token": "cd4283827366490eb037bf1b4b28dadc"
}
}
```
>**返回示例2**
``` json
{
"code": 3000,
"msg": "参数错误"
}
```
>**返回参数说明**
>|参数名|类型|说明|
|:----- |:-----|----- |
|token |String |访问令牌(Token的有效期为2小时,当Token未失效时调用该接口,则返回新的Token,有效期重新计算,老的Token同时失效) |
|code |Number |状态码 |
|msg |String |错误信息 |
------------
>**备注**
> 状态码对应的错误信息
|code|错误信息|处理方式|
|:----- |:-----|----- |
|0 | 成功 | 需要注意并发 |
|101 |参数错误或缺失 |需检查参数是否缺失或错误 |
|3000 | 验签出错 |具体错误信息解释见4.2 |
## **2.4** 创建订单号
**简要描述:**
- 通过该接口创建订单号
订单号是查询任务和获取数据的唯一标识,请妥善保管,每次任务对应一个订单号
**请求URL:**
- path ` IncomeTaxAPI/getOrderSn `
**请求方式:**
- Method: POST
- Content-Type: application/json
- Charset: UTF-8
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|sign |是 |string |签名 |
|appKey |是 |string |公钥 |
|token |是 |string | 访问令牌 |
|timestamp |是 |string | 时间戳 (单位:ms) |
|cityId |是 |string |城市编号 |
**请求示例**
```json
{
"signParams": {
"params": {
"appKey": "3FD179425381644F95424B66BE06E3E4",
"token": "cd4283827366490eb037bf1b4b28dadc",
"timestamp": "1504828184314"
},
"sign": "SDSKKL5KJJKLL6JK1L",
},
"cityId": "323"
}
```
**返回示例1**
```json
{
"code": 0,
"orderSn": "e7b7040b-8ea1-4585-95cc-977925d24757",
"msg": "任务创建成功"
}
```
**返回示例2**
```json
{
"code": 3000,
"msg": "参数错误"
}
```
**返回参数说明**
|参数名|类型|说明|
|:----- |:-----|-----|
|orderSn |String |订单号 |
|code |Number |状态码 |
|msg |String |任务信息 |
**备注**
状态码对应的信息说明
|code|错误信息|处理方式|
|:----- |:-----|----- |
|0 | 成功 | 可以继续接下来的步骤 |
|101 |参数错误或缺失 |需检查参数是否缺失或错误 |
|3000 | 验签出错 |具体错误信息解释见4.2 |
|201 |城市维护或不支持 |因为cityId所在地区处于维护状态或不支持 |
|500 |服务出错 |由于网络或其他原因导致服务出现问题 |
## **2.5** 获取验证码
**简要描述:**
- 获取当前个税查询任务需要的验证码信息(即附录4.3所示的查询参数为phoneCode或code时候可调用该接口)
**请求URL:**
- ` IncomeTaxAPI/getCode `
**请求方式:**
- POST
- Content-Type = application/json
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|orderSn |是 |string |个税查询订单号 |
|type |是 |string | 验证码类型 code:图形验证码 phone_code:手机验证码 |
**请求示例**
```json
{
"orderSn":"1199a04a-d203-4d3d-b65b-0c07ce5fd9f7",
"type":"code"
}
```
**返回示例**
- type=code
```json
{
"code": 0,
"data": {
"img": "iVBORw0KGgoAAAANSUhEUgAAAFIAAAAlCAYAAADRC77iAAATTUlEQVRogc1aaY8dx3U9Vd1vmzcznDecIYczXMSdoihKkCyJUhRZ8hYrgZB8yJcA2QB9yPf8gvyMIAGyGEg+BAjgIIAdS5ENBXEsR0IoUtwkk5RJjkiKmzTkLG/prsq5t6pevyEZLY7NpAc9771eqqtO3XvuubfanN5+wBsDGP555+C8h+UBK7/5XXbZjOERfpUd8Rjkd/imn8bF43qJH56TzXr+4i5XuPAV8mDPdgelR9cBt/n8q0UfVzJg5onH8NTv/g62P/c06gtbkHUmeUPBhrSnKL3jf4ssz7Q7jr+tzarexL6Z0V6MduiXvOWNwiEN3wiA7Ix2QDvnwbFFMEsZg+7SS+cEZKcdTsCa2IZucqzCVc+V3le/iGROIEpniY8jkA4rWY6Ne3fjyG9+HZtf+nXU9+2Bne3A12ro8dZGliE1ak2GIWA68VafMfLIB7rlNVfTL6PWp98RrDA30TLhdC9MmaZaLtAPGQTiodGR3N2eTyCItToThx6spuQMLRzYg/2v/gFaLzwDbN4ItGsYWD7P5pwFfnLeTFmE59IS04zLpFpr/89AlC370/FNfyYzmnYdWPye0QKkg7oTVOm40oA3SH96PCIbXCwao9dxB6vW3elvbd+HNpQ++Lvg/wGbWC77cIMuWuUANV5kMrouLTXjudzG/on7li48IIsTaO1dwzLD/w/Ktc3PN+/XiVTrUfNa3ykTLVIGr5BFVx61NjfSSZ2E6NXJAn0E09tAD7kMrxS3lBatgrjKa9d4/PLybTQ2zWBs6xZM79mJHY8/ivGHtsLs2QUszAOTE4JcmFFfhk9Sglp96gOyCrdRM/1VAnl+fp8fguJQcY66SrAkA7EKdo8DNy4bxpr0pfpZ9TrxVWgyfPPG6QkFUk8EKytkF+vOa+jTpJd6q+jynm6jhiU/QGNmCgtPP4lNR45g9tAjaO7aCdNqhifUCVq9HgGNnqH8ebeVpp6mPlbn7wF8HUJfAEXB7MzcbgnTGmSygpxYBuKW2S04eGcK9q8gV3q1IAkO0rq4ZWYiqKMAyoBcYFTE/wJkCb/ufOp8AFymKkSyUt0X6POzz2euFgVWBz0CWqLe2Yjm/Bxmdu7A5oN7MU9rxb6dwPRUcPNWC6jV2Z1MKWYgz8jyiIU8pVAy8TFI6WlTo4GMYOwq8FRZyLFEx6PYJev3se2z83u8WF9BCZKXFjVfU5gEAiF6ZwsGhwI1fYJV4vcCaEFoeI+J/OkSMQq3DYMQAgvGc6XKHTPSgfW98mpNQR5F1PV6Fydi4IQCHO7w/G3GyN5kG9P7dmH/c89g6+OPw87Nw0xOwoyPw4w1aPoENbcKqExtfYiEiZMXOdQHYO3dYT+iF7rvOVd23Tk/vJhmcGHjLpFy2mHhlsznah0FWx1kjgOgRdIaaj5oTHGbzHIWxWo1GodBls4FPBQho5E5E03KwJCVChEcg1cpbhfBHKWCsNnKVZSTA8XIxAi4BSO2IzBlVscqv1/vruIOP/OJSTQ2TmNh3z5M7diB2Yf3INtP6bRtC8w0gW1mMUjZyuLkdx4mqlTvS0rOKcdZ/qjZ4HnJewJQI6ZpwgTp18XObm8JlMtCRBQwCw6WXo4iE+soGTkJpOpGUZMi3H1lRTFIZXmusSPFZiNAUrJYibouurCNQGKIV+xhNf1mVEhHdwsBjYMzQeaIZQ80alMWZTUV88uDPu7QS9ZqdOsNE5jaswPbvnIY2ynsM7q/6UxTMjXJrW2RAFCkOGax2EInKvlx6EqQaGXwKg1uNqEZLogdTQRmLs8+7HPKjr4b0GtzbbBgZwfcXZQ8uSsVDMkkfLQQjdxR6wTZFKyzmj7adYxeKuRFK/rovlV/I08alUPOx0kwWci0EpY6WQRSJkZ1OAcv8kokEb1DvKE3KOnJLRXud5gdfcq9X8/R3jKLeQr7iV070DlwEO09tNTtC7AbxoBmrqB6tqN7NDUbpZ1mYupp8hyDpIYTkBUT8PwHmw/6FsncinEbqDAuhPMkkIiF8ru4phjaQIIBwZZrev2+ulpey9EkwYveM7QI3oVcNWJweifWPjJ7+lhXcaT1IXRV6aYZ8o8TE9eLM7VGDX9iJeyTz4RaGJAYjCx5u1FrwBHowslTeY5u22dDazSQZR5fYlNrG6Ywd+hh7Dz8COYePYhs90OwnQlkVACmzUBVrwXLkxlUPszCxAcXC26sAFY61UdxbX48d8DPUgCPIViQ8IWTYGMVEh7LtOEBb1ghgLfYsVtrq7jdXUHPMQhx1jfQXabqTYyRyMY4kDYH3gzKne2V1ImB9Kw+w1eJUeLC6C72rqyo9IHIJR2U8TmCWrhg5YYTKJ5QquUz3SSYJtYKVEcSaKGhAYHv81uXd33SG2DA/pbNOsapSacJ5MRD2zH98H60D+5DPjsLKzq10dDJC4BmMbFwwbuR+h+pzQRPNf+0/YDfSV3b7nahyaI16tJqW0ZcPae7EERe/jFBvESCX7Yc3HgLjhpuhZrPdftoE8RpAi97h/dMMSDUORib+kMQcgKfl2WMmaH4YGJQVwYSq05Zlo9k4aMF2ODqKnNE2pSFWorNwpA8vSEX/iyd3idcKg+Xq/Q+5RcZi8Ma+9BjinmHbS/xd2t+AVsPH8KuZ4+gvZeBavtW2PYYgxQBHWuFgCRwCpX4CkjjbUWZf3/4KT9/axnz1BY53VVyWHHpvlghNVaP36/T9RcJ4CLFcX+2gye+9lW88MrLaDAiLl5ZxKXz53Hu3RO4+cF5ZDduo7XcwxSZYpJgthkQahx8g+PawIloFAMV93meqXaVKOmdq1xag1oZchMTgYxWJlFTq1BD3hTQvVadQuKQ4lZQEOJdZbQauS6L+bgTwOlpA963JpUnXthlX2yng2kCufmxR9AhBeQP70K+bQ5mYoyUZtWwNFnxYU8KQNt/449e9bfffAs7+gbjZewAB36ncLRCgxsc+OWih25nEgvPfAVP//Yr2HHkSdRnOlAlS4twvS7KpWUsXVjE9dNnsfjuaVw5fhrdK9dgVru0Qo8GrbHDyLqxZjFB19EcvRSZEaSG0EoWhb4RIEg3Yl0aZCTnZlBhV0KJz2TKvQqyUoYJ4DkT1SE0i0rBKvz2IaDEqpQ+yWdxgqgmaK3LPHedfbzdIOfuWMDck49ix7NPYsOhA8g2b4KldaroV5FeizGVz6OsM5f+6m/9O3/+HdQ+vIyNPOk153W4SfBu0H16k+OYffIwHn/l29jz7LOob9kC36gFcssCKZfirgKEZCzkIdxZQ/nxTSxd/AiX3z+Ln588hY9/dhb9SxfR7K6hyVvH2PExWoHyKUdcZ4daYqF0UZFjmQ3WVvhC5YWWzZxVK85l4LymJP9pImRtCG5lsF6L0c8ApATIft2q5jW8LnOBkzOJA6JQJIDyc5kTfodjWRZepRWOM+/fwqjfoetPHHkGrQN7kRETlVCUWhL0VDauHD3mj/3Fd3DutTfR6hcEpcDSoIsuCXnDnl145Jsv4sDL38AY5QOaLQ4szKpE65SJiLuJOwrnqf4iGBopZF/tobx+A8uXr2Dx+HFcPXMKV8+ex/K168hX+2j2CrRp/RPkmw2cyDZVwZjUHQdikf3Qrg0xUtSRlVRAdB8H7KP0slF+mVR6CkIt9CUGNOV90okApllMkm6Ji6UdAjOQgCv0Rv7v0kCW6W1rvKbLINQ++Aj2fv1FTD/9BOoLDExTbXjhUQl8/vpN/+FrP8Rrf/k3WDzzPsaaTUxunsXjL72Ax779TYzv3QU/NQ4nViiRESE7CKW0pGcQUkCNbEFzaalLaodRHmiFuE9bv3UTn9JSPzrzAS69e5I0cALdjz5GY6WLDi+ZpoyZIq/mBFKSgBajrOiHQb8Xq+Mm5D/iAcJVdr0G9dGtI8UOP7WCEKIOXdzHCn2V4oUbk47FUKiL8Je8f4033JGezEzTQw9hy689hUl6auOhrcA4A5NfW/PLFxfx5j/8I376xo9wgGnWi7/1MuYfOwRIeZ+Iu9ioSAKZda960Q5L+yYSv4+lyXJYGPYx6SPIJDi5Vwhfr1/rwt/4BNd/dh4Xjx7DlROnyK/vA7eW0CY9bKAFTYg+pLXWeX2LVupV7/pYzmNwVOuE6kl182EwWV+FkoPiyrI7Ad26sNwRRKxadKaCgOcGhdYRtMhCyxSZVYrHyc7+SJS/xvv7M1PY/vwR7PuNb6BJdzdu0FXBdu3SIm5cvIj5uS3ozG8hgPXg/yLAfaBwq1EzRdGYKiK6Vqw5YpgFhJlWSzGhAGyciXk0/zHzCNUAnl9Zoci7haunzuDcf76Dcz9+CyuXLqNFWmgPPCbo8jMMUC1KtCYbyGIuH+wsFunk+em5I8WHSqp4lSsuSioBW+tAUWCr/Cqd0pTNQp00WK0Na0vi8iKCJOtjf24S7BUaWXv3Lmx/4Xmhs4E+UmdZyvn6w4YxaqQLsTQVGMSVFBzlp1g5T+szsQisUiQK8pRU6XVF1I+pzGJi3UoogBmK8CJu38bq+Qv48OhxXHjnKDn1LLpipbTgOaaBM2xnLK9Rk9IiJatxsSAiRRUbCr6pZJfHBTvVQKEiHRfejGZbqUIlbaQCiaSbLkV7E65QpWCDpUs2ZzLhxQZWeN91SsauVJucS0t/Vbmr8ouwyjd0EaBa3PoS22hquP5Iqp7EpYMY/ZVfGYgGV6/jw1OnceKtn2Lx7aPIzl/EbL9EJ2cg5MjGKZEavDQXa6HbqyuKCI+6tE7AxduEisJKqViipLpR+/mQotY0+IQxCogCWBkLPVa5NQAg4EstQkNZrNJLhXNZLLkCcn1Z627AfhEA79nuC2SFsA/lXXoGf/eKsOjFrXv5Kj4+eRIn/uVfcfPYcaxeuIwOwdnCoDTFfrXEKmkpMuWOx2sEWgbfIxXk5NZaXTToQN1bABxkoSyn9iZAll4/dQ1JHEeAjEJbjuUpFsXiRlxICIFONK1q0hH07q0P/pIAvBe/u7ZgDqQZzXqU1cTV41q4lrupP8H8/uq7x3DiBz/C4ltvUwRfZQblMCXWSQsZl+yEE1BXnehDgaMmBQxhjQEtN4sJR1i1DBbpFSilCA0o0Fpscm+pqWYBnLj4FiSf1mA1HthQrfL3Q+9XtX0OkC5qQIxQaAI0vMUgPMogJdH+6Emc/P4PcOXYexhcu4mMmdVCo4VZUIt2C9QYfetUG/2yi1VDCpBsquvUJSUoORtLZlp8jvmz1jpV9w850kawU7EiFJoDBRTKuWHp4v8JkLI5LQwEkZ9WLUNhQ8zEU4A7LVjQanuMHgTKXLuGc2+/g+Ov/xCX/us4xm4sYZvLsbnLdLc/oGSCFFOZR4f6d70f4nNpK8vSaB6BhNZgQyE9bUFqxbKZDYCGkmiyzFjYfaBAAp8JZoAy1QJMLL2lOlFIlGQJNtfa50BzcpFPK0w/P/jJO3jvu99H//R5zCz1sLPRprsL4D0MTF8VSavMAw9Gxhia/jAammGxI20KvQ+EakgRLgZEG9fZNQA9aCD9yJf7Ma84SRHXhvTVGWOG4wzZTFXL9KbQwrEsZXhmPZYi/tbx93H8u9/DhdffROPaJ5hn1O7kUpgWK+6hWWAYgeNHAC89P1FyenPEV3XToJO85viagkZq8LH0+8CATHoSaQD3AdMP/wInVi8aAPFNn+rFBDJUqcUNqymkuLqYbLl4FWeZ8p763uu4cfQ9bKfe2yS5O/XpBoQcPo/vN+lyiLVxUS+CaNJUhYJzdOrYFyl8c+KkBpolChru/3sgP0s2jQKZZEMSwsNUd7QHJuXLI8eHM1BNh7hXeMnAIa1Kwof3k/DJp1j+4Dz+46//Dufe+Ddso8TcxIY7AgSzqDGCG7iRE8EUcMCA5uNKavBiEy3RDjul2aQLOrTIA4+qPNKcX156eIDb/XC730UxKRp5owNDgIdmmo77NKJQKtNMbGYa460WvvYnr6JRa+L8P7+OJq9rU7DnTH0LwV4q6jHNDVkYhi4ydOeRPvkU/CKgIUML5bgvBWT1nuS9FvdlteZnXm3u+joEzSO+pJEOAGmdOXJa4YKIL2iqzfYYart34vk//kNa6Aqu/PtP0KSu7NACM6aqDP6qWfX1RFO1GUA0o+n6cBLTC5CaBalFD6nzvi/I3LONum56/e8XYQRz1+e6E+Y+J+4l0WrB3kRjTK/5iFEyuEjOXfqQxkk1OyOYT/3+72HDgd241ltlOlegkEqStXEtxod1qpQep0JK5D7ElyCED8uYb4c1e6eV/7Rm/7lAfhaIXxbQdVj9D7clfhzuNgEV7/aBw4KwHj0fq0q0sIatheUIkSh1i8bh/TjwrZfQa9Wx1O+jb8K6jY8PDJZflRxSiDNxRyy5hfJbWpJNL72E4PiFLPLzti9ipQlEmzKW+1wTigLpldb0wkH1qQUFATAhN9pwjPI14UjnqkjcqiGfbGDhq8/qenbJlLHnyjAJ2qEYl0foKVTVR1/djsDGN/PUOrMQdPr87Fv/5YAcfSF1FDwnHXfu8+/39/fgqqvr/9aBGYVyKiYYXXRIb/2GCdRXD02s8sgSRb0W5MpEC7Vtc9j7/HOoTYwHdw6LPRHA6oXZJHe0FV/1BGkNKHqJADnQ3ev+3w88cB1NoRAlAAAAAElFTkSuQmCC",
"cityId": 12,
"orderSn": "1199a04a-d203-4d3d-b65b-0c07ce5fd9f7"
}
}
```
- type=phone_code
```json
{
"msg":"对不起,查询短信随机码暂时不能发送,请一分钟以后再试",
"code":115,
"data":{
"cityId":2,
"orderSn": "1199a04a-d203-4d3d-b65b-0c07ce5fd9f7"
}
}
```
**返回参数说明**
|参数名|类型|说明|
|:----- |:-----|----- |
|code |int |错误码 |
|orderSn|int|个税查询任务订单号
|cityId|int|城市ID
|img|String|图片base64编码格式,不包含头信息|
|msg|string|错误信息
**备注**
状态码对应的信息说明
|code|原因|处理方式|
|:----- |:-----|----- |
|0 | 成功 | 可以继续接下来的步骤 |
|-1 | 系统异常 |系统异常导致的错误 |
|101 |参数错误或缺失 |需检查参数是否缺失或错误 |
|107 |未找到该订单号 |需检查订单号是否正确 |
|201 |城市维护中或者不支持 | |
|202 |个税任务不存在 |确认订单号是否正确 |
|203 |验证码任务类型不存在 |确定验证码类型是否正确 |
|207 |获取图形验证码任务失败 | 可重新获取 |
|208 |获取短信验证码任务失败 | 可重发|
## **2.6** 提交任务查询参数
**简要描述:**
- 查询个税任务
**请求URL:**
- ` IncomeTaxAPI/query `
**请求方式:**
- POST
- Content-Type = application/json
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|orderSn |是 |string |个税查询任务订单号 |
|params|是|json string|当前查询任务需要的参数 如:{"phone":1111,"code":1111}
**请求示例**
```json
{
"orderSn":"7d7cf6f8-8104-4660-bd8c-ec3a93026fg6",
"params":{
"ID":"41302619841025456X",
"password":"123"
}
}
```
**返回示例**
```json
{
"msg":null,
"code":0,
"data":{
"cityId":12,
"orderSn":"7d7cf6f8-8104-4660-bd8c-ec3a93026fg6"
}
}
```
**返回参数说明**
|参数名|类型|说明|
|:----- |:-----|----- |
|code |int |错误码 |
|orderSn|string|个税查询订单号
|cityId|int|城市ID
|msg|string|错误信息
**备注**
|code|原因|处理方式|
|:----- |:-----|----- |
|0 | 成功 | 可以继续接下来的步骤 |
|-1 | 系统异常 |系统异常导致的错误 |
|101 |参数错误或缺失 |需检查参数是否缺失或错误 |
|107 |未找到该订单号 |需检查订单号是否正确 |
|201 |城市维护或不支持 |当前城市不支持查询 |
|202 |个税任务不存在 |需检查订单号是否正确 |
|204 |任务失败 | |
|300 |任务结束 |当抓取任务已经结束且成功,如若继续提交参数会返回该信息 |
|301 |个税任务正在执行中 |已经提交了任务 |
## **2.7** 查询任务结果
**简要描述:**
- 查询个税任务
!> 禁止轮询该接口,检测到轮询会封对应的appKey
**请求URL:**
- ` IncomeTaxAPI/getData `
**请求方式:**
- POST
- Content-Type = application/json
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|orderSn |是 |String |个税查询任务订单号 |
**请求示例**
```json
{
"sign":"89D89A1D07E875C649D6A2D01F8E650A",
"params":{
"appKey": "88A03809137291F333BF2679AB85850E",
"timestamp":"1494316515535",
"token":"f63bbb7a1c1b497387597efda28a1e3c",
"orderSn":"4243d640-146a-47d7-97b9-a03681fc9bf8"
}
}
```
**返回示例**
- 当前步骤执行成功,还需要执行下一步,loginParam为登录参数,
```JSON
{
"msg":null,
"code":1,
"data":{
"data":null,
"loginParam":[{"note":"用户名指您在注册时自行设置的2-12位英文字母或数字(区分大小写)","name":"account","type":"string"},{"note":"","name":"password","type":"string"}],
"cityId":12,
"orderSn":"7d7cf6f8-8104-4660-bd8c-ec3a93026fg6"
}
}
```
- 登录成功,
```JSON
{
"msg":null,
"code":110,
"data":{
"data":null,
"cityId":12,
"orderSn":"7d7cf6f8-8104-4660-bd8c-ec3a93026fg6"
}
}
```
- 执行成功
```json
{
"code":0,
"msg":"",
"data":{
"incometaxData": {
"data":{
//具体数据结构见附录4.3}
},
"cityName":"杭州",
"cityId":"12",
"orderId":"158ddhkj-jlhlkmsd-4456465sads",
"create_date": "2017-10-12 12:26:10"
}
}
}
```
- 执行失败
```json
{
"msg":"参数不正确",
"code":204,
"data":{
"data":null,
"loginParam":null,
"cityId":12,
"orderSn":"7d7cf6f8-8104-4660-bd8c-ec3a93026fg6"
}
}
```
**返回参数说明**
|参数名|类型|说明|
|:----- |:-----|----- |
|code |int |错误码 |
|orderSn|string|个税查询任务订单号
|cityId|int|城市ID
|msg|string|错误信息
|data|string|数据
|loginParam|json Object|登录参数
**备注**
|code|原因|处理方式|
|:----- |:-----|-----|
|0 | 成功 | 成功并返回数据 |
|1 | 需要下一步 | 当前步骤执行成功,还需要执行下一步,loginParam为登录参数,需要根据登录参数渲染下一步登录界面 |
|110 | 登录成功 | 任务已成功提交,等待下一步回调 |
|105| 初始状态 | 任务状态未改变 |
|101 |参数错误或缺失 |需检查参数是否缺失或错误 |
|107 |未找到该订单号 |需检查订单号是否正确 |
|204 | 任务出错 |错误信息见msg |
|-1 | 其他错误 | |
|3000 | 验签出错 |具体错误信息解释见4.2 |
## **2.8** 拉取个税证明
**简要描述:**
- 拉取个税证明
!> 禁止轮询该接口,检测到轮询会封对应的appKey
**请求URL:**
- ` IncomeTaxAPI/getIncomeProve `
**请求方式:**
- POST
- Content-Type = application/json
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|orderSn |是 |String |个税查询任务订单号 |
**请求示例**
```json
{
"sign":"89D89A1D07E875C649D6A2D01F8E650A",
"params":{
"appKey": "88A03809137291F333BF2679AB85850E",
"timestamp":"1494316515535",
"token":"f63bbb7a1c1b497387597efda28a1e3c",
"orderSn":"4243d640-146a-47d7-97b9-a03681fc9bf8"
}
"file":"2018.jpg" //为空或无此参数则拉取全部年份数据
}
```
**返回示例**
- 执行成功
```json
{
"code":0,
"msg":"获取成功",
"data":[
{
"file":"2017.jpg", //个税年份文件名
"data":"" //个税证明图片base64编码格式,不包含头信息
},
{
"file":"2018.jpg", //个税年份文件名
"data":"" //个税证明图片base64编码格式,不包含头信息
}
]
}
```
- 执行失败
```json
{
"msg":"未查询到此订单号",
"code":-1,
"orderSn":"7d7cf6f8-8104-4660-bd8c-ec3a93026fg6"
}
```
# **3** 回调通知
## **8.1** 通知参数
>**请求方式:**
>- Method: POST
- Content-Type: application/json
- Charset: UTF-8
**参数:**
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|orderSn |是 |String |个税查询任务订单号 |
## **8.2** 通知示例
比如,回调地址为```https://your.url.com/your/server```,那么我方异步回调通
知的请求类似:
```json
{
"orderSn":"7d7cf6f8-8104-4660-bd8c-ec3a93026fg6"
}
```
当成功收到回调通知后,页面应返回HttpStatus=200
之后,可通过``` 查询任务结果``` 接口查询对应的信息和数据
# **4** 附录
## **4.1** 签名算法
签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
- 参数名ASCII码从小到大排序(字典序);
- 如果参数的值为空不参与签名;
- 参数名区分大小写;
第二步,在stringA最后拼接上appSecret得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
举例:
假设传送的参数如下:
``` json
appKey : 88A03809137291F333BF2689AB85850E,
orderSn : 426ea0df-7f1b-4491-8989-5c130291e892,
timestamp : 1494649888152
token : 0eaeb00afcc4448da724d9179a50abe7
```
第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:
``` javascript
stringA="appKey=092217B6B52ED02D46EFFFA7CFA20940&orderSn=3e993890-ff08-4af5-bb9b-04fda6dd2b78&timestamp=1494669826683&token=8731de2cd2604f4a856f210703541326";
```
第二步:拼接API密钥:
``` javascript
stringSignTemp=stringA+"&appSecret=192006250b4c09247ec02edce69f6a2d"
sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7"
```
## **4.2** 验签接口错误解释
|code|错误信息|解释及处理方式|
|:----- |:-----|----- |
|3000 | 系统异常 |验签服务出错 |
|3000 |参数错误 |需检查参数是否缺失或错误 |
|3000 | 时间戳超时 |时间戳的有效期为1分钟,超过视为超时(北京时间) |
|3000 |无效的token |检查token是否正确 |
|3000 |token已失效 |token过了两小时有效期,或者有了新的token覆盖了旧的token,此处要做好token管理防止并发 |
|3000 |签名错误 |生成的签名sign与我方根据传来参数计算出的sign不一致,需要检查算法是否正确 |
|3000 |appKey错误 |检查appKey是否正确 |
## **4.3** 个税数据结构
### 总体结构
!> - JSON键值对除了对象、数组以外,其余键值对的值的数据类型均为String,任何字段若未抓取到数据,默认空字符串
```json
{
"brief": {
"ID": "",
"name": "",
"amount": 10, //最新月缴税额
"total": 1000, //缴税总额
"record_date": "2018-01-01"//最新缴税时间
},
"detail": [{
"record_date": "2018-01-01", //缴税日期或申报日期
"record_month": "201801", //所属年月
"amount": 10, //缴税金额
"income": 1000, //收入金额
"tax_type": "基本工资", //缴税项目或收入类型
"company": "杭州煎饼网络技术有限公司",
"agency": "XXX税务局" //征收机关
},
{
"record_date": "2018-01-01", //缴税日期或申报日期
"record_month": "201801", //所属年月
"amount": 10, //已缴金额
"income": 1000, //收入金额
"tax_type": "基本工资", //缴税项目或收入类型
"company": "杭州煎饼网络技术有限公司",
"agency": "XXX税务局" //征收机关
}],
"proofs": [ //个税证明文件
"2018.jpg",
"2017.jpg"
]
}
```
![logo](media/logo_43.png)
# 个税API服务接口文档
>查询本文档你将能了解到:
- 创建任务API
- 如何拉取数据
- 常见问题及解决方案
[开始查看](#文档更新说明)
<footer>
<span>杭州煎饼网络技术有限公司 版权所有 &copy;2017 </span>
<span>由51公积金管家数据部门提供支持 </span>
</footer>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>个税API接口文档</title>
<meta name="description" content="Description">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
<style>
.markdown-section{
margin-left: 20px;
}
</style>
</head>
<body>
<div id="app"></div>
</body>
<script>
window.$docsify = {
name: '个税API接口文档',
themeColor: '#439df8',
coverpage: true,
maxLevel: 2,
externalLinkTarget: '_self',
auto2top: true,
plugins: [
function (hook) {
var footer = [
'<hr/>',
'<footer>',
'<span>杭州煎饼网络技术有限公司 版权所有 &copy;2017 </span>',
'<span> 由51公积金管家数据部门提供支持 </span>',
'</footer>'
].join('')
hook.afterEach(function (html) {
return html + footer
})
}
]
}
</script>
<script src="doc/vendor/docsify.js"></script>
<script src="//unpkg.com/prismjs/components/prism-bash.js"></script>
<script src="//unpkg.com/prismjs/components/prism-json.js"></script>
</html>
!function(){"use strict";function e(e){var t=Object.create(null);return function(n){var r=t[n];return r||(t[n]=e(n))}}function t(e){return"string"==typeof e||"number"==typeof e}function n(){}function r(e){return"function"==typeof e}function i(e){var t=["init","mounted","beforeEach","afterEach","doneEach","ready"];e._hooks={},e._lifecycle={},t.forEach(function(t){var n=e._hooks[t]=[];e._lifecycle[t]=function(e){return n.push(e)}})}function a(e,t,r,i){void 0===i&&(i=n);var a=r,o=e._hooks[t],s=function(e){var t=o[e];if(e>=o.length)i(a);else if("function"==typeof t)if(2===t.length)t(r,function(t){a=t,s(e+1)});else{var n=t(r);a=void 0!==n?n:a,s(e+1)}else s(e+1)};s(0)}function o(e,t){if(void 0===t&&(t=!1),"string"==typeof e){if("undefined"!=typeof window.Vue)return s(e);e=t?s(e):be[e]||(be[e]=s(e))}return e}function s(e,t){return t?e.querySelector(t):ye.querySelector(e)}function l(e,t){return[].slice.call(t?e.querySelectorAll(t):ye.querySelectorAll(e))}function c(e,t){return e=ye.createElement(e),t&&(e.innerHTML=t),e}function u(e,t){return e.appendChild(t)}function p(e,t){return e.insertBefore(t,e.children[0])}function h(e,t,n){r(t)?window.addEventListener(e,t):e.addEventListener(t,n)}function d(e,t,n){r(t)?window.removeEventListener(e,t):e.removeEventListener(t,n)}function g(e,t,n){e&&e.classList[n?t:"toggle"](n||t)}function f(e){var t={};return(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach(function(e){var n=e.replace(/\+/g," ").split("=");t[n[0]]=Ce(n[1])}),t):t}function m(e){var t=[];for(var n in e)t.push(($e(n)+"="+$e(e[n])).toLowerCase());return t.length?"?"+t.join("&"):""}function v(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];return je(e.join("/"))}function b(e){var t=window.location.href.indexOf("#");window.location.replace(window.location.href.slice(0,t>=0?t:0)+"#"+e)}function y(){var e=k();return e=Oe(e),"/"===e.charAt(0)?b(e):void b("/"+e)}function k(){var e=window.location.href,t=e.indexOf("#");return t===-1?"":e.slice(t+1)}function w(e){void 0===e&&(e=window.location.href);var t="",n=e.indexOf("?");n>=0&&(t=e.slice(n+1),e=e.slice(0,n));var r=e.indexOf("#");return r&&(e=e.slice(r+1)),{path:e,query:f(t)}}function x(e,t,n){var r=n&&"#"===e[0],i=w(Oe(e));return i.query=pe({},i.query,t),e=i.path+m(i.query),e=e.replace(/\.md(\?)|\.md$/,"$1"),r&&(e=n+e),je("#/"+e)}function _(e){var t=function(e){return ke.classList.toggle("close")};e=o(e),h(e,"click",function(e){e.stopPropagation(),t()});var n=o(".sidebar");Le&&h(ke,"click",function(e){return ke.classList.contains("close")&&t()}),h(n,"click",function(e){return setTimeout(0)})}function S(){var e=o("section.cover");if(e){var t=e.getBoundingClientRect().height;window.pageYOffset>=t||e.classList.contains("hidden")?g(ke,"add","sticky"):g(ke,"remove","sticky")}}function L(e,t,n){e=o(e);var r,i=l(e,"a"),a="#"+k();return i.sort(function(e,t){return t.href.length-e.href.length}).forEach(function(e){var n=e.getAttribute("href"),i=t?e.parentNode:e;0!==a.indexOf(n)||r?g(i,"remove","active"):(r=e,g(i,"add","active"))}),n&&(ye.title=r?r.innerText+" - "+Pe:Pe),r}function C(){for(var e,t=o(".sidebar"),n=l(".anchor"),r=s(t,".sidebar-nav"),i=s(t,"li.active"),a=ke.scrollTop,c=0,u=n.length;c<u;c+=1){var p=n[c];if(p.offsetTop>a){e||(e=p);break}e=p}if(e){var h=qe[e.getAttribute("data-id")];if(h&&h!==i&&(i&&i.classList.remove("active"),h.classList.add("active"),i=h,!Ne&&ke.classList.contains("sticky"))){var d=t.clientHeight,g=0,f=i.offsetTop+i.clientHeight+40,m=i.offsetTop>=r.scrollTop&&f<=r.scrollTop+d,v=f-g<d,b=m?r.scrollTop:v?g:f-d;t.scrollTop=b}}}function $(){if(!Le){for(var e=o(".sidebar"),t=l(e,"li"),n=0,r=t.length;n<r;n+=1){var i=t[n],a=i.querySelector("a");if(a){var s=a.getAttribute("href");"/"!==s&&(s=w(s).query.id),qe[decodeURIComponent(s)]=i}}d("scroll",C),h("scroll",C),h(e,"mouseover",function(){Ne=!0}),h(e,"mouseleave",function(){Ne=!1})}}function E(e){var t=s("#"+e);t&&t.scrollIntoView()}function T(e){void 0===e&&(e=0),Fe.scrollTop=e===!0?0:Number(e)}function A(){var e=c("div");e.classList.add("progress"),u(ke,e),me=e}function j(e,t){void 0===t&&(t=!1);var r=new XMLHttpRequest,i=function(){r.addEventListener.apply(r,arguments)};return Ie[e]?{then:function(t){return t(Ie[e])},abort:n}:(r.open("GET",e),r.send(),{then:function(r,a){if(void 0===a&&(a=n),t){var o=setInterval(function(e){return He({step:Math.floor(5*Math.random()+1)})},500);i("progress",He),i("loadend",function(e){He(e),clearInterval(o)})}i("error",a),i("load",function(t){var n=t.target;n.status>=400?a(n):(Ie[e]=n.response,r(n.response))})},abort:function(e){return 4!==r.readyState&&r.abort()}})}function O(e,t){e.innerHTML=e.innerHTML.replace(/var\(\s*--theme-color.*?\)/g,t)}function M(e){return e?(/\/\//.test(e)||(e="https://github.com/"+e),e=e.replace(/^git\+/,""),'<a href="'+e+'" class="github-corner" aria-label="View source on Github"><svg viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>'):""}function P(e){var t='<button class="sidebar-toggle"><div class="sidebar-toggle-button"><span></span><span></span><span></span></div></button><aside class="sidebar">'+(e.name?'<h1><a class="app-name-link" data-nosearch>'+e.name+"</a></h1>":"")+'<div class="sidebar-nav"></div></aside>';return(Le?t+"<main>":"<main>"+t)+'<section class="content"><article class="markdown-section" id="main"></article></section></main>'}function q(){var e=", 100%, 85%",t="linear-gradient(to left bottom, hsl("+(Math.floor(255*Math.random())+e)+") 0%,hsl("+(Math.floor(255*Math.random())+e)+") 100%)";return'<section class="cover" style="background: '+t+'"><div class="cover-main"></div><div class="mask"></div></section>'}function N(e,t){return void 0===t&&(t=""),e&&e.length?(e.forEach(function(e){t+='<li><a class="section-link" href="'+e.slug+'">'+e.title+"</a></li>",e.children&&(t+='<li><ul class="children">'+N(e.children)+"</li></ul>")}),t):""}function F(e,t){return'<p class="'+e+'">'+t.slice(5).trim()+"</p>"}function H(e){return"<style>:root{--theme-color: "+e+";}</style>"}function I(e,t){return t={exports:{}},e(t,t.exports),t.exports}function z(e,t){var n=[],r={};return e.forEach(function(e){var i=e.level||1,a=i-1;i>t||(r[a]?r[a].children=(r[a].children||[]).concat(e):n.push(e),r[i]=e)}),n}function R(e){if("string"!=typeof e)return"";var t=e.toLowerCase().trim().replace(/<[^>\d]+>/g,"").replace(Ue,"").replace(/\s/g,"-").replace(/-+/g,"-").replace(/^(\d)/,"_$1"),n=De[t];return n=De.hasOwnProperty(t)?n+1:0,De[t]=n,n&&(t=t+"-"+n),t}function W(e,t){return'<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/'+t+'.png" alt="'+t+'" />'}function B(e){return $docsify.noEmoji?e:e.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g,function(e){return e.replace(/:/g,"__colon__")}).replace(/:(\w+?):/gi,window.emojify||W).replace(/__colon__/g,":")}function D(e,t){var n="";if(e)n=Qe(e),n=n.match(/<ul[^>]*>([\s\S]+)<\/ul>/g)[0];else{var r=Ye[Xe]||z(Je,t);n=N(r,"<ul>"),Ye[Xe]=r}return n}function U(e,t){if(e){Je[0]&&Je[0].ignoreAllSubs&&(Je=[]),Je[0]&&1===Je[0].level&&Je.shift(),Je.forEach(function(e,t){e.ignoreSubHeading&&Je.splice(t,1)});var n=Ye[Xe]||z(Je,t);e.parentNode.innerHTML+=N(n,'<ul class="app-sub-sidebar">'),Ye[Xe]=n}Je=[]}function G(e){var t=Je.slice(),n=Qe(e);return Je=t.slice(),n}function V(){var e=l(".markdown-section>script").filter(function(e){return!/template/.test(e.type)})[0];if(!e)return!1;var t=e.innerText.trim();return!!t&&void setTimeout(function(e){window.__EXECUTE_RESULT__=new Function(t)()},0)}function X(e){e||(e="not found"),this._renderTo(".markdown-section",e),!this.config.loadSidebar&&this._renderSidebar(),this.config.executeScript===!1||"undefined"==typeof window.Vue||V()?this.config.executeScript&&V():setTimeout(function(e){var t=window.__EXECUTE_RESULT__;t&&t.$destroy&&t.$destroy(),window.__EXECUTE_RESULT__=(new window.Vue).$mount("#main")},0),this.config.auto2top&&T(this.config.auto2top)}function Z(e){var n=o(".app-name-link"),r=e.config.nameLink,i=e.route.path;if(n)if(t(e.config.nameLink))n.setAttribute("href",r);else if("object"==typeof r){var a=Object.keys(r).find(function(e){return i.indexOf(e)>-1});n.setAttribute("href",r[a])}}function Y(e){e._renderTo=function(e,t,n){var r=o(e);r&&(r[n?"outerHTML":"innerHTML"]=t)},e._renderSidebar=function(e){var t=this.config,n=t.maxLevel,r=t.subMaxLevel,i=t.autoHeader,a=t.loadSidebar;this._renderTo(".sidebar-nav",D(e,n));var s=L(".sidebar-nav",!0,!0);if(U(a?s:"",r),this.activeLink=s,$(),i&&s){var l=o("#main"),u=l.children[0];if(u&&"H1"!==u.tagName){var h=c("h1");h.innerText=s.innerText,p(l,h)}}},e._renderNav=function(e){e&&this._renderTo("nav",Qe(e)),L("nav")},e._renderMain=function(e){var t=this;a(this,"beforeEach",e,function(e){var n=t.isHTML?e:Qe(e);a(t,"afterEach",n,function(e){return X.call(t,e)})})},e._renderCover=function(e){var t=o(".cover");if(!e)return void g(t,"remove","show");g(t,"add","show");var n=this.coverIsHTML?e:G(e),r=n.trim().match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$');if(r){if("color"===r[2])t.style.background=r[1]+(r[3]||"");else{var i=r[1];g(t,"add","has-mask"),Te(r[1])||(i=v(Ee(this.config.basePath),r[1])),t.style.backgroundImage="url("+i+")",t.style.backgroundSize="cover",t.style.backgroundPosition="center center"}n=n.replace(r[0],"")}this._renderTo(".cover-main",n),S()},e._updateRender=function(){Qe.update(),Z(this)}}function J(e){var t=e.config;Qe.init(t.markdown,t.basePath);var n=t.el||"#app",r=s("nav")||c("nav"),i=s(n),a="",o=ke;i||(i=c(n),u(ke,i)),t.repo&&(a+=M(t.repo)),t.coverpage&&(a+=q()),a+=P(t),e._renderTo(i,a,!0),t.mergeNavbar&&Le?o=s(".sidebar"):(r.classList.add("app-nav"),t.repo||r.classList.add("no-badge")),p(o,r),t.themeColor&&(ye.head.innerHTML+=H(t.themeColor),ze(t.themeColor)),g(ke,"ready")}function Q(e,t){return t[e]?Q(t[e],t):e}function K(e){return/\.(md|html)$/g.test(e)?e:/\/$/g.test(e)?e+"README.md":e+".md"}function ee(e){e.route={},e.$getFile=function(e){var t=this,n=t.config,r=Ee(n.basePath);return e=n.alias?Q(e,n.alias):e,e=K(e),e="/README.md"===e?n.homepage||e:e,e=Te(e)?e:v(r,e)}}function te(e){y(),et=e.route=w(),e._updateRender(),h("hashchange",function(t){return y(),e.route=w(),e._updateRender(),et.path===e.route.path?void e.$resetEvents():(e.$fetch(),void(et=e.route))})}function ne(e){e.$resetEvents=function(){E(this.route.query.id),L("nav")}}function re(e){_("button.sidebar-toggle"),e.config.coverpage?!Le&&h("scroll",S):ke.classList.add("sticky")}function ie(e,t,n,r,i){e=i?e:e.replace(/\/$/,""),e=Ae(e),e&&j(r.$getFile(e+t)).then(n,function(i){return ie(e,t,n,r)})}function ae(e){var t;e._fetch=function(e){var r=this;void 0===e&&(e=n);var i=this.route,a=i.path,o=this.config,s=o.loadNavbar,l=o.loadSidebar;t&&t.abort&&t.abort(),t=j(this.$getFile(a),!0),this.isHTML=/\.html$/g.test(a),t.then(function(t){if(r._renderMain(t),!l)return e();var n=function(t){r._renderSidebar(t),e()};ie(a,l,n,r,!0)},function(e){return r._renderMain(null)}),s&&ie(a,s,function(e){return r._renderNav(e)},this,!0)},e._fetchCover=function(){var e=this,t=this.config,n=t.coverpage,r=Ae(this.route.path),i=this.$getFile(r+n);return"/"===this.route.path&&n?(this.coverIsHTML=/\.html$/g.test(i),void j(i).then(function(t){return e._renderCover(t)})):void this._renderCover()},e.$fetch=function(e){var t=this;void 0===e&&(e=n),this._fetchCover(),this._fetch(function(n){t.$resetEvents(),a(t,"doneEach"),e()})}}function oe(e){e.$fetch(function(t){return a(e,"ready")})}function se(e){e._init=function(){var e=this;e.config=he||{},i(e),le(e),a(e,"init"),J(e),re(e),te(e),oe(e),a(e,"mounted")}}function le(e){[].concat(e.config.plugins).forEach(function(t){return r(t)&&t(e._lifecycle,e)})}function ce(){this._init()}var ue=e(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),pe=Object.assign||function(e){for(var t=arguments,n=Object.prototype.hasOwnProperty,r=1;r<arguments.length;r++){var i=Object(t[r]);for(var a in i)n.call(i,a)&&(e[a]=i[a])}return e},he=pe({el:"#app",repo:"",maxLevel:6,subMaxLevel:0,loadSidebar:null,loadNavbar:null,homepage:"README.md",coverpage:"",basePath:"",auto2top:!1,name:"",themeColor:"",nameLink:window.location.pathname,autoHeader:!1,executeScript:null,noEmoji:!1,ga:"",mergeNavbar:!1},window.$docsify),de=document.currentScript||[].slice.call(document.getElementsByTagName("script")).filter(function(e){return/docsify\./.test(e.src)})[0];if(de){for(var ge in he){var fe=de.getAttribute("data-"+ue(ge));t(fe)&&(he[ge]=""===fe||fe)}he.loadSidebar===!0&&(he.loadSidebar="_sidebar.md"),he.loadNavbar===!0&&(he.loadNavbar="_navbar.md"),he.coverpage===!0&&(he.coverpage="_coverpage.md"),he.repo===!0&&(he.repo=""),he.name===!0&&(he.name="")}window.$docsify=he;var me,ve,be={},ye=document,ke=ye.body,we=ye.head,xe=Object.freeze({getNode:o,$:ye,body:ke,head:we,find:s,findAll:l,create:c,appendTo:u,before:p,on:h,off:d,toggleClass:g}),_e=window.navigator.userAgent.toLowerCase(),Se=_e&&/msie|trident/.test(_e),Le=document.body.clientWidth<=600,Ce=decodeURIComponent,$e=encodeURIComponent,Ee=e(function(e){return/^(\/|https?:)/g.test(e)?e:je(window.location.pathname+"/"+e)}),Te=e(function(e){return/(:|(\/{2}))/.test(e)}),Ae=e(function(e){return/\/$/g.test(e)?e:(e=e.match(/(\S*\/)[^\/]+$/))?e[1]:""}),je=e(function(e){return e.replace(/^\/+/,"/").replace(/([^:])\/{2,}/g,"$1/")}),Oe=e(function(e){return e.replace("#","?id=")}),Me=Object.freeze({normalize:y,getHash:k,parse:w,toURL:x,parseQuery:f,stringifyQuery:m,getBasePath:Ee,getPath:v,isAbsolutePath:Te,getParentPath:Ae,cleanPath:je}),Pe=ye.title,qe={},Ne=!1,Fe=ye.scrollingElement||ye.documentElement,He=function(e){var t,n=e.loaded,r=e.total,i=e.step;!me&&A(),i?(t=parseInt(me.style.width||0,10)+i,t=t>80?80:t):t=Math.floor(n/r*100),me.style.opacity=1,me.style.width=t>=95?"100%":t+"%",t>=95&&(clearTimeout(ve),ve=setTimeout(function(e){me.style.opacity=0,me.style.width="0%"},200))},Ie={},ze=function(e){if(!(window.CSS&&window.CSS.supports&&window.CSS.supports("(--v:red)"))){var t=l("style:not(.inserted),link");[].forEach.call(t,function(t){if("STYLE"===t.nodeName)O(t,e);else if("LINK"===t.nodeName){var n=t.getAttribute("href");if(!/\.css$/.test(n))return;j(n).then(function(t){var n=c("style",t);we.appendChild(n),O(n,e)})}})}},Re="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},We=I(function(e,t){(function(){function t(e){this.tokens=[],this.tokens.links={},this.options=e||u.defaults,this.rules=p.normal,this.options.gfm&&(this.options.tables?this.rules=p.tables:this.rules=p.gfm)}function n(e,t){if(this.options=t||u.defaults,this.links=e,this.rules=h.normal,this.renderer=this.options.renderer||new r,this.renderer.options=this.options,!this.links)throw new Error("Tokens array requires a `links` property.");this.options.gfm?this.options.breaks?this.rules=h.breaks:this.rules=h.gfm:this.options.pedantic&&(this.rules=h.pedantic)}function r(e){this.options=e||{}}function i(e){this.tokens=[],this.token=null,this.options=e||u.defaults,this.options.renderer=this.options.renderer||new r,this.renderer=this.options.renderer,this.renderer.options=this.options}function a(e,t){return e.replace(t?/&/g:/&(?!#?\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function o(e){return e.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g,function(e,t){return t=t.toLowerCase(),"colon"===t?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}function s(e,t){return e=e.source,t=t||"",function n(r,i){return r?(i=i.source||i,i=i.replace(/(^|[^\[])\^/g,"$1"),e=e.replace(r,i),n):new RegExp(e,t)}}function l(){}function c(e){for(var t,n,r=arguments,i=1;i<arguments.length;i++){t=r[i];for(n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])}return e}function u(e,n,r){if(r||"function"==typeof n){r||(r=n,n=null),n=c({},u.defaults,n||{});var o,s,l=n.highlight,p=0;try{o=t.lex(e,n)}catch(e){return r(e)}s=o.length;var h=function(e){if(e)return n.highlight=l,r(e);var t;try{t=i.parse(o,n)}catch(t){e=t}return n.highlight=l,e?r(e):r(null,t)};if(!l||l.length<3)return h();if(delete n.highlight,!s)return h();for(;p<o.length;p++)!function(e){return"code"!==e.type?--s||h():l(e.text,e.lang,function(t,n){return t?h(t):null==n||n===e.text?--s||h():(e.text=n,e.escaped=!0,void(--s||h()))})}(o[p])}else try{return n&&(n=c({},u.defaults,n)),i.parse(t.lex(e,n),n)}catch(e){if(e.message+="\nPlease report this to https://github.com/chjj/marked.",(n||u.defaults).silent)return"<p>An error occured:</p><pre>"+a(e.message+"",!0)+"</pre>";throw e}}var p={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:l,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:l,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:l,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};p.bullet=/(?:[*+-]|\d+\.)/,p.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,p.item=s(p.item,"gm")(/bull/g,p.bullet)(),p.list=s(p.list)(/bull/g,p.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+p.def.source+")")(),p.blockquote=s(p.blockquote)("def",p.def)(),p._tag="(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b",p.html=s(p.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,p._tag)(),p.paragraph=s(p.paragraph)("hr",p.hr)("heading",p.heading)("lheading",p.lheading)("blockquote",p.blockquote)("tag","<"+p._tag)("def",p.def)(),p.normal=c({},p),p.gfm=c({},p.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),p.gfm.paragraph=s(p.paragraph)("(?!","(?!"+p.gfm.fences.source.replace("\\1","\\2")+"|"+p.list.source.replace("\\1","\\3")+"|")(),p.tables=c({},p.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/}),t.rules=p,t.lex=function(e,n){var r=new t(n);return r.lex(e)},t.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},t.prototype.token=function(e,t,n){for(var r,i,a,o,s,l,c,u,h,d=this,e=e.replace(/^ +$/gm,"");e;)if((a=d.rules.newline.exec(e))&&(e=e.substring(a[0].length),a[0].length>1&&d.tokens.push({type:"space"})),a=d.rules.code.exec(e))e=e.substring(a[0].length),a=a[0].replace(/^ {4}/gm,""),d.tokens.push({type:"code",text:d.options.pedantic?a:a.replace(/\n+$/,"")});else if(a=d.rules.fences.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"code",lang:a[2],text:a[3]||""});else if(a=d.rules.heading.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"heading",depth:a[1].length,text:a[2]});else if(t&&(a=d.rules.nptable.exec(e))){for(e=e.substring(a[0].length),l={type:"table",header:a[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:a[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:a[3].replace(/\n$/,"").split("\n")},u=0;u<l.align.length;u++)/^ *-+: *$/.test(l.align[u])?l.align[u]="right":/^ *:-+: *$/.test(l.align[u])?l.align[u]="center":/^ *:-+ *$/.test(l.align[u])?l.align[u]="left":l.align[u]=null;for(u=0;u<l.cells.length;u++)l.cells[u]=l.cells[u].split(/ *\| */);d.tokens.push(l)}else if(a=d.rules.lheading.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"heading",depth:"="===a[2]?1:2,text:a[1]});else if(a=d.rules.hr.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"hr"});else if(a=d.rules.blockquote.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"blockquote_start"}),a=a[0].replace(/^ *> ?/gm,""),d.token(a,t,!0),d.tokens.push({type:"blockquote_end"});else if(a=d.rules.list.exec(e)){for(e=e.substring(a[0].length),o=a[2],d.tokens.push({type:"list_start",ordered:o.length>1}),a=a[0].match(d.rules.item),r=!1,h=a.length,u=0;u<h;u++)l=a[u],c=l.length,l=l.replace(/^ *([*+-]|\d+\.) +/,""),~l.indexOf("\n ")&&(c-=l.length,l=d.options.pedantic?l.replace(/^ {1,4}/gm,""):l.replace(new RegExp("^ {1,"+c+"}","gm"),"")),d.options.smartLists&&u!==h-1&&(s=p.bullet.exec(a[u+1])[0],o===s||o.length>1&&s.length>1||(e=a.slice(u+1).join("\n")+e,u=h-1)),i=r||/\n\n(?!\s*$)/.test(l),u!==h-1&&(r="\n"===l.charAt(l.length-1),i||(i=r)),d.tokens.push({type:i?"loose_item_start":"list_item_start"}),d.token(l,!1,n),d.tokens.push({type:"list_item_end"});d.tokens.push({type:"list_end"})}else if(a=d.rules.html.exec(e))e=e.substring(a[0].length),d.tokens.push({type:d.options.sanitize?"paragraph":"html",pre:!d.options.sanitizer&&("pre"===a[1]||"script"===a[1]||"style"===a[1]),text:a[0]});else if(!n&&t&&(a=d.rules.def.exec(e)))e=e.substring(a[0].length),d.tokens.links[a[1].toLowerCase()]={href:a[2],title:a[3]};else if(t&&(a=d.rules.table.exec(e))){for(e=e.substring(a[0].length),l={type:"table",header:a[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:a[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:a[3].replace(/(?: *\| *)?\n$/,"").split("\n")},u=0;u<l.align.length;u++)/^ *-+: *$/.test(l.align[u])?l.align[u]="right":/^ *:-+: *$/.test(l.align[u])?l.align[u]="center":/^ *:-+ *$/.test(l.align[u])?l.align[u]="left":l.align[u]=null;for(u=0;u<l.cells.length;u++)l.cells[u]=l.cells[u].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */);d.tokens.push(l)}else if(t&&(a=d.rules.paragraph.exec(e)))e=e.substring(a[0].length),d.tokens.push({type:"paragraph",text:"\n"===a[1].charAt(a[1].length-1)?a[1].slice(0,-1):a[1]});else if(a=d.rules.text.exec(e))e=e.substring(a[0].length),d.tokens.push({type:"text",text:a[0]});else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0));return this.tokens};var h={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:l,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:l,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};h._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/,h._href=/\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/,h.link=s(h.link)("inside",h._inside)("href",h._href)(),h.reflink=s(h.reflink)("inside",h._inside)(),h.normal=c({},h),h.pedantic=c({},h.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/}),h.gfm=c({},h.normal,{escape:s(h.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:s(h.text)("]|","~]|")("|","|https?://|")()}),h.breaks=c({},h.gfm,{br:s(h.br)("{2,}","*")(),text:s(h.gfm.text)("{2,}","*")()}),n.rules=h,n.output=function(e,t,r){var i=new n(t,r);return i.output(e)},n.prototype.output=function(e){for(var t,n,r,i,o=this,s="";e;)if(i=o.rules.escape.exec(e))e=e.substring(i[0].length),s+=i[1];else if(i=o.rules.autolink.exec(e))e=e.substring(i[0].length),"@"===i[2]?(n=":"===i[1].charAt(6)?o.mangle(i[1].substring(7)):o.mangle(i[1]),r=o.mangle("mailto:")+n):(n=a(i[1]),r=n),s+=o.renderer.link(r,null,n);else if(o.inLink||!(i=o.rules.url.exec(e))){if(i=o.rules.tag.exec(e))!o.inLink&&/^<a /i.test(i[0])?o.inLink=!0:o.inLink&&/^<\/a>/i.test(i[0])&&(o.inLink=!1),e=e.substring(i[0].length),s+=o.options.sanitize?o.options.sanitizer?o.options.sanitizer(i[0]):a(i[0]):i[0];else if(i=o.rules.link.exec(e))e=e.substring(i[0].length),o.inLink=!0,s+=o.outputLink(i,{href:i[2],title:i[3]}),o.inLink=!1;else if((i=o.rules.reflink.exec(e))||(i=o.rules.nolink.exec(e))){if(e=e.substring(i[0].length),t=(i[2]||i[1]).replace(/\s+/g," "),t=o.links[t.toLowerCase()],!t||!t.href){s+=i[0].charAt(0),e=i[0].substring(1)+e;continue}o.inLink=!0,s+=o.outputLink(i,t),o.inLink=!1}else if(i=o.rules.strong.exec(e))e=e.substring(i[0].length),s+=o.renderer.strong(o.output(i[2]||i[1]));else if(i=o.rules.em.exec(e))e=e.substring(i[0].length),s+=o.renderer.em(o.output(i[2]||i[1]));else if(i=o.rules.code.exec(e))e=e.substring(i[0].length),s+=o.renderer.codespan(a(i[2],!0));else if(i=o.rules.br.exec(e))e=e.substring(i[0].length),s+=o.renderer.br();else if(i=o.rules.del.exec(e))e=e.substring(i[0].length),s+=o.renderer.del(o.output(i[1]));else if(i=o.rules.text.exec(e))e=e.substring(i[0].length),s+=o.renderer.text(a(o.smartypants(i[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else e=e.substring(i[0].length),n=a(i[1]),r=n,s+=o.renderer.link(r,null,n);return s},n.prototype.outputLink=function(e,t){var n=a(t.href),r=t.title?a(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,a(e[1]))},n.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014\/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014\/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},n.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,i=0;i<r;i++)t=e.charCodeAt(i),Math.random()>.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},r.prototype.code=function(e,t,n){if(this.options.highlight){var r=this.options.highlight(e,t);null!=r&&r!==e&&(n=!0,e=r)}return t?'<pre><code class="'+this.options.langPrefix+a(t,!0)+'">'+(n?e:a(e,!0))+"\n</code></pre>\n":"<pre><code>"+(n?e:a(e,!0))+"\n</code></pre>"},r.prototype.blockquote=function(e){return"<blockquote>\n"+e+"</blockquote>\n"},r.prototype.html=function(e){return e},r.prototype.heading=function(e,t,n){return"<h"+t+' id="'+this.options.headerPrefix+n.toLowerCase().replace(/[^\w]+/g,"-")+'">'+e+"</h"+t+">\n"},r.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"},r.prototype.list=function(e,t){var n=t?"ol":"ul";return"<"+n+">\n"+e+"</"+n+">\n"},r.prototype.listitem=function(e){return"<li>"+e+"</li>\n"},r.prototype.paragraph=function(e){return"<p>"+e+"</p>\n"},r.prototype.table=function(e,t){return"<table>\n<thead>\n"+e+"</thead>\n<tbody>\n"+t+"</tbody>\n</table>\n"},r.prototype.tablerow=function(e){return"<tr>\n"+e+"</tr>\n"},r.prototype.tablecell=function(e,t){var n=t.header?"th":"td",r=t.align?"<"+n+' style="text-align:'+t.align+'">':"<"+n+">";return r+e+"</"+n+">\n"},r.prototype.strong=function(e){return"<strong>"+e+"</strong>"},r.prototype.em=function(e){return"<em>"+e+"</em>"},r.prototype.codespan=function(e){return"<code>"+e+"</code>"},r.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"},r.prototype.del=function(e){return"<del>"+e+"</del>"},r.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(o(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:"))return""}var i='<a href="'+e+'"';return t&&(i+=' title="'+t+'"'),i+=">"+n+"</a>"},r.prototype.image=function(e,t,n){var r='<img src="'+e+'" alt="'+n+'"';return t&&(r+=' title="'+t+'"'),r+=this.options.xhtml?"/>":">"},r.prototype.text=function(e){return e},i.parse=function(e,t,n){var r=new i(t,n);return r.parse(e)},i.prototype.parse=function(e){var t=this;this.inline=new n(e.links,this.options,this.renderer),this.tokens=e.reverse();for(var r="";this.next();)r+=t.tok();return r},i.prototype.next=function(){return this.token=this.tokens.pop()},i.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},i.prototype.parseText=function(){for(var e=this,t=this.token.text;"text"===this.peek().type;)t+="\n"+e.next().text;return this.inline.output(t)},i.prototype.tok=function(){var e=this;switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var t,n,r,i,a,o="",s="";for(r="",t=0;t<this.token.header.length;t++)i={header:!0,align:e.token.align[t]},r+=e.renderer.tablecell(e.inline.output(e.token.header[t]),{header:!0,align:e.token.align[t]});for(o+=this.renderer.tablerow(r),t=0;t<this.token.cells.length;t++){for(n=e.token.cells[t],r="",a=0;a<n.length;a++)r+=e.renderer.tablecell(e.inline.output(n[a]),{header:!1,align:e.token.align[a]});s+=e.renderer.tablerow(r)}return this.renderer.table(o,s);case"blockquote_start":for(var s="";"blockquote_end"!==this.next().type;)s+=e.tok();return this.renderer.blockquote(s);case"list_start":for(var s="",l=this.token.ordered;"list_end"!==this.next().type;)s+=e.tok();return this.renderer.list(s,l);case"list_item_start":for(var s="";"list_item_end"!==this.next().type;)s+="text"===e.token.type?e.parseText():e.tok();return this.renderer.listitem(s);case"loose_item_start":for(var s="";"list_item_end"!==this.next().type;)s+=e.tok();return this.renderer.listitem(s);case"html":var c=this.token.pre||this.options.pedantic?this.token.text:this.inline.output(this.token.text);return this.renderer.html(c);case"paragraph":return this.renderer.paragraph(this.inline.output(this.token.text));case"text":return this.renderer.paragraph(this.parseText())}},l.exec=l,u.options=u.setOptions=function(e){return c(u.defaults,e),u},u.defaults={gfm:!0,tables:!0,breaks:!1,pedantic:!1,sanitize:!1,sanitizer:null,mangle:!0,smartLists:!1,silent:!1,highlight:null,langPrefix:"lang-",smartypants:!1,headerPrefix:"",renderer:new r,xhtml:!1},u.Parser=i,u.parser=i.parse,u.Renderer=r,u.Lexer=t,u.lexer=t.lex,u.InlineLexer=n,u.inlineLexer=n.output,u.parse=u,e.exports=u}).call(function(){return this||("undefined"!=typeof window?window:Re)}())}),Be=I(function(e){var t="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},n=function(){var e=/\blang(?:uage)?-(\w+)\b/i,n=0,r=t.Prism={util:{encode:function(e){return e instanceof i?new i(e.type,r.util.encode(e.content),e.alias):"Array"===r.util.type(e)?e.map(r.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++n}),e.__id},clone:function(e){var t=r.util.type(e);switch(t){case"Object":var n={};for(var i in e)e.hasOwnProperty(i)&&(n[i]=r.util.clone(e[i]));return n;case"Array":return e.map&&e.map(function(e){return r.util.clone(e)})}return e}},languages:{extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var i in t)n[i]=t[i];return n},insertBefore:function(e,t,n,i){i=i||r.languages;var a=i[e];if(2==arguments.length){n=arguments[1];for(var o in n)n.hasOwnProperty(o)&&(a[o]=n[o]);return a}var s={};for(var l in a)if(a.hasOwnProperty(l)){if(l==t)for(var o in n)n.hasOwnProperty(o)&&(s[o]=n[o]);
s[l]=a[l]}return r.languages.DFS(r.languages,function(t,n){n===i[e]&&t!=e&&(this[t]=s)}),i[e]=s},DFS:function(e,t,n,i){i=i||{};for(var a in e)e.hasOwnProperty(a)&&(t.call(e,a,e[a],n||a),"Object"!==r.util.type(e[a])||i[r.util.objId(e[a])]?"Array"!==r.util.type(e[a])||i[r.util.objId(e[a])]||(i[r.util.objId(e[a])]=!0,r.languages.DFS(e[a],t,a,i)):(i[r.util.objId(e[a])]=!0,r.languages.DFS(e[a],t,null,i)))}},plugins:{},highlightAll:function(e,t){var n={callback:t,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};r.hooks.run("before-highlightall",n);for(var i,a=n.elements||document.querySelectorAll(n.selector),o=0;i=a[o++];)r.highlightElement(i,e===!0,n.callback)},highlightElement:function(n,i,a){for(var o,s,l=n;l&&!e.test(l.className);)l=l.parentNode;l&&(o=(l.className.match(e)||[,""])[1].toLowerCase(),s=r.languages[o]),n.className=n.className.replace(e,"").replace(/\s+/g," ")+" language-"+o,l=n.parentNode,/pre/i.test(l.nodeName)&&(l.className=l.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var c=n.textContent,u={element:n,language:o,grammar:s,code:c};if(r.hooks.run("before-sanity-check",u),!u.code||!u.grammar)return u.code&&(u.element.textContent=u.code),void r.hooks.run("complete",u);if(r.hooks.run("before-highlight",u),i&&t.Worker){var p=new Worker(r.filename);p.onmessage=function(e){u.highlightedCode=e.data,r.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,a&&a.call(u.element),r.hooks.run("after-highlight",u),r.hooks.run("complete",u)},p.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=r.highlight(u.code,u.grammar,u.language),r.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,a&&a.call(n),r.hooks.run("after-highlight",u),r.hooks.run("complete",u)},highlight:function(e,t,n){var a=r.tokenize(e,t);return i.stringify(r.util.encode(a),n)},tokenize:function(e,t,n){var i=r.Token,a=[e],o=t.rest;if(o){for(var s in o)t[s]=o[s];delete t.rest}e:for(var s in t)if(t.hasOwnProperty(s)&&t[s]){var l=t[s];l="Array"===r.util.type(l)?l:[l];for(var c=0;c<l.length;++c){var u=l[c],p=u.inside,h=!!u.lookbehind,d=!!u.greedy,g=0,f=u.alias;if(d&&!u.pattern.global){var m=u.pattern.toString().match(/[imuy]*$/)[0];u.pattern=RegExp(u.pattern.source,m+"g")}u=u.pattern||u;for(var v=0,b=0;v<a.length;b+=a[v].length,++v){var y=a[v];if(a.length>e.length)break e;if(!(y instanceof i)){u.lastIndex=0;var k=u.exec(y),w=1;if(!k&&d&&v!=a.length-1){if(u.lastIndex=b,k=u.exec(e),!k)break;for(var x=k.index+(h?k[1].length:0),_=k.index+k[0].length,S=v,L=b,C=a.length;S<C&&L<_;++S)L+=a[S].length,x>=L&&(++v,b=L);if(a[v]instanceof i||a[S-1].greedy)continue;w=S-v,y=e.slice(b,L),k.index-=b}if(k){h&&(g=k[1].length);var x=k.index+g,k=k[0].slice(g),_=x+k.length,$=y.slice(0,x),E=y.slice(_),T=[v,w];$&&T.push($);var A=new i(s,p?r.tokenize(k,p):k,f,k,d);T.push(A),E&&T.push(E),Array.prototype.splice.apply(a,T)}}}}}return a},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var i,a=0;i=n[a++];)i(t)}}},i=r.Token=function(e,t,n,r,i){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!i};if(i.stringify=function(e,t,n){if("string"==typeof e)return e;if("Array"===r.util.type(e))return e.map(function(n){return i.stringify(n,t,e)}).join("");var a={type:e.type,content:i.stringify(e.content,t,n),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:n};if("comment"==a.type&&(a.attributes.spellcheck="true"),e.alias){var o="Array"===r.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(a.classes,o)}r.hooks.run("wrap",a);var s=Object.keys(a.attributes).map(function(e){return e+'="'+(a.attributes[e]||"").replace(/"/g,"&quot;")+'"'}).join(" ");return"<"+a.tag+' class="'+a.classes.join(" ")+'"'+(s?" "+s:"")+">"+a.content+"</"+a.tag+">"},!t.document)return t.addEventListener?(t.addEventListener("message",function(e){var n=JSON.parse(e.data),i=n.language,a=n.code,o=n.immediateClose;t.postMessage(r.highlight(a,r.languages[i],i)),o&&t.close()},!1),t.Prism):t.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(r.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(r.highlightAll):window.setTimeout(r.highlightAll,16):document.addEventListener("DOMContentLoaded",r.highlightAll))),t.Prism}();e.exports&&(e.exports=n),"undefined"!=typeof Re&&(Re.Prism=n),n.languages.markup={comment:/<!--[\w\W]*?-->/,prolog:/<\?[\w\W]+?\?>/,doctype:/<!DOCTYPE[\w\W]+?>/i,cdata:/<!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},n.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&amp;/,"&"))}),n.languages.xml=n.languages.markup,n.languages.html=n.languages.markup,n.languages.mathml=n.languages.markup,n.languages.svg=n.languages.markup,n.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:{pattern:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},n.languages.css.atrule.inside.rest=n.util.clone(n.languages.css),n.languages.markup&&(n.languages.insertBefore("markup","tag",{style:{pattern:/(<style[\w\W]*?>)[\w\W]*?(?=<\/style>)/i,lookbehind:!0,inside:n.languages.css,alias:"language-css"}}),n.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:n.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:n.languages.css}},alias:"language-css"}},n.languages.markup.tag)),n.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(true|false)\b/,function:/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},n.languages.javascript=n.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,function:/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*\*?|\/|~|\^|%|\.{3}/}),n.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}}),n.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\\\|\\?[^\\])*?`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:n.languages.javascript}},string:/[\s\S]+/}}}),n.languages.markup&&n.languages.insertBefore("markup","tag",{script:{pattern:/(<script[\w\W]*?>)[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:n.languages.javascript,alias:"language-javascript"}}),n.languages.js=n.languages.javascript,function(){"undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector&&(self.Prism.fileHighlight=function(){var e={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"};Array.prototype.forEach&&Array.prototype.slice.call(document.querySelectorAll("pre[data-src]")).forEach(function(t){for(var r,i=t.getAttribute("data-src"),a=t,o=/\blang(?:uage)?-(?!\*)(\w+)\b/i;a&&!o.test(a.className);)a=a.parentNode;if(a&&(r=(t.className.match(o)||[,""])[1]),!r){var s=(i.match(/\.(\w+)$/)||[,""])[1];r=e[s]||s}var l=document.createElement("code");l.className="language-"+r,t.textContent="",l.textContent="Loading…",t.appendChild(l);var c=new XMLHttpRequest;c.open("GET",i,!0),c.onreadystatechange=function(){4==c.readyState&&(c.status<400&&c.responseText?(l.textContent=c.responseText,n.highlightElement(l)):c.status>=400?l.textContent="✖ Error "+c.status+" while fetching file: "+c.statusText:l.textContent="✖ Error: File does not exist or is empty")},c.send(null)})},document.addEventListener("DOMContentLoaded",self.Prism.fileHighlight))}()}),De={},Ue=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^`{|}~]/g;R.clear=function(){De={}};var Ge=We,Ve="",Xe="",Ze=new We.Renderer,Ye={},Je=[],Qe=e(function(e){var t="";return e?(t=Ge(e),t=B(t),R.clear(),t):e});Qe.renderer=Ze,Qe.init=function(e,t){void 0===e&&(e={}),void 0===t&&(t=window.location.pathname),Ve=Ee(t),r(e)?Ge=e(We,Ze):(Ze=pe(Ze,e.renderer),We.setOptions(pe(e,{renderer:Ze})))},Qe.update=function(){Xe=w().path},Ze.heading=function(e,t){var n={level:t,title:e};/{docsify-ignore}/g.test(e)&&(e=e.replace("{docsify-ignore}",""),n.title=e,n.ignoreSubHeading=!0),/{docsify-ignore-all}/g.test(e)&&(e=e.replace("{docsify-ignore-all}",""),n.title=e,n.ignoreAllSubs=!0);var r=R(e),i=x(Xe,{id:r});return n.slug=i,Je.push(n),"<h"+t+' id="'+r+'"><a href="'+i+'" data-id="'+r+'" class="anchor"><span>'+e+"</span></a></h"+t+">"},Ze.code=function(e,t){void 0===t&&(t="");var n=Be.highlight(e,Be.languages[t]||Be.languages.markup);return'<pre v-pre data-lang="'+t+'"><code class="lang-'+t+'">'+n+"</code></pre>"},Ze.link=function(e,t,n){var r="";return/:|(\/{2})/.test(e)?r=' target="_blank"':e=x(e,null,Xe),t&&(t=' title="'+t+'"'),'<a href="'+e+'"'+(t||"")+r+">"+n+"</a>"},Ze.paragraph=function(e){return/^!&gt;/.test(e)?F("tip",e):/^\?&gt;/.test(e)?F("warn",e):"<p>"+e+"</p>"},Ze.image=function(e,t,n){var r=e,i=t?' title="'+t+'"':"";return Te(e)||(r=v(Ve,e)),'<img src="'+r+'" data-origin="'+e+'" alt="'+n+'"'+i+">"};var Ke=Object.freeze({markdown:Qe,sidebar:D,subSidebar:U,cover:G}),et={},tt=Object.freeze({cached:e,hyphenate:ue,merge:pe,isPrimitive:t,noop:n,isFn:r,UA:_e,isIE:Se,isMobile:Le}),nt=function(){window.Docsify={util:tt,dom:xe,render:Ke,route:Me,get:j,slugify:R},window.marked=We,window.Prism=Be},rt=ce.prototype;se(rt),ee(rt),Y(rt),ae(rt),ne(rt),nt(),setTimeout(function(e){return new ce},0)}();
(function(Prism) {
var insideString = {
variable: [
// Arithmetic Environment
{
pattern: /\$?\(\([\s\S]+?\)\)/,
inside: {
// If there is a $ sign at the beginning highlight $(( and )) as variable
variable: [{
pattern: /(^\$\(\([\s\S]+)\)\)/,
lookbehind: true
},
/^\$\(\(/,
],
number: /\b-?(?:0x[\dA-Fa-f]+|\d*\.?\d+(?:[Ee]-?\d+)?)\b/,
// Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic
operator: /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,
// If there is no $ sign at the beginning highlight (( and )) as punctuation
punctuation: /\(\(?|\)\)?|,|;/
}
},
// Command Substitution
{
pattern: /\$\([^)]+\)|`[^`]+`/,
inside: {
variable: /^\$\(|^`|\)$|`$/
}
},
/\$(?:[a-z0-9_#\?\*!@]+|\{[^}]+\})/i
],
};
Prism.languages.bash = {
'shebang': {
pattern: /^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,
alias: 'important'
},
'comment': {
pattern: /(^|[^"{\\])#.*/,
lookbehind: true
},
'string': [
//Support for Here-Documents https://en.wikipedia.org/wiki/Here_document
{
pattern: /((?:^|[^<])<<\s*)(?:"|')?(\w+?)(?:"|')?\s*\r?\n(?:[\s\S])*?\r?\n\2/g,
lookbehind: true,
greedy: true,
inside: insideString
},
{
pattern: /(["'])(?:\\\\|\\?[^\\])*?\1/g,
greedy: true,
inside: insideString
}
],
'variable': insideString.variable,
// Originally based on http://ss64.com/bash/
'function': {
pattern: /(^|\s|;|\||&)(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|\s|;|\||&)/,
lookbehind: true
},
'keyword': {
pattern: /(^|\s|;|\||&)(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|\s|;|\||&)/,
lookbehind: true
},
'boolean': {
pattern: /(^|\s|;|\||&)(?:true|false)(?=$|\s|;|\||&)/,
lookbehind: true
},
'operator': /&&?|\|\|?|==?|!=?|<<<?|>>|<=?|>=?|=~/,
'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];]/
};
var inside = insideString.variable[1].inside;
inside['function'] = Prism.languages.bash['function'];
inside.keyword = Prism.languages.bash.keyword;
inside.boolean = Prism.languages.bash.boolean;
inside.operator = Prism.languages.bash.operator;
inside.punctuation = Prism.languages.bash.punctuation;
})(Prism);
Prism.languages.json = {
'property': /"(?:\\.|[^\\"])*"(?=\s*:)/ig,
'string': /"(?!:)(?:\\.|[^\\"])*"(?!:)/g,
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?)\b/g,
'punctuation': /[{}[\]);,]/g,
'operator': /:/g,
'boolean': /\b(true|false)\b/gi,
'null': /\bnull\b/gi
};
Prism.languages.jsonp = Prism.languages.json;
@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}body:not(.ready){overflow:hidden}body:not(.ready) .app-nav,body:not(.ready) [data-cloak]{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}.emoji{height:19.2px;height:1.2rem;vertical-align:middle}.progress{background-color:#42b983;background-color:var(--theme-color,#42b983);height:2px;left:0;position:fixed;right:0;top:0;-webkit-transition:width .2s,opacity .4s;transition:width .2s,opacity .4s;width:0;z-index:5}.search .search-keyword,.search a:hover{color:#42b983;color:var(--theme-color,#42b983)}.search .search-keyword{font-style:normal}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#34495e;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}.app-nav{left:0;margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:2}.app-nav p{margin:0}.app-nav>a{margin:0 16px;margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;-webkit-transition:color .3s;transition:color .3s}.app-nav a.active,.app-nav a:hover{color:#42b983;color:var(--theme-color,#42b983)}.app-nav a.active{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983)}.app-nav li{display:inline-block;margin:0 16px;margin:0 1rem;padding:5px 0;position:relative}.app-nav li ul{background-color:#fff;border:1px solid #ddd;border-bottom-color:#ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:scroll;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:16px;line-height:1rem;margin:0;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.app-nav.no-badge{margin-right:25px}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner svg{color:#fff;fill:#42b983;fill:var(--theme-color,#42b983);height:80px;width:80px}.github-corner:hover .octo-arm{-webkit-animation:a .56s ease-in-out;animation:a .56s ease-in-out}main{display:block;position:relative;width:100vw;height:100%}.anchor{display:inline-block;text-decoration:none;-webkit-transition:all .3s;transition:all .3s}.anchor span{color:#34495e}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0;top:0;bottom:0;left:0;position:absolute;-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out;width:300px;z-index:3}.sidebar>h1{margin:0 auto 16px;margin:0 auto 1rem;font-size:24px;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar ul{margin:0;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53%,.1)}.sidebar-toggle{background-color:transparent;background-color:hsla(0,0%,100%,.8);border:0;outline:none;padding:10px;bottom:0;left:0;position:absolute;text-align:center;-webkit-transition:opacity .3s;transition:opacity .3s;width:30px;width:284px;z-index:4}.sidebar-toggle .sidebar-toggle-button:hover{opacity:.4}.sidebar-toggle span{background-color:#42b983;background-color:var(--theme-color,#42b983);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:20px;top:0;right:0;bottom:0;left:300px;position:absolute;-webkit-transition:left .25s ease;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:800px;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:16px;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section p.tip,.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#34495e}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;width:20px;height:20px;text-align:center;top:14px}.markdown-section p.warn{background:rgba(66,185,131,.1);border-radius:2px;padding:16px;padding:1rem}body.close .sidebar{-webkit-transform:translateX(-300px);transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;overflow-x:hidden}.sidebar{left:-300px;-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out}.content{left:0;max-width:100vw;position:static;-webkit-transition:-webkit-transform .25s ease;transition:-webkit-transform .25s ease;transition:transform .25s ease;transition:transform .25s ease,-webkit-transform .25s ease}.app-nav,.github-corner{-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto}body.close .sidebar{-webkit-transform:translateX(300px);transform:translateX(300px)}body.close .sidebar-toggle{background-color:hsla(0,0%,100%,.8);-webkit-transition:background-color 1s;transition:background-color 1s;width:284px}body.close .content{-webkit-transform:translateX(300px);transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner .octo-arm{-webkit-animation:a .56s ease-in-out;animation:a .56s ease-in-out}.github-corner:hover .octo-arm{-webkit-animation:none;animation:none}}@-webkit-keyframes a{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@keyframes a{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}section.cover{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;height:100vh;display:none}section.cover .cover-main{-webkit-box-flex:1;-ms-flex:1;flex:1;margin:-20px 16px 0;text-align:center;z-index:1}section.cover a{color:inherit}section.cover a,section.cover a:hover{text-decoration:none}section.cover p{line-height:24px;line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:40px;font-size:2.5rem;font-weight:300;margin:10px 0 40px;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-7px;bottom:-.4375rem;font-size:16px;font-size:1rem;position:absolute}section.cover blockquote{font-size:24px;font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border-color:#42b983;border:1px solid var(--theme-color,#42b983);border-radius:2rem;box-sizing:border-box;color:#42b983;color:var(--theme-color,#42b983);display:inline-block;font-size:16.8px;font-size:1.05rem;letter-spacing:1.6px;letter-spacing:.1rem;margin-right:16px;margin-right:1rem;padding:.75em 32px;padding:.75em 2rem;text-decoration:none;-webkit-transition:all .15s ease;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:#42b983;background-color:var(--theme-color,#42b983);color:#fff;margin-right:0}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983);-webkit-transition:color .3s;transition:color .3s}section.cover blockquote>p>a:hover{color:#42b983;color:var(--theme-color,#42b983)}section.cover.show{display:-webkit-box;display:-ms-flexbox;display:flex}section.cover.has-mask .mask{background-color:#fff;opacity:.8;position:absolute;width:100%;height:100%}.sidebar,body{background-color:#fff}.sidebar{color:#364149}.sidebar li{margin:6px 0 6px 15px}.sidebar ul li a{color:#505d6b;font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{border-right:2px solid;color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.app-sub-sidebar .section-link:before{content:"-";padding-right:4px}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#2c3e50;font-weight:600}.markdown-section a{color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.markdown-section h1{font-size:32px;font-size:2rem;margin:0 0 16px;margin:0 0 1rem}.markdown-section h2{font-size:28px;font-size:1.75rem;margin:45px 0 12.8px;margin:45px 0 .8rem}.markdown-section h3{font-size:24px;font-size:1.5rem;margin:40px 0 9.6px;margin:40px 0 .6rem}.markdown-section h4{font-size:20px;font-size:1.25rem}.markdown-section h5,.markdown-section h6{font-size:16px;font-size:1rem}.markdown-section h6{color:#777}.markdown-section figure,.markdown-section ol,.markdown-section p,.markdown-section ul{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:25.6px;line-height:1.6rem;word-spacing:.8px;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:24px;padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid #42b983;border-left:4px solid var(--theme-color,#42b983);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code{border-radius:2px;color:#e96900;font-size:12.8px;font-size:.8rem;margin:0 2px;padding:3px 5px;white-space:nowrap}.markdown-section code,.markdown-section pre{background-color:#f8f8f8;font-family:Roboto Mono,Monaco,courier,monospace}.markdown-section pre{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;line-height:24px;line-height:1.5rem;margin:1.2em 0;overflow:auto;padding:0 22.4px;padding:0 1.4rem;position:relative;word-wrap:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:#42b983;color:var(--theme-color,#42b983)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:#42b983;color:var(--theme-color,#42b983)}.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;background-color:#f8f8f8;border-radius:2px;color:#525252;display:block;font-family:Roboto Mono,Monaco,courier,monospace;font-size:12.8px;font-size:.8rem;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;padding:2.2em 5px;white-space:inherit}.markdown-section code:after,.markdown-section code:before{letter-spacing:.8px;letter-spacing:.05rem}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:24px;min-height:1.5rem}pre:after{color:#ccc;content:attr(data-lang);font-size:9.6px;font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0}
\ No newline at end of file
(function () {
'use strict';
/*
* medium-zoom v0.2.0
* Medium zoom on your images in vanilla JavaScript
* Copyright 2017 Francois Chalifour
* https://github.com/francoischalifour/medium-zoom
* MIT License
*/function __$styleInject(a,b){if('undefined'==typeof document){ return b; }a=a||'';var c=document.head||document.getElementsByTagName('head')[0],d=document.createElement('style');return d.type='text/css',c.appendChild(d),d.styleSheet?d.styleSheet.cssText=a:d.appendChild(document.createTextNode(a)),b}function createCommonjsModule(a,b){return b={exports:{}},a(b,b.exports),b.exports}var _extends=Object.assign||function(a){for(var b,c=1;c<arguments.length;c++){ for(var d in b=arguments[c],b){ Object.prototype.hasOwnProperty.call(b,d)&&(a[d]=b[d]); } }return a}; var toConsumableArray=function(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);b<a.length;b++){ c[b]=a[b]; }return c}return Array.from(a)}; var mediumZoom_1=createCommonjsModule(function(a){var b=['IMG'],c=[27,81],d=function(a){return b.includes(a.tagName)},e=function(a){return a.naturalWidth!==a.width},f=function(a){return NodeList.prototype.isPrototypeOf(a)||HTMLCollection.prototype.isPrototypeOf(a)},g=function(a){return a&&1===a.nodeType};a.exports=function(a){var h=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=h.margin,j=void 0===i?0:i,k=h.background,l=void 0===k?'#fff':k,m=h.scrollOffset,n=void 0===m?48:m,o=h.metaClick,p=function(a){var b=a.getBoundingClientRect(),c=b.top,d=b.left,e=b.width,f=b.height,g=a.cloneNode(),h=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,i=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;return g.removeAttribute('id'),g.style.position='absolute',g.style.top=c+h+'px',g.style.left=d+i+'px',g.style.width=e+'px',g.style.height=f+'px',g.style.transform='',g},q=function(){if(C.template){ if(C.template.dispatchEvent(new Event('show')),D=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,E=!0,C.zoomed=p(C.template),document.body.appendChild(B),document.body.appendChild(C.zoomed),requestAnimationFrame(function(){document.body.classList.add('medium-zoom--open');}),C.template.style.visibility='hidden',C.zoomed.classList.add('medium-zoom-image--open'),C.zoomed.addEventListener('click',r),C.zoomed.addEventListener('transitionend',u),C.template.getAttribute('data-zoom-target')){C.zoomedHd=C.zoomed.cloneNode(),C.zoomedHd.src=C.zoomed.getAttribute('data-zoom-target'),C.zoomedHd.onerror=function(){clearInterval(a),console.error('Unable to reach the zoom image target '+C.zoomedHd.src),C.zoomedHd=null,y();};var a=setInterval(function(){C.zoomedHd.naturalWidth&&(clearInterval(a),C.zoomedHd.classList.add('medium-zoom-image--open'),C.zoomedHd.addEventListener('click',r),document.body.appendChild(C.zoomedHd),y());},10);}else { y(); } }},r=function a(){var b=0<arguments.length&&void 0!==arguments[0]?arguments[0]:0,c=function(){E||!C.template||(C.template.dispatchEvent(new Event('hide')),E=!0,document.body.classList.remove('medium-zoom--open'),C.zoomed.style.transform='',C.zoomedHd&&(C.zoomedHd.style.transform='',C.zoomedHd.removeEventListener('click',a)),C.zoomed.removeEventListener('click',a),C.zoomed.addEventListener('transitionend',v));};0<b?setTimeout(c,b):c();},s=function(a){C.template?r():(C.template=a?a.target:A[0],q());},t=function(a){return(a.metaKey||a.ctrlKey)&&z.metaClick?window.open(a.target.getAttribute('data-original')||a.target.parentNode.href||a.target.src,'_blank'):void(a.preventDefault(),s(a))},u=function a(){E=!1,C.zoomed.removeEventListener('transitionend',a),C.template.dispatchEvent(new Event('shown'));},v=function a(){C.template&&(C.template.style.visibility='',document.body.removeChild(C.zoomed),C.zoomedHd&&document.body.removeChild(C.zoomedHd),document.body.removeChild(B),C.zoomed.classList.remove('medium-zoom-image--open'),E=!1,C.zoomed.removeEventListener('transitionend',a),C.template.dispatchEvent(new Event('hidden')),C.template=null,C.zoomed=null,C.zoomedHd=null);},w=function(){if(!E&&C.template){var a=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;Math.abs(D-a)>z.scrollOffset&&r(150);}},x=function(a){c.includes(a.keyCode||a.which)&&r();},y=function(){var a=Math.min;if(C.template){var b=window.innerWidth,c=window.innerHeight,d=b-2*z.margin,e=c-2*z.margin,f=C.zoomedHd||C.template,g=f.naturalWidth,h=void 0===g?d:g,i=f.naturalHeight,j=void 0===i?e:i,k=f.getBoundingClientRect(),l=k.top,m=k.left,n=k.width,o=k.height,p=a(h,d)/n,q=a(j,e)/o,r=a(p,q)||1,s=(-m+(d-n)/2+z.margin)/r,t=(-l+(e-o)/2+z.margin)/r,u='scale('+r+') translate3d('+s+'px, '+t+'px, 0)';C.zoomed.style.transform=u,C.zoomedHd&&(C.zoomedHd.style.transform=u);}},z={margin:j,background:l,scrollOffset:n,metaClick:void 0===o||o};a instanceof Object&&_extends(z,a);var A=function(a){try{return Array.isArray(a)?a.filter(d):f(a)?[].concat(toConsumableArray(a)).filter(d):g(a)?[a].filter(d):'string'==typeof a?[].concat(toConsumableArray(document.querySelectorAll(a))).filter(d):[].concat(toConsumableArray(document.querySelectorAll(b.map(function(a){return a.toLowerCase()}).join(',')))).filter(e)}catch(a){throw new TypeError('The provided selector is invalid.\nExpects a CSS selector, a Node element, a NodeList, an HTMLCollection or an array.\nSee: https://github.com/francoischalifour/medium-zoom')}}(a),B=function(a){var b=document.createElement('div');return b.classList.add('medium-zoom-overlay'),b.style.backgroundColor=a,b}(z.background),C={template:null,zoomed:null,zoomedHd:null},D=0,E=!1;return A.forEach(function(a){a.classList.add('medium-zoom-image'),a.addEventListener('click',t);}),B.addEventListener('click',r),document.addEventListener('scroll',w),document.addEventListener('keyup',x),window.addEventListener('resize',r),{show:s,hide:r,toggle:s,update:function(){var a=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};return a.background&&(B.style.backgroundColor=a.background),_extends(z,a)},addEventListeners:function(a,b){A.forEach(function(c){c.addEventListener(a,b);});},detach:function(){var a=function a(){var b=new Event('detach');A.forEach(function(a){a.classList.remove('medium-zoom-image'),a.removeEventListener('click',t),a.dispatchEvent(b);}),A.splice(0,A.length),B.removeEventListener('click',r),document.removeEventListener('scroll',w),document.removeEventListener('keyup',x),window.removeEventListener('resize',r),C.zoomed&&C.zoomed.removeEventListener('transitionend',a);};C.zoomed?(r(),C.zoomed.addEventListener('transitionend',requestAnimationFrame(a))):a();},images:A,options:z}};});__$styleInject('.medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--open .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s}.medium-zoom-image--open{position:relative;z-index:1;cursor:pointer;cursor:zoom-out;will-change:transform}',void 0);var src=mediumZoom_1;
function install (hook) {
var zoom;
hook.doneEach(function (_) {
if (zoom) {
zoom.detach();
}
zoom = src('img:not(.emoji):not([data-no-zoom])');
});
}
$docsify.plugins = [].concat(install, $docsify.plugins);
}());
const router = require('koa-router')();
const taskController=require('./../controllers/task')
const signController=require('./../controllers/sign')
const routers = router
.get('getCity',taskController.getCity)
.get('getHelpInfo',taskController.getHelpInfo)
.post('getOrderSn',taskController.createTask)
.post('getCode',taskController.getCode)
.post('query',taskController.query)
.post('getData',taskController.getData)
.post('result',taskController.result)
.post('getToken',signController.getToken)
.post('getIncomeProve',taskController.getIncomeProve)
module.exports = routers;
\ No newline at end of file
const router = require('koa-router')();
const home = require('./home');
router.use('/IncomeTaxAPI/', home.routes(), home.allowedMethods());
module.exports = router
\ No newline at end of file
const request = require('request');
const config = require('../config');
const StorageHost = config.StorageHost;
const
setStorageUrl=StorageHost+'/data',
getStorageUrl=StorageHost+'/IncomeTax/';
exports.dataStorage=(params)=>{
return new Promise(function (resolve, reject) {
let options = {
url: setStorageUrl,
method: 'POST',
json: true,
body: params,
headers: {
'content-type': 'application/json'
}
};
request(options, (e, r, b) => {
if (e) {
return resolve({ code: -1, msg: '数据库服务器出错'});
} else {
return resolve(b);
}
});
});
};
exports.readData=(orderSn)=>{
return new Promise(function (resolve, reject) {
let url =getStorageUrl + orderSn;
let options = {
url: url,
gzip: true
};
request(options, (e, r, b) => {
if (e) {
return resolve({ code: -1, msg: '数据库服务器出错'});
} else {
return resolve(b);
}
});
});
};
\ No newline at end of file
const request = require('request');
const config = require('../config');
const SignHost = config.SignHost;
const
signUrl=SignHost+'/Access/SignValidityCheck',
tokenUrl=SignHost+'/Access/GetToken',
orderSnUrl=SignHost+'/Order/GetOrderSn',
getPartner=SignHost+'/customer/query';
/*获取Token*/
exports.getToken=(params)=>{
return new Promise((resolve,reject)=>{
let errMsg = {code: 3000, msg: '签名校验服务出错'};
let options = {
url: tokenUrl,
method: 'POST',
json: true,
body: params,
headers: {
'content-type': 'application/json'
}
};
request(options, (e, r, b) => {
if (e) {
console.error('[func getToken]',params,e);
resolve(errMsg);
} else {
if (b.code == 0) {
resolve(b);
} else {
console.error('[func getToken]',params,b);
errMsg = {code: 3000, msg: b.msg};
resolve(errMsg);
}
}
});
});
};
/*获取订单号*/
exports.getOrderSn=(params)=>{
return new Promise((resolve,reject)=>{
let errMsg = {code: 3000, msg: '签名校验服务出错'};
let options = {
url: orderSnUrl,
method: 'POST',
json: true,
body: params,
headers: {
'content-type': 'application/json'
}
};
request(options, (e, r, b) => {
if (e) {
console.error('[func getOrderSn]',params,e);
resolve(errMsg);
} else {
if (b.code == 0) {
resolve(b);
} else {
console.error('[func getOrderSn]',params,b);
errMsg = {code: 3000, msg:b.msg};
resolve(errMsg);
}
}
});
});
};
/*验证签名*/
exports.signValidation=(params)=>{
return new Promise((resolve, reject) => {
params.type=config.signType;
let options = {
url: signUrl,
method: 'POST',
json: true,
body: params,
headers: {
'content-type': 'application/json'
}
};
request(options, (e, r, vb) => {
if (e) {
console.error('[reGJJ][signValidityCheck] signValidityCheck error: ' ,e);
reject({code:-1,msg:'验签服务器出错'});
} else {
if (vb.code === 0) {
resolve(vb);
} else {
reject(vb);
}
}
});
});
};
/*获取合作方信息*/
exports.getCallbackMap=()=>{
return new Promise(function (resolve, reject) {
request({url:getPartner,gzip:true},(e,r,b)=>{
if(e){
console.error('getCityList');
console.error(e);
return reject(e);
}else{
return resolve(b);
}
});
});
};
const request=require('request')
const db=require('./../utils/db-util');
const signAPI=require('./ValidationAPI')
const taskAPI=require('./taskAPI');
const log=require('../utils/log');
let cityList=[];
let orderSnMap = new Map();
let CustomerMap= new Map();
let cityMap=new Map();
let helpInfo=[];
let newCityMap=new Map()
function getCityList() {
taskAPI.getCityList("gsgj").then(Row=>{
Row=JSON.parse(Row);
Row.data.map(Prov=>{
Prov.citys.map(city=>{
newCityMap.set(String(city.id),city)
})
});
taskAPI.getCityList("51gs").then(Row51=>{
Row51=JSON.parse(Row51);
cityList=[];
Row51.data.map(Prov=>{
let newProv = { provinceName: Prov.provinceName, citys: [] };
Prov.citys.map(city=>{
city.type="51gs";
if(city.state===-1&&newCityMap.get(String(city.id))&&newCityMap.get(String(city.id)).state!==-1){
city=newCityMap.get(String(city.id))
city.type="gsgj";
console.log(city)
}
cityMap.set(String(city.id),city)
if (city.state === 1 || city.state === -1) {
newProv.citys.push({
province: city.province,
name: city.name,
id: city.id,
state: city.state,
queryParam: city.queryParam
});
}
})
cityList.push(newProv)
});
})
}).catch(err=>{
log.error(err)
})
}
function getHelpInfo() {
db.QueryHelpInfo([['cid','city','help']]).then(Rows=>{
if(Rows.length>0){
helpInfo=Rows;
}else{
log.error("getHelpInfo")
}
}).catch(err=>{
log.error(err)
})
}
function getCustomer() {
signAPI.getCallbackMap().then(b=>{
b = JSON.parse(b);
if (b.code === 0) {
b.data.customerList.map(customer => {
if ('callBackUrl' in customer) {
CustomerMap.set(customer.appKey, customer.callBackUrl);
}
});
}
}).catch(err=>{
cosnole.error(err)
})
}
function getCustomerByAppKey(appKey) {
if(CustomerMap.has(appKey)){
return CustomerMap.get(appKey)
}else{
log.error("noCus",appKey)
return ""
}
}
getHelpInfo()
getCityList();
getCustomer();
setInterval(function () {
getCityList();
getCustomer();
getHelpInfo();
},1000*60*3);
function RCityList() {
return cityList
}
function RHelpInfo() {
return helpInfo
}
function getTaskByOrderSn(orderSn) {
return new Promise((resolve, reject) => {
if (orderSnMap.has(orderSn)) {
return resolve(orderSnMap.get(orderSn));
} else {
db.QueryFromStatus([['status', 'note', 'appKey', 'taskId'], orderSn]).then(Rows => {
if (Rows.length > 0) {
Rows[0].note = JSON.parse(Rows[0].note);
resolve(Rows[0]);
} else {
reject();
}
});
}
});
}
async function getapiTaskByOrderSn(orderSn) {
try {
let rows = await db.QueryFromStatus([['status', 'note', 'appKey', 'taskId'], orderSn]);
log.info("getapiTaskByOrderSn", rows);
return rows;
} catch (e) {
log.error("getapiTaskByOrderSn", e);
return [];
}
}
async function getH5TaskByOrderSn(orderSn) {
try {
let rows = await db.QueryFromH5Status([['status', 'appKey', 'taskId'], orderSn]);
log.info("getH5TaskByOrderSn", rows);
return rows;
} catch (e) {
log.error("getH5TaskByOrderSn", e);
return [];
}
}
function setOrderSnMap(key, values) {
values.time = new Date().getTime();
if (orderSnMap.has(key)) {
orderSnMap.get(key).status = values.status;
orderSnMap.get(key).note = values.note;
orderSnMap.get(key).taskId = values.taskId;
orderSnMap.get(key).time = values.time;
} else {
orderSnMap.set(key, values)
}
}
function ServerSideCall(appKey,data) {
let url=getCustomerByAppKey(appKey);
return new Promise((resolve, reject) => {
let options = {
url: url,
method: 'POST',
json: true,
body: data,
headers: {
'content-type': 'application/json'
}
};
request(options, (e, r, b) => {
if (e) {
log.error('callbackParams' + JSON.stringify(options));
log.error(e);
resolve();
} else {
log.info('callbackParams' + JSON.stringify(options));
log.info(b);
resolve();
}
});
});
}
function getCityById(centerId) {
if(cityMap.has(String(centerId))){
return cityMap.get(String(centerId))
}else{
log.error("centerId",centerId,cityMap)
return {}
}
}
exports.cityList=RCityList;
exports.helpInfo=RHelpInfo;
exports.setOrderSnMap=setOrderSnMap;
exports.getTaskByOrderSn = getTaskByOrderSn;
exports.getH5TaskByOrderSn = getH5TaskByOrderSn;
exports.getapiTaskByOrderSn = getapiTaskByOrderSn;
exports.getCustomerByAppKey=getCustomerByAppKey;
exports.ServerSideCall=ServerSideCall;
exports.getCityById=getCityById;
const request = require('request');
const config = require('../config');
const TaskHost = config.TaskHost;
const newTaskHost = config.newTaskHost;
const log=require('../utils/log');
// const staticVari=require('./staticVari');
const
cityListUrl = TaskHost + '/IncomeTax/getItSetting',
createTaskUrl = TaskHost + '/IncomeTax/createItTask',
getCodeUrl = TaskHost + '/IncomeTax/getItCode',
submitParamsUrl = TaskHost + '/IncomeTax/loginItWeb',
getDataUrl = TaskHost + '/IncomeTax/getItData';
const
cityListUrlNew = newTaskHost + '/IncomeTax/getItSetting',
createTaskUrlNew = newTaskHost + '/IncomeTax/createItTask',
getCodeUrlNew = newTaskHost + '/IncomeTax/getItCode',
submitParamsUrlNew = newTaskHost + '/IncomeTax/loginItWeb',
getDataUrlNew = newTaskHost + '/IncomeTax/getItData';
/*获取城市列表*/
exports.getCityList=(type)=> {
return new Promise(function (resolve, reject) {
request({url:type==="gsgj"?cityListUrlNew:cityListUrl,gzip:true},(e,r,b)=>{
if(e){
log.error('getCityList');
log.error(e);
return reject(e);
}else{
if(b){
return resolve(b);
}else{
log.error(r.statusCode);
}
}
});
});
};
/*创建任务*/
exports.createTask=(cityId,type)=> {
let errMsg = {code: 500, msg: '创建任务服务出错'};
return new Promise(function (resolve, reject) {
let form_data = {cityId: cityId};
let options = {
url: type==="gsgj"?createTaskUrlNew:createTaskUrl,
method: 'POST',
json: true,
body: form_data,
headers: {
'content-type': 'application/json'
}
};
request(options, (e, r, b) => {
if (e) {
log.error(e);
log.error('[createTask err]',JSON.stringify(options));
reject(errMsg);
} else {
if (b&&b.code === 0) {
resolve(b.data.taskId);
} else {
console.log('createTask err' , JSON.stringify(options),JSON.stringify(b));
reject(b);
}
}
});
});
};
/*获取验证码*/
exports.getCode=(params)=>{
return new Promise((resolve,reject)=>{
let errMsg={code:-1,msg:'服务器出错'};
let options = {
url: params.taskId.length>20?getCodeUrlNew:getCodeUrl,
method: 'POST',
json: true,
body: params,
headers: {
'content-type': 'application/json'
}
};
request(options, (e, r, b) => {
if (e) {
console.error('getCode',e);
resolve(errMsg);
} else {
if (b&&b.code === 0) {
resolve(b);
log.info(JSON.stringify(options))
log.info(b)
} else {
log.error('[getImgCode]ErrReq:' + JSON.stringify(params) + 'Res:' + JSON.stringify(b));
resolve(b);
}
}
});
});
};
/*提交参数*/
exports.submitParams=(params) =>{
let errMsg = {code: -1, msg: '服务器错误'};
return new Promise(function (resolve, reject) {
let options = {
url: params.taskId.length>20?submitParamsUrlNew:submitParamsUrl,
method: 'POST',
json: true,
body: params,
headers: {
'content-type': 'application/json'
}
};
log.info(JSON.stringify(options))
request(options, (e, r, b) => {
if (e) {
log.error('[GJJ][/ajax/commitParams]提交任务请求失败');
log.error(e);
resolve(errMsg);
} else {
if (b&&b.code === 0) {
resolve(b);
} else {
console.error('提交任务出错Req:+' + JSON.stringify(params) + ' Res: ' + JSON.stringify(b));
resolve(b);
}
}
});
});
};
/*拉取数据*/
exports.getData=(taskId)=>{
return new Promise((resolve,reject)=>{
let options = {
url:taskId.length>20?getDataUrlNew:getDataUrl,
method: 'POST',
json: true,
body: { taskId: taskId },
headers: {
'content-type': 'application/json'
}
};
request(options, (e, r, b) => {
if (e) {
console.error(e);
reject(e);
} else {
if(b){
resolve(b);
}else{
reject(r.statusCode)
}
}
});
});
};
'use strict';
const { app, assert } = require('egg-mock/bootstrap');
describe('test/app/controller/home.test.js', () => {
it('should assert', function* () {
const pkg = require('../../../package.json');
assert(app.config.keys.startsWith(pkg.name));
// const ctx = app.mockContext({});
// yield ctx.service.xx();
});
it('should GET /', () => {
return app.httpRequest()
.get('/')
.expect('hi, egg')
.expect(200);
});
});
const fs = require('fs');
const moment = require('moment');
const schedule = require('node-schedule');
const log = require('./log');
function getFileName(path) {
return new Promise((resolve, reject) => {
fs.readdir(path, (err, files) => {
if (err) {
reject(err);
} else {
resolve(files);
}
});
});
}
function removeFile(path) {
return new Promise((resolve, reject) => {
fs.unlink(path, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
function removeOverdueLogFile(eachFileName) {
let result = /IITAPI-(\d{8}).log/.exec(eachFileName);
if (null !== result) {
let date = moment(result[1], 'YYYYMMDD');
if (date.isValid() && moment().subtract(3, 'd').isAfter(date)) {
try {
removeFile(`./logs/${eachFileName}`);
log.info('删除三天前日志');
log.info(`${eachFileName}`);
} catch(e) {
log.error('删除日志失败');
log.error(e);
}
}
}
}
async function cleanLogFile() {
let filesName = await getFileName('./logs');
for (let eachFileName of filesName) {
removeOverdueLogFile(eachFileName);
}
}
function cleanLogEveryDay() {
schedule.scheduleJob('00 00 4 * * *', cleanLogFile);
}
module.exports = cleanLogEveryDay;
\ No newline at end of file
const config = require('./../config');
const mysql = require("mysql")
const pool = mysql.createPool(config.database)
let query = function( sql, values ) {
return new Promise(( resolve, reject ) => {
pool.getConnection(function(err, connection) {
if (err) {
resolve( err )
} else {
connection.query(sql, values, ( err, rows) => {
if ( err ) {
reject( err )
} else {
resolve( rows )
}
connection.release()
})
}
})
})
};
let selectUser = function( values ) {
let _sql = "SELECT ?? FROM adminuser WHERE ?? = ?"
return query( _sql, values )
}
let insertUser = function( values ) {
let _sql = "INSERT INTO adminuser set ?"
return query( _sql, values )
}
let insertObj = function( values ) {
let _sql = "INSERT INTO iit_status set ?"
return query( _sql, values )
}
let getCity=function (values) {
let _sql = "SELECT ?? FROM adminuser "
return query( _sql, values )
}
let updateData = function( values ) {
let _sql = "UPDATE iit_status SET ? WHERE orderId = ?"
return query( _sql, values )
}
let selectPartnerList = function( values ) {
let _sql = "SELECT ?? FROM admin_partner "
return query( _sql, values )
};
let QueryFromStatus = function (values) {
let _sql = "SELECT ?? FROM iit_status WHERE orderId = ?"
return query( _sql, values )
};
let QueryHelpInfo = function (values) {
let _sql = "SELECT ?? FROM iit_help "
return query( _sql, values )
};
let QueryFromH5Status = function (values) {
let _sql = "SELECT ?? FROM iith5_status WHERE orderId = ? and `status`= 'success'"
return query( _sql, values )
};
module.exports = {
query,
selectUser,
insertUser,
selectPartnerList,
getCity,
insertObj,
updateData,
QueryFromStatus,
QueryHelpInfo,
QueryFromH5Status
}
const log4js = require('log4js');
const config = require('../config');
log4js.configure(config.log4jsConfig);
module.exports = log4js.getLogger();
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<div id="app">hello</div>
</body>
</html>
\ No newline at end of file
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