Commit 2f6df8e7 authored by 刘松's avatar 刘松

final commit

parents
File added
运营平台说明:
1、datareceiver
遍历nginx 日志写到 数据库 requestdatas
部署位置: 54.223.242.95
2、yunbao-server-api
镜像: registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbao-data-api:latest
部署位置: 54.223.242.95
启动脚本: /home/ubuntu/scripts/yunbaoapi.sh
3、yunbao-server-ui
镜像: registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbaodata:latest
部署位置: 54.223.242.95
启动脚本: /home/ubuntu/scripts/yunbaoui.sh
FROM reg.yunpro.cn/library/node:9.11.1
WORKDIR /app
ENV PORT=8808
ENV PROJECT_LEVEL=production
RUN \
rm /etc/localtime && \
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY package.json /app/
COPY . /app
ENV NODE_ENV='production'
EXPOSE 8808
CMD node index.js
\ No newline at end of file
image: clean
@echo "building docker image"
@docker build -t registry.cn-hangzhou.aliyuncs.com/xiaoyun-ssp/receiver-api .
push:
@docker push registry.cn-hangzhou.aliyuncs.com/xiaoyun-ssp/receiver-api
clean:
@echo "cleanning"
\ No newline at end of file
const {
ESHOST = 'http://52.81.59.169:9200',
MONGO_DB = 'mongodb://localhost:27017/xiaoyunssp?authSource=admin',
MONGO_LOG_DB = 'mongodb://localhost:27017/xiaoyunsspdev?authSource=admin',
} = process.env;
module.exports = {
ESHOST,
MONGO_DB: MONGO_DB.replace(/&/g, ','),
MONGO_LOG_DB: MONGO_LOG_DB.replace(/&/g, ',')
};
\ No newline at end of file
const config = process.env.NODE_ENV === 'production'
? require('./prod')
: require('./dev');
console.log('RUN as ', process.env.NODE_ENV === 'production' ? 'Production' : 'Development');
module.exports = config;
\ No newline at end of file
const {
ESHOST = 'http://172.31.10.99:9200',
MONGO_DB = 'mongodb://172.31.13.47:1301,172.31.0.156:1301,172.31.10.99:1301/xiaoyunssp',
MONGO_LOG_DB = 'mongodb://172.31.13.47:1301,172.31.0.156:1301,172.31.10.99:1301/xiaoyunsspdev'
} = process.env;
module.exports = {
ESHOST,
MONGO_DB: MONGO_DB.replace(/&/g, ','),
MONGO_LOG_DB: MONGO_LOG_DB.replace(/&/g, ',')
};
\ No newline at end of file
const mongoose = require('mongoose');
const {
ObjectId
} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
filename: String,
lines: String
}, {
timestamps: true
});
module.exports = mongoose.model('file', schema);
\ No newline at end of file
const mongoose = require('mongoose');
const {
ObjectId
} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
nginxTime: Number,
filename: String,
data: Object
}, {
timestamps: true
});
module.exports = mongoose.model('requestdata', schema);
\ No newline at end of file
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
var morgan = require('morgan');
const request = require('request');
const app = express();
const { PORT = 8808 } = process.env;
const mongoose = require('mongoose');
const config = require('./config');
const { check, getInfo } = require('./scripts/logparser.js');
const url = 'http://forward.yunbao.hoogame.cn';
/*app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());
app.use(morgan('combined'));*/
const { MONGO_DB } = process.env;
app.use(function (req, res) {
console.dir(req.query);
console.dir(req.body);
request(url).pipe(res);
});
mongoose.connect(MONGO_DB || config.MONGO_DB, {});
console.log('MONGO CONNECT INFO: ', MONGO_DB || config.MONGO_DB);
/*app.use('/*',(req, res) => {
console.dir(req.query);
console.dir(req.body);
res.send({ status: 'ok' });
});*/
getInfo(path.join(__dirname,'./files'));
/*setInterval(() => {
getInfo(path.join(__dirname,'./files'));
}, 1000 * 60 * 10); */
app.listen(PORT, () => console.log(`index page app listening on port ${PORT}!`))
\ No newline at end of file
{
"name": "datareceiver",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "NODE_ENV='production' node index.js"
},
"dependencies": {
"body-parser": "^1.19.0",
"compressing": "^1.5.1",
"elasticsearch": "^16.7.2",
"express": "^4.17.1",
"linebyline": "^1.3.0",
"moment": "^2.29.1",
"mongoose": "^5.11.18",
"morgan": "^1.10.0",
"readline": "^1.3.0",
"request": "^2.88.2"
}
}
const fs = require("fs");
const path = require('path');
const readline = require('readline');
const moment = require('moment');
const compressing = require('compressing');
const elasticsearch= require('elasticsearch');
const child_process = require('child_process');
const { ESHOST } = require('../config');
const client = new elasticsearch.Client({
host: ESHOST,
log: 'trace',
apiVersion: '7.x', // use the same version of your Elasticsearch instance
});
let doing = false;
function decodeNginxLog(c) {
let r = '';
for (let i = 0; i < c.length;) {
if (c[i] === '\\' && c[i + 1] === 'x') {
let j = i;
let hexList = [];
while(true) {
if (c[j] === '\\' && c[j + 1] === 'x') {
hexList.push(c[j + 2]);
hexList.push(c[j + 3]);
} else {
break;
}
j += 4;
}
r += Buffer.from(hexList.join(''), 'hex').toString('utf8');
i = j;
} else{
r += c[i];
i++;
}
}
return r;
}
async function decompress(fileName) {
return new Promise(function(resolve,reject) {
compressing.gzip.uncompress(fileName, `${fileName}.txt`)
.then(() => {
resolve(`${fileName}.txt`);
})
.catch(err => {
console.error(err);
reject(err);
});
})
}
function stringToBase64(str){
var base64Str = new Buffer(str).toString('base64');
return base64Str;
}
function base64ToString(base64Str){
var str = new Buffer(base64Str,'base64').toString();
return str;
}
async function parseFile(fileName) {
let count = 0;
console.dir('parseFile 开始处理');
let fReadName = await decompress(fileName);
let id = await child_process.execSync('wc -l ' + fReadName + "| awk '{print $1}'");
let num = parseInt(id.toString().trim());
return new Promise(function(resolve,reject) {
const fRead = fs.createReadStream(fReadName);
const objReadline = readline.createInterface({
input: fRead
});
objReadline.on('line', async (line, linecount) => {
count++;
if(line.indexOf('/Log/logdata')>=0 || line.indexOf('setting?h5Type=')>=0 || line.indexOf('/plugin/config')>=0) {
let time_string = line.split("[")[1].split("]")[0].split(" ")[0];
let time = moment(time_string,'DD/MMM/YYYY:HH:mm:ss').format('x')
let info = decodeNginxLog(line).split('request_body:')[1].trim();
let data = {};
if(info.indexOf('resp_body') >= 0) info = info.split('resp_body')[0].trim();
if(info.indexOf('{') >=0) {
try{
info = JSON.parse(info);
} catch(e){
console.dir(e);
console.dir(info);
console.dir(decodeNginxLog(line).split('request_body:')[1].trim());
console.dir(decodeNginxLog(line));
console.dir(line);
console.log('end============')
}
let data = {};
if(info.encryption) {
delete info.encryption;
for(let k in info) {
let key = base64ToString(k);
data[key] = base64ToString(decodeURIComponent(info[k]));
}
data['encryption'] = 1;
info = data;
}
if(info.deviceInfo && info.deviceInfo.indexOf('{') >=0) {
info.deviceInfo = JSON.parse(decodeURIComponent(info.deviceInfo));
}
} else info = null;
if(info && line.indexOf('/plugin/config') >= 0) {
//if(info.sdk_version && info.sdk_version <= '1.2.1') { info.action = 'show_yunbao'; }
if((info.sdk_version && info.sdk_version <= '1.2.1') || info.sdk_version == '1.2.3') { info.action = 'show_yunbao'; }
else info = null;
}
if(info && line.indexOf('setting?h5Type=') >= 0 ) {
if(info.sdk_version && info.sdk_version <= '1.1.5') {
let pluginId = line.split('setting?h5Type=')[1].split('&')[0];
if(pluginId && pluginId.length) {
info.action = 'enter_plugin';
info.pluginId = parseInt(pluginId);
}
} else info = null;
}
if(info) {
/*await client.create({
index: 'xiaoyunssp',
id: Date.now() + '_' + Math.random().toString(36).substr(2) + '_' + info.action,
type: 'log',
body: info
});*/
if(info && info.osType) info.osType = info.osType.toString();
if(num <= count) {
console.dir('done' + count);
resolve({ count })
}
}
}
});
objReadline.on('close', ()=>{
console.dir('close done==============');
});
})
}
const sleep = function (ms){
return new Promise(resolve => setTimeout(resolve, ms))
}
const check = async (entry) => {
if(doing) {
console.log('执行中');
return;
} else {
if(entry.indexOf('.txt') >=0 || entry.indexOf('ui.') >=0 || entry.indexOf('.gz') == -1) {
console.log('格式错误');
return;
}
doing = true;
console.log('开始处理' + entry);
let rep = await parseFile(entry);
console.log('处理完成' + entry);
doing = false;
return rep;
}
}
const getInfo = async (entry) => {
const dirInfo = fs.readdirSync(entry);
for(let item of dirInfo) {
const location = path.join(entry,item);
const info = fs.statSync(location);
if(info.isDirectory()) {
await getInfo(location);
} else {
if(doing) {
break;
}
let rep = await check(location);
await child_process.execSync(`rm ${location}.txt`);
}
}
}
getInfo('20210415');
//exports.check = check;
\ No newline at end of file
const fs = require("fs");
const path = require('path');
const readline = require('readline');
const moment = require('moment');
const compressing = require('compressing');
const elasticsearch= require('elasticsearch');
const FileData = require('../db/mongo/file');
const RequestData = require('../db/mongo/requestdata');
const child_process = require('child_process');
const { ESHOST } = require('../config');
const client = new elasticsearch.Client({
host: ESHOST,
log: 'trace',
apiVersion: '7.x', // use the same version of your Elasticsearch instance
});
let doing = false;
function decodeNginxLog(c) {
let r = '';
for (let i = 0; i < c.length;) {
if (c[i] === '\\' && c[i + 1] === 'x') {
let j = i;
let hexList = [];
while(true) {
if (c[j] === '\\' && c[j + 1] === 'x') {
hexList.push(c[j + 2]);
hexList.push(c[j + 3]);
} else {
break;
}
j += 4;
}
r += Buffer.from(hexList.join(''), 'hex').toString('utf8');
i = j;
} else{
r += c[i];
i++;
}
}
return r;
}
async function decompress(fileName) {
return new Promise(function(resolve,reject) {
compressing.gzip.uncompress(fileName, `${fileName}.txt`)
.then(() => {
resolve(`${fileName}.txt`);
})
.catch(err => {
console.error(err);
reject(err);
});
})
}
function stringToBase64(str){
var base64Str = new Buffer(str).toString('base64');
return base64Str;
}
function base64ToString(base64Str){
var str = new Buffer(base64Str,'base64').toString();
return str;
}
async function parseFile(fileName) {
let count = 0;
let filedata = await FileData.findOne({ filename: fileName });
if(filedata) {
return null;
} else console.dir('parseFile 开始处理');
let fReadName = await decompress(fileName);
let id = await child_process.execSync('wc -l ' + fReadName + "| awk '{print $1}'");
let num = parseInt(id.toString().trim());
return new Promise(function(resolve,reject) {
const fRead = fs.createReadStream(fReadName);
const objReadline = readline.createInterface({
input: fRead
});
objReadline.on('line', async (line, linecount) => {
count++;
if(line.indexOf('/Log/logdata')>=0 || line.indexOf('setting?h5Type=')>=0 || line.indexOf('/plugin/config')>=0) {
let time_string = line.split("[")[1].split("]")[0].split(" ")[0];
let time = moment(time_string,'DD/MMM/YYYY:HH:mm:ss').format('x')
let info = decodeNginxLog(line).split('request_body:')[1].trim();
let data = {};
if(info.indexOf('resp_body') >= 0) info = info.split('resp_body')[0].trim();
if(info.indexOf('{') >=0) {
info = JSON.parse(info);
let data = {};
if(info.encryption) {
delete info.encryption;
for(let k in info) {
let key = base64ToString(k);
data[key] = base64ToString(decodeURIComponent(info[k]));
}
data['encryption'] = 1;
info = data;
}
if(info.deviceInfo && info.deviceInfo.indexOf('{') >=0) {
info.deviceInfo = JSON.parse(decodeURIComponent(info.deviceInfo));
}
} else info = null;
if(info && line.indexOf('/plugin/config') >= 0) {
if((info.sdk_version && info.sdk_version <= '1.2.1') || info.sdk_version == '1.2.3') { info.action = 'show_yunbao'; }
else info = null;
}
if(info && line.indexOf('setting?h5Type=') >= 0 ) {
if(info.sdk_version && info.sdk_version <= '1.1.5') {
let pluginId = line.split('setting?h5Type=')[1].split('&')[0];
if(pluginId && pluginId.length) {
info.action = 'enter_plugin';
info.pluginId = parseInt(pluginId);
}
} else info = null;
}
if(info) {
/*await client.create({
index: 'xiaoyunssp',
id: Date.now() + '_' + Math.random().toString(36).substr(2) + '_' + info.action,
type: 'log',
body: info
});*/
if(info.action == 'ad' && info.appId='52P455VrhbIVFIeaLS9DwL56XzMNPEAn')
fs.appendFile('./log.txt', JSON.stringify(info), (err) => {
if (err) throw err;
console.log('数据已被追加到文件');
});
console.dir(info);
let rep = await new RequestData({
nginxTime: time,
filename: fileName,
data: info
}).save();
if(num <= count) {
console.dir('done' + count);
resolve({ count })
}
}
}
});
objReadline.on('close', ()=>{
console.dir('close done==============');
});
})
}
const sleep = function (ms){
return new Promise(resolve => setTimeout(resolve, ms))
}
const check = async (entry) => {
if(doing) {
console.log('执行中');
return;
} else {
if(entry.indexOf('.txt') >=0 || entry.indexOf('ui.') >=0 || entry.indexOf('.gz') == -1) {
console.log('格式错误');
return;
}
doing = true;
console.log('开始处理' + entry);
let rep = await parseFile(entry);
console.log('处理完成' + entry);
doing = false;
return rep;
}
}
const getInfo = async (entry) => {
const dirInfo = fs.readdirSync(entry);
for(let item of dirInfo) {
const location = path.join(entry,item);
const info = fs.statSync(location);
if(info.isDirectory()) {
await getInfo(location);
} else {
if(doing) {
break;
}
let rep = await check(location);
if(rep) {
await new FileData({
filename: location,
lines: rep ? rep.count : 0
}).save();
await child_process.execSync(`rm ${location}.txt`);
console.dir("处理" + location)
} else { console.dir('没处理' + location) }
}
}
}
exports.getInfo = getInfo;
This diff is collapsed.
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
BROWSER=none
ESLINT=1
{
"extends": "eslint-config-umi"
}
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/npm-debug.log*
/yarn-error.log
/yarn.lock
/package-lock.json
# production
/dist
# misc
.DS_Store
# umi
.umi
.umi-production
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}
FROM node:9.11.1
WORKDIR /app
#ADD . /app/
ENV PORT=8787
ENV PROJECT_LEVEL=production
RUN \
rm /etc/localtime && \
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY package.json /app/
COPY . /app
ENV NODE_ENV='production'
EXPOSE 8787
CMD node index.js
\ No newline at end of file
FROM node:9.11.1
WORKDIR /app
#ADD . /app/
ENV PORT=8889
ENV MONGO_DB=mongodb://172.27.224.211:27017/xsb-dev?authSource=admin
ENV PROJECT_LEVEL=production
RUN \
rm /etc/localtime && \
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY package.json /app/
COPY . /app
ENV NODE_ENV='production'
EXPOSE 8889
CMD node index.js
\ No newline at end of file
image: clean
@echo "building docker image"
@docker build -t registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbao-data-api .
push:
@docker push registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbao-data-api
clean:
@echo "cleanning"
all:
@echo "building docker image"
@docker build -t registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbao-data-api .
@echo "生成docker镜像完成,准备上传"
@docker push registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbao-data-api
@echo "镜像更新完成"
alldev:
@echo "building docker image"
@docker build -t registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbao-data-api-dev . -f Dockerfile.dev
@echo "生成docker镜像完成,准备上传"
@docker push registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbao-data-api-dev
@echo "镜像更新完成"
\ No newline at end of file
This diff is collapsed.
const {
MONGO_DB = 'mongodb://localhost:27017/xiaoyunssp',
MONGO_LOG_DB = 'mongodb://localhost:27017/xiaoyunsspdev',
JWT_SECRET = '9104b291d48a4844d2a346a695d2602fa4d8ffe7328f7c98c27270b32a6b636f',
SQL_CONF = {
host: "localhost",
user:"lottery",//用户名
password:'KP6ZopZxIa9L0Lkp',//密码
database:"lottery",//数据库名
}
} = process.env;
module.exports = {
MONGO_DB: MONGO_DB.replace(/&/g, ','),
MONGO_LOG_DB: MONGO_LOG_DB.replace(/&/g, ','),
JWT_SECRET,
SQL_CONF
};
\ No newline at end of file
const config = process.env.NODE_ENV === 'production'
? require('./prod')
: require('./dev');
console.log('RUN as ', process.env.NODE_ENV === 'production' ? 'Production' : 'Development');
module.exports = config;
\ No newline at end of file
const {
MONGO_DB = 'mongodb://172.31.13.47:1301/xiaoyunssp',
MONGO_LOG_DB = 'mongodb://172.31.13.47:1301/xiaoyunsspdev',
//MONGO_DB = 'mongodb://172.27.224.211:27017/yunbaossp?authSource=admin',
JWT_SECRET = '9104b291d48a4844d2a346a695d2602fa4d8ffe7328f7c98c27270b32a6b636f',
SQL_CONF = {
host: "172.31.14.12",
user:"lottery",//用户名
password:'KP6ZopZxIa9L0Lkp',//密码
database:"lottery",//数据库名
}
} = process.env;
module.exports = {
MONGO_DB: MONGO_DB.replace(/&/g, ','),
MONGO_LOG_DB: MONGO_LOG_DB.replace(/&/g, ','),
JWT_SECRET,
SQL_CONF
};
\ No newline at end of file
This diff is collapsed.
function randomn(n) {
if (n > 21) return null
return parseInt((Math.random() + 1) * Math.pow(10,n-1))
}
const jwt = require('jsonwebtoken');
const config = require('config');
const hash = require('utils/hash');
const _ = require('lodash');
const mongoose = require('mongoose');
const Account = require('db/mongo/user');
const {
ObjectId
} = require('mongoose').Types;
function getToken(user, opt = {}) {
if (!opt.expiresIn) {
opt.expiresIn = '7d';
}
return jwt.sign(
user,
config.JWT_SECRET,
opt
);
}
/*(async function(argument) {
let a = await new Account({
username: 'admin',
password: hash('admin')
}).save();
console.dir(a);
})()*/
const RETURN_FIELDS = ['_id', 'code', 'username','role', 'createdAt'];
exports.checkPassword = async(ctx, next) => {
let {
username,
password
} = ctx.request.body;
let user = await Account.findOne({
username,
removed: { $ne: true }
});
console.dir(ctx.request.body);
ctx.assert(user, 404, '没有该用户', {
code: 1
});
user = user.toJSON();
console.dir(user.password)
ctx.assert(
hash(password) === user.password,
400,
'密码错误', {
code: 1
}
);
ctx.state.checkedAccount = user;
await next();
};
exports.whoAmI = async ctx => {
let myId = ctx.state.user._id;
let { username, phone, company, createdAt, updatedAt, role } = await Account.findById(myId);
ctx.body = {
status: 'ok',
data: {
username
}
};
};
exports.signin = async(ctx, next) => {
let {
username
} = ctx.request.body;
let user = await Account.findOne({
username
});
let token = getToken(_.pick(user, '_id', 'username'));
ctx.body = {
status: 'ok',
pid: user._id,
username,
role: user.role,
token
};
};
console.log('==============')
console.log(hash('1234567xx'))
const mongoose = require('mongoose');
const config = require('../config');
global.Promise = mongoose.Promise = require('bluebird');
const options = {
useMongoClient: true
};
exports.db = mongoose.createConnection(process.env.MONGO_DB || config.MONGO_DB, {});
exports.logDb = mongoose.createConnection(process.env.MONGO_LOG_DB || config.MONGO_LOG_DB, {});
console.log('MONGO CONNECT INFO: ', process.env.MONGO_DB || config.MONGO_DB);
console.log('MONGO_LOG_DB CONNECT INFO: ', process.env.MONGO_LOG_DB || config.MONGO_LOG_DB);
const mongoose = require('mongoose');
const connect = require('../connect');
const {
ObjectId
} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
date: String,
nginxTime: Number,
filename: String,
data: Object
}, {
timestamps: true
});
module.exports = connect.db.model('requestdata', schema);
\ No newline at end of file
const mongoose = require('mongoose');
const connect = require('../connect');
const {
ObjectId
} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
date: String,
osType: String,
type: String,
detail: Object,
sdk_version: String,
channel: String,
appId: String,
appName: String,
package_name: String,
app_name: String,
plugin_data: Object,
plugin_data_more: Object,
shop_data: Object
}, {
timestamps: true
});
module.exports = connect.db.model('stat', schema);
\ No newline at end of file
const mongoose = require('mongoose');
const connect = require('../connect');
const {
ObjectId
} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
username: {
type: String,
unique: true
},
name: String,
company: String,
phone: String,
password:{
type: String,
required: true
},
role: String,
notityUrl: String
}, {
timestamps: true
});
module.exports = connect.db.model('user', schema);
\ No newline at end of file
const mongoose = require('mongoose');
const connect = require('../connect');
const {
ObjectId
} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
data: Object
}, {
timestamps: true
});
module.exports = connect.logDb.model('cowrequestdata', schema);
\ No newline at end of file
const mongoose = require('mongoose');
const connect = require('../connect');
const {
ObjectId
} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
data: Object
}, {
timestamps: true
});
module.exports = connect.logDb.model('shoprequestdata', schema);
\ No newline at end of file
const mysql = require("mysql");
const config = require('../config');
const Promise = require('bluebird');
const pool = mysql.createPool(config.SQL_CONF);
module.exports = {
query(query_string) {
return new Promise(( resolve, reject ) => {
pool.getConnection(function(err, connection) {
if (err) {
reject( err )
} else {
connection.query(query_string, ( err, rows) => {
if ( err ) {
reject( err )
} else {
resolve( rows )
}
connection.release()
})
}
})
})
}
}
require('colors');
require('app-module-path/register');
const api = require('./utils/api');
const config = require('config');
const PassThrough = require('stream').PassThrough;
const Koa = require('koa');
const compress = require('koa-compress');
const cors = require('kcors');
const bodyParser = require('koa-bodyparser');
const logger = require('koa-logger');
const path = require('path');
const mongoose = require('mongoose');
const moment = require('moment');
const error = require('middleware/error');
const jwt = require('middleware/jwt');
const rp = require('request-promise');
const request = require('request');
const mountRoutes = require('utils/mount-routes');
const favicon = require('koa-favicon');
const fs = require('fs');
//const crypto = require('crypto');
const websockify = require('koa-websocket');
global.Promise = mongoose.Promise = require('bluebird');
const options = {
useMongoClient: true
};
const parse = require('co-body');
const router = require('koa-router')();
const app = new Koa();
const { MONGO_DB } = process.env;
/*mongoose.connect(MONGO_DB || config.MONGO_DB, {});
console.log('MONGO CONNECT INFO: ', MONGO_DB || config.MONGO_DB);*/
const opts = { threshold: 2048 };
app.use(cors());
app.use(compress(opts));
app.use(router.routes());
app.use(logger());
app.use(error());
app.use(require('koa-static')(__dirname + '/dist'))
app.use(jwt());
app.use(bodyParser({}));
app.use(mountRoutes().routes());
const { PORT = 8787 } = process.env;
app.listen(PORT, () => {
console.log(`server start at ${PORT}`);
});
console.dir(`当前运行环境${process.env.NODE_ENV}`);
process.on('unhandledRejection', (err, promise) => {
console.error('Unhandled rejection (promise: ', promise, ', reason: ', err, ').');
});
\ No newline at end of file
// const {merge} = require('lodash');
// const ERROR = {
// '10401': {
// status: {
// code: 10401,
// message: '密码错误'
// }
// },
// '10404': {
// status: {
// code: 10404,
// message: '没有该用户'
// }
// },
// '10422': {
// status: {
// code: 10422,
// message: '用户已存在'
// }
// },
// '11400': {
// status: {
// code: 11400,
// message: '参数不全'
// }
// },
// '11401': {
// status: {
// code: 11401,
// message: '操作权限不够'
// }
// },
// '11422': {
// status: {
// code: 11422,
// message: '用户名已存在'
// }
// },
// '20404': {
// status: {
// code: 20404,
// message: '没有该文章'
// }
// },
// '20403': {
// status: {
// code: 20403,
// message: '没有修改此文章的权限'
// }
// },
// '30404': {
// status: {
// code: 30404,
// message: '上游帐号不存在'
// }
// },
// '30422': {
// status: {
// code: 30422,
// message: '重复的平台帐号'
// }
// },
// '40404': {
// status: {
// code: 40404,
// message: '找不到该上游副本'
// }
// }
// };
module.exports = () => async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = err.status || 400;
ctx.body = {
status: {
code: err.code || 'unknow',
message: err.message || 'unknow'
}
};
}
// try {
// await next();
// } catch (err) {
// if (err.status === 401) {
// ctx.status = 401;
// ctx.body = {
// status: {
// code: 99401,
// message: '认证信息失效, 请重新登录'
// }
// };
// } else {
// if (process.env.NODE_ENV !== 'production' && !ERROR[err.message]) {
// console.error(err.message, '\n', err.stack);
// }
// ctx.status = ctx.status || 500;
// ctx.body = ERROR[err.message] || merge({
// status: {
// code: 99500,
// message: err.message || 'unknow error'
// }
// }, ctx.body);
// }
// }
};
const jwt = require('koa-jwt');
const config = require('config');
module.exports = (opt = {}) => {
return jwt({
secret: config.JWT_SECRET,
audience: opt.audience,
issuer: opt.issuer
}).unless({
path: [
'/',
'/api/user/signin'
]
});
};
\ No newline at end of file
{
"name": "scm-hmj",
"version": "1.0.0",
"main": "index.js",
"author": "liusong <liusong@xiaoyun.com>",
"license": "MIT",
"dependencies": {
"app-module-path": "^2.2.0",
"bluebird": "^3.7.2",
"co": "^4.6.0",
"colors": "^1.4.0",
"cron": "^1.8.2",
"kcors": "2",
"koa": "^2.0.1",
"koa-body": "^4.0.4",
"koa-bodyparser": "^4.2.1",
"koa-compress": "^2.0.0",
"koa-favicon": "^2.0.1",
"koa-jwt": "koa2",
"koa-logger": "^3.2.0",
"koa-multer": "^1.0.2",
"koa-mysql": "^1.0.3",
"koa-route": "^3.2.0",
"koa-router": "7.1.1",
"koa-static": "^5.0.0",
"koa-websocket": "^6.0.0",
"lodash": "^4.17.21",
"moment": "^2.17.1",
"mongoose": "^5.3.14",
"mysql": "^2.17.1",
"node-cache": "^5.1.2",
"node-xlsx": "^0.16.1",
"request": "^2.88.2",
"request-promise": "^4.2.6",
"simple-archiver": "^1.0.1"
}
}
const Router = require('koa-router');
const router = new Router();
const $ = require('controllers/stat');
router.post('/list', $.list);
router.post('/selects', $.selects);
module.exports = router;
\ No newline at end of file
const Router = require('koa-router');
const router = new Router();
const $ = require('controllers/user');
router.post('/signin', $.checkPassword, $.signin);
module.exports = router;
\ No newline at end of file
var crypto = require('crypto')
function WXBizDataCrypt(appId, sessionKey) {
this.appId = appId
this.sessionKey = sessionKey
}
WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
// base64 decode
var sessionKey = new Buffer(this.sessionKey, 'base64')
encryptedData = new Buffer(encryptedData, 'base64')
iv = new Buffer(iv, 'base64')
try {
// 解密
var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
// 设置自动 padding 为 true,删除填充补位
decipher.setAutoPadding(true)
var decoded = decipher.update(encryptedData, 'binary', 'utf8')
decoded += decipher.final('utf8')
decoded = JSON.parse(decoded)
} catch (err) {
throw new Error('Illegal Buffer')
}
if (decoded.watermark.appid !== this.appId) {
throw new Error('Illegal Buffer')
}
return decoded
}
module.exports = WXBizDataCrypt
const request = require('request');
module.exports = async (options) => {
return new Promise((resolve, reject) => {
request(options, function(err, result, body) {
if(err) reject(err)
else resolve(body);
})
})
}
\ No newline at end of file
const crypto = require('crypto');
module.exports = (str) => {
if (!str) return '';
return crypto.createHash('md5').update(str).digest('hex')
};
const fs = require('fs');
const path = require('path');
const Router = require('koa-router');
const router = new Router();
module.exports = (readPath) => {
const absoluteReadPath = getRoutesPath(readPath);
const routerMap = getRouerMap(absoluteReadPath);
routerMap.forEach(({route, filePath}, idx) => {
const m = require(filePath);
if (m.constructor.name !== 'Router') return;
router.use(route, m.routes());
if (idx === 0) {
log(`\n┏${Array(42).join('━')}${Array(83).join('━')}┓`.black);
} else {
log(`┣${Array(42).join('━')}${Array(83).join('━')}┫`.black);
}
log(
'┃'.black,
`${fixWidth(route)}`.green,
'┃'.black,
` ${fixWidth(filePath, 80)}`.blue,
'┃'.black
);
if (idx !== 0 && idx === routerMap.length - 1) {
log(`┗${Array(42).join('━')}${Array(83).join('━')}┛\n`.black);
}
});
return router;
};
function log (...arg) {
if (process.env.NODE_ENV !== 'production') {
console.log(...arg);
}
}
function getRoutesPath (readPath) {
if (!readPath) {
return path.resolve(
path.dirname(module.parent.filename),
'routes'
);
}
if (path.isAbsolute(readPath)) {
return readPath;
}
return path.resolve(
path.dirname(module.parent.filename),
readPath
);
}
function getRouerMap (r) {
const result = [];
function routerMap (readPath, prefix = '/') {
fs.readdirSync(readPath).forEach(cName => {
const absolutePath = path.resolve(readPath, cName);
const stat = fs.statSync(absolutePath);
if (stat.isDirectory()) {
routerMap(absolutePath, prefix + cName + '/');
}
if (!stat.isFile() || !cName.endsWith('.js')) return;
if (cName !== 'index.js') {
result.push({
route: prefix + cName.replace(/\.js$/, ''),
filePath: absolutePath
});
} else if (readPath !== __dirname) {
result.push({
route: prefix === '/' ? '/' : prefix.replace(/\/$/, ''),
filePath: absolutePath
});
}
});
}
routerMap(r);
return result;
}
function fixWidth (str, width = 40) {
const restNum = width - str.length;
if (restNum < 0) {
return str.substr(0, width - 1);
}
return str + Array(restNum).join(' ');
}
const async = require('async');
/**
*队列
* @param obj :obj对象 包含执行时间
* @param callback :回调函数
*/
const nodeQueue = async.queue(async function (obj, callback) {
setTimeout(async function () {
// 需要执行的代码的回调函数
if(typeof callback==='function'){
await callback();
}
}, obj.time)
}, 1)
// worker数量将用完时,会调用saturated函数
nodeQueue.saturated = function() {
console.log('all workers to be used');
}
// 当最后一个任务交给worker执行时,会调用empty函数
nodeQueue.empty = function() {
console.log('no more tasks wating');
}
// 当所有任务都执行完时,会调用drain函数
nodeQueue.drain = function() {
console.log('all tasks have been processed');
}
module.exports = nodeQueue;
\ No newline at end of file
const moment = require('moment');
const fs = require('fs');
module.exports = {
transDate: (items, key) => {
return items.map( x => {
x = x.toJSON ? x.toJSON() : x;
x[key || 'createdAt'] = moment(x[key || 'createdAt']).format('YYYY/MM/DD HH:mm');
return x;
})
},
generateDateQuery: (start, end, option) => {
if(/^[0-9]{8}$/.test(start) && /^[0-9]{8}$/.test(end)) {
let data = {};
if(option && option.type === 'string') {
data[option && option.key ? option.key : 'createdAt'] = { '$gte': start, '$lte': end };
} else {
data[option && option.key ? option.key : 'createdAt'] = { '$gte': moment(start,'YYYYMMDD').startOf('day').toDate(), '$lt': moment(end,'YYYYMMDD').endOf('day').toDate() };
}
return data;
}
else return {};
},
generateTokenCode: () => {
return Math.random().toString(36).substr(8);
},
getFixedNumber: (number) => {
return parseFloat(Number(number || 0).toFixed(2));
},
valid: (id) => {
return /^[0-9a-z]{24}$/.test(id);
},
allUndefined: (array) => {
let b = true
for(var k in array) {
b = b && (array[k] === undefined)
}
return b;
},
log: (content,file) => {
let to = file || 'public/log';
let time = moment().format('YYYYMMDD HH:mm:ss') + '~~';
fs.appendFile(to, 'At '+ time + content + '\n',function(){
console.log(content);
});
}
}
\ No newline at end of file
const inspect = require('util').inspect
const path = require('path')
const os = require('os')
const fs = require('fs')
const Busboy = require('busboy')
/**
* 同步创建文件目录
* @param {string} dirname 目录绝对地址
* @return {boolean} 创建目录结果
*/
function mkdirsSync( dirname ) {
if (fs.existsSync( dirname )) {
return true
} else {
if (mkdirsSync( path.dirname(dirname)) ) {
fs.mkdirSync( dirname )
return true
}
}
}
/**
* 获取上传文件的后缀名
* @param {string} fileName 获取上传文件的后缀名
* @return {string} 文件后缀名
*/
function getSuffixName( fileName ) {
let nameList = fileName.split('.')
return nameList[nameList.length - 1]
}
/**
* 上传文件
* @param {object} ctx koa上下文
* @param {object} options 文件上传参数 fileType文件类型, path文件存放路径
* @return {promise}
*/
function uploadFile( ctx, options) {
let req = ctx.req
let res = ctx.res
let busboy = new Busboy({headers: req.headers})
// 获取类型
let fileType = options.fileType || 'common'
let filePath = path.join( options.path, fileType)
let mkdirResult = mkdirsSync( filePath )
return new Promise((resolve, reject) => {
console.log('文件上传中...')
let result = {
success: false,
formData: {},
}
// 解析请求文件事件
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
let fileName = (options.fileName || Math.random().toString(16).substr(2)) + '.' + getSuffixName(filename);
result.fileName = fileName;
let _uploadFilePath = path.join( filePath, fileName )
let saveTo = path.join(_uploadFilePath)
// 文件保存到制定路径
file.pipe(fs.createWriteStream(saveTo))
// 文件写入事件结束
file.on('end', function() {
result.success = true
result.message = '文件上传成功'
console.log('文件上传成功!')
resolve(result)
})
})
// 解析表单中其他字段信息
busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
console.log('表单字段数据 [' + fieldname + ']: value: ' + inspect(val));
result.formData[fieldname] = inspect(val);
});
// 解析结束事件
busboy.on('finish', function( ) {
console.log('文件上结束')
resolve(result)
})
// 解析错误事件
busboy.on('error', function(err) {
console.log('文件上出错')
reject(result)
})
req.pipe(busboy)
})
}
module.exports = {
uploadFile
}
\ No newline at end of file
/**
* 不是真实的 webpack 配置,仅为兼容 webstorm 和 intellij idea 代码跳转
* ref: https://github.com/umijs/umi/issues/1109#issuecomment-423380125
*/
module.exports = {
resolve: {
alias: {
'@': require('path').resolve(__dirname, 'src'),
},
},
};
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/npm-debug.log*
/yarn-error.log
/yarn.lock
/package-lock.json
# production
/dist
# misc
.DS_Store
# umi
/src/.umi
/src/.umi-production
/src/.umi-test
/.env.local
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}
import { defineConfig } from 'umi';
export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
routes: [
{ path: '/login', component: '@/pages/login' },
{
path: '/',
component: '@/layouts/index',
routes: [
{ path: '/', component: '@/pages/index' },
{ path: '/stat', component: '@/pages/stat' }
]
},
],
fastRefresh: {},
plugins:[]
});
# umi project
## Getting Started
Install dependencies,
```bash
$ yarn
```
Start the dev server,
```bash
$ yarn start
```
{
"private": true,
"scripts": {
"start": "umi dev",
"build": "umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,less,md,json}": [
"prettier --write"
],
"*.ts?(x)": [
"prettier --parser=typescript --write"
]
},
"dependencies": {
"@ant-design/pro-layout": "^6.5.0",
"@umijs/preset-react": "1.x",
"echarts": "^5.0.2",
"echarts-for-react": "^3.0.1",
"umi": "^3.4.2"
},
"devDependencies": {
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@umijs/test": "^3.4.2",
"lint-staged": "^10.0.7",
"prettier": "^2.2.0",
"react": "17.x",
"react-dom": "17.x",
"typescript": "^4.1.2",
"yorkie": "^2.0.0"
}
}
import { getToken } from './local';
export default function(initialState) {
//const { userId, role } = initialState;
let token = getToken();
return {
token,
};
}
\ No newline at end of file
import HttpRequest from './request';
const host = 'http://yunbao-data-api.xiaoyunke.cn';
//const host = 'http://localhost:8787';
export default {
async sign(params: any): Promise<any> {
return HttpRequest({
method: 'post', // 如果是get方法可省
body: params, // 所有方法传参都通过body,没有省略即可
})(`${host}/api/user/signin`);
},
async getSelects(params: any): Promise<any> {
return HttpRequest({
method: 'post',
body: params,
}, true)(`${host}/api/stat/selects`);
},
async getStats(params: any): Promise<any> {
return HttpRequest({
method: 'post',
body: params,
}, true)(`${host}/api/stat/list`);
},
}
\ No newline at end of file
import { RequestConfig } from 'umi';
export async function getInitialState() {
return { a: 1 };
}
export const request: RequestConfig = {
timeout: 1000,
errorConfig: {},
middlewares: [],
requestInterceptors: [],
responseInterceptors: [],
};
html, body, #root {
height: 100%;
width: 100%;
margin: 0px auto;
background: #bfbfbf;
}
#root {
background: #fff;
overflow: auto;
}
a{
color: #555;
}
body {
margin: 0;
}
a{
text-decoration: none;
}
.container{
background: #fff;
max-height: 100%;
overflow: auto;
}
.box{
height: 100%;
}
.flex{
display: flex;
}
.c{
flex-direction: column;
}
.r{
flex-direction: row;
}
.trigger {
padding: 0 24px;
font-size: 18px;
line-height: 64px;
cursor: pointer;
transition: color 0.3s;
}
.trigger:hover {
color: #1890ff;
}
.logo {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.3);
}
.site-layout .layout-back {
background: #fff;
}
.chart{
margin: 20px 0px;
}
\ No newline at end of file
import React, { useState, useEffect, useRef } from 'react';
import styles from './index.less';
import { useAccess } from 'umi';
import { Button, Form, Card, Input, Layout, Menu } from 'antd';
import { setToken, delToken, setUserName, delUserName, getUserName } from '../local';
import {
MenuUnfoldOutlined,
MenuFoldOutlined,
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
DatabaseOutlined,
FundOutlined,
SettingOutlined,
LogoutOutlined
} from '@ant-design/icons';
const { Header, Sider, Content } = Layout;
import * as fn from '../api';
const { sign } = fn.default;
const menus = ['/','/stat'];
const BasicLayout: React.FC = props => {
const access = useAccess();
if(!access.token) {
delToken();
delUserName();
console.dir('=========')
if(props.location.pathname !== '/login') return window.location.href = '/login';
}
const [collapsed,setCollapsed] = useState(false);
const [key,setKey] = useState([menus.indexOf(props.location.pathname).toString()]);
const username = getUserName()
const toggle = () => {
setCollapsed(!collapsed);
};
const handleClick = (e) => {
window.location.href = menus[e.key];
};
const logout = (e) => {
delToken();
setTimeout( x => {
window.location.reload();
},500);
}
return (
<div style={{ height: '100%', width: '100%' }}>
<Layout className="box">
<Sider trigger={null} collapsible collapsed={collapsed}>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={key} onClick={handleClick}>
<Menu.Item key="0" icon={<FundOutlined />}>
广告数据
</Menu.Item>
<Menu.Item key="1" icon={<SettingOutlined />}>
权限设置
</Menu.Item>
</Menu>
</Sider>
<Layout className="site-layout">
<Header className="layout-back" style={{ padding: 0,justifyContent: 'space-between', display: 'flex' }}>
{React.createElement(collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
className: 'trigger',
onClick: toggle,
})}
<div>
<span>欢迎你,{
username
}</span>
{React.createElement(LogoutOutlined, {
className: 'trigger',
onClick: logout,
})}
</div>
</Header>
<Content
className="layout-back"
style={{
margin: '24px 16px',
padding: 24,
minHeight: 280,
}}
>
{props.children}
</Content>
</Layout>
</Layout>
</div>
);
};
export default BasicLayout;
// 获取本地保存的用户名
export function getUserName (){
return localStorage.getItem('username') || ''
}
// 设置本地保存的用户名
export function setUserName (name){
return localStorage.setItem('username', name);
}
export function setRole(name) {
return localStorage.setItem('role', name);
}
export function getRole(name) {
return localStorage.getItem('role', name);
}
// 删除本地保存的用户名
export function delUserName (){
return localStorage.removeItem('username');
}
// 获取是否保存帐号标示
export function getToken (){
return localStorage.getItem('token');
}
// 设置本地保存的用户名
export function setToken (token){
return localStorage.setItem('token', token);
}
// 删除本地保存的用户名
export function delToken (){
return localStorage.removeItem('token');
}
\ No newline at end of file
.title {
background: rgb(121, 242, 157);
}
This diff is collapsed.
import React, { useState, useEffect, useRef } from 'react';
import styles from './index.less';
import { Button, Form, Card, Input } from 'antd';
import { setToken, delToken, setUserName, delUserName, getUserName } from '../local';
import * as fn from '../api';
const { sign } = fn.default;
const tailLayout = {
wrapperCol: { offset: 5, span: 19 },
};
const layout = {
labelCol: { span: 5 },
wrapperCol: { span: 19 },
};
export default function LoginPage() {
const onFinish = async (values: any) => {
console.log('Success:', values);
let a = await sign(values);
console.dir(a);
setUserName(a.username);
setToken('Bearer ' + a.token);
return window.location.href = '/';
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
return (
<div className="box">
<div className = 'flex c' style={{ height: '100%', background: '#001529' }} >
<Card
className = { 'm' }
title = { '运营管理系统' }
extra = { <span>登录</span> }
style = {{ width:400,margin:'auto' }}
>
<Form
{...layout}
name="basic"
onFinish={onFinish}
onFinishFailed={onFinishFailed}
>
<Form.Item
label="用户名"
name="username"
rules={[{ required: true, message: '请输入账号' }]}
>
<Input />
</Form.Item>
<Form.Item
label="密码"
name="password"
rules={[{ required: true, message: '请输入密码!' }]}
>
<Input.Password />
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">
提交
</Button>
</Form.Item>
</Form>
</Card>
</div>
</div>
);
}
import React, { useState, useEffect, useRef } from 'react';
import styles from './index.less';
import ReactECharts from 'echarts-for-react';
import { Button, Form, Card, Input, Layout, Menu, Select, DatePicker, Table, Radio } from 'antd';
import { setToken, delToken, setUserName, delUserName, getUserName } from '../local';
import moment from 'moment';
import {
MenuUnfoldOutlined,
MenuFoldOutlined,
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
DatabaseOutlined,
FundOutlined
} from '@ant-design/icons';
import * as fn from '../api';
const { getSelects, getStats } = fn.default;
const { Header, Sider, Content } = Layout;
const { Option } = Select;
const { RangePicker } = DatePicker;
const dateFormat = 'YYYYMMDD';
export default function IndexPage(props) {
const toggle = () => {
setCollapsed(!collapsed);
};
async function init() {
let result = await getSelects();
console.dir(result);
}
useEffect(() => {
init();
}, [])
return (
<div className="container">
开发中
</div>
);
}
import { extend } from 'umi-request';
import { notification, message } from 'antd';
import _omit from 'lodash/omit';
import { getToken } from './local';
/*const codeMessage = {
200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。',
202: '一个请求已经进入后台排队(异步任务)。',
204: '删除数据成功。',
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
401: '用户没有权限(令牌、用户名、密码错误)。',
403: '用户得到授权,但是访问是被禁止的。',
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
406: '请求的格式不可得。',
410: '请求的资源被永久删除,且不会再得到的。',
422: '当创建一个对象时,发生一个验证错误。',
500: '服务器发生错误,请检查服务器。',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。',
};
const errorHandler = (error: { response: Response }): Response => {
const { response } = error;
if (response && response.status) {
const errorText = codeMessage[response.status] || response.statusText;
const { status, url } = response;
notification.error({
message: `请求错误 ${status}`,
description: errorText,
});
} else if (!response) {
notification.error({
description: '您的网络发生异常,无法连接服务器',
message: '网络异常',
});
}
return response;
};*/
const authorization = (noAuth?: boolean) => {
const AuthorizationToken = getToken();
console.dir(AuthorizationToken);
return AuthorizationToken;
};
/**
* @param noAuth
* 是否带token请求
*
* @param credential
* 默认请求是否带上cookie
* include 携带
* omit 不携带
*/
const HttpRequest = (option?:any, noAuth?: boolean, credential?: 'include' | 'omit') => {
let newOption = {...option}
if(newOption.method === 'post' || newOption.method === 'delete' || newOption.method === 'put') {
// params --> 会被放到body的请求参数,POST/PUT/DELETE 方法
newOption.data = newOption.body
}else {
// params --> 会被拼接到url上的的请求参数,GET方法
newOption.params = newOption.body
}
if(newOption.body) {
// 为了保证调用的一致性,外部都通过自定义的body传递参数,但body是关键字需要手动清除
newOption = _omit(newOption, 'body')
}
const request = extend({
errorHandler: null, // 默认错误处理
timeout: 15000,
credentials: credential || 'omit',
...newOption,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
Authorization: authorization(noAuth),
}
})
// 添加拦截器统一处理返回response
request.interceptors.response.use(async response => {
const data = await response.clone().json()
if(data.status !== 200 && data.status.message){
message.error(data.status.message)
}
return response;
});
return request
};
export default HttpRequest;
\ No newline at end of file
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"jsx": "react-jsx",
"esModuleInterop": true,
"sourceMap": true,
"baseUrl": "./",
"strict": true,
"paths": {
"@/*": ["src/*"],
"@@/*": ["src/.umi/*"]
},
"allowSyntheticDefaultImports": true
},
"include": [
"mock/**/*",
"src/**/*",
"config/**/*",
".umirc.ts",
"typings.d.ts"
],
"exclude": [
"node_modules",
"lib",
"es",
"dist",
"typings",
"**/__test__",
"test",
"docs",
"tests"
]
}
declare module '*.css';
declare module '*.less';
declare module '*.png';
declare module '*.svg' {
export function ReactComponent(props: React.SVGProps<SVGSVGElement>): React.ReactElement
const url: string
export default url
}
FROM node:9.11.1
WORKDIR /app
#ADD . /app/
ENV PORT=8786
ENV PROJECT_LEVEL=production
ENV NODE_ENV=production
RUN \
rm /etc/localtime && \
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY package.json /app/
COPY . /app
EXPOSE 8786
CMD node index.js
\ No newline at end of file
image: clean
@echo "building docker image"
@docker build -t registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbaodata .
push:
@docker push registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbaodata
clean:
@echo "cleanning"
all:
@echo "打包文件"
@cd '../app' && yarn build
@echo "打包文件完成,文件替换中"
@rm -rf './dist'
@mv '../app/dist' '.'
@echo "building docker image"
@echo "文件替换完成,生成docker镜像"
@docker build -t registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbaodata .
@echo "生成docker镜像完成,准备上传"
@docker push registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbaodata
@echo "镜像更新完成"
alldev:
@echo "打包文件"
@cd '../app' && yarn build
@echo "打包文件完成,文件替换中"
@rm -rf './dist'
@mv '../app/dist' '.'
@cd './dist' && sed -i "" s/yz-api.qyyz.ltd/yz-api-dev.qyyz.ltd/g `grep yz-api.qyyz.ltd -rl --include="*.js" .`
@echo "building docker image"
@echo "文件替换完成,生成docker镜像"
@docker build -t registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbaodata-dev . -f Dockerfile.dev
@echo "生成docker镜像完成,准备上传"
@docker push registry.cn-hangzhou.aliyuncs.com/wjh-reg/yunbaodata-dev
@echo "镜像更新完成"
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<link rel="stylesheet" href="/umi.css" />
<script>
window.routerBase = "/";
</script>
<script>
//! umi version: 3.4.2
</script>
</head>
<body>
<div id="root"></div>
<script src="/umi.js"></script>
</body>
</html>
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
const express = require('express');
const path = require('path');
const send = require('send');
const parseUrl = require('parseurl')
const bodyParser = require('body-parser')
const app = express();
const port = 8786;
const pagePaths = ['','/','/stat','/login']
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
// 页面渲染
app.get('/umi.css',(req,res) => {
let stream = send(req, path.join(__dirname, './dist/umi.css'), {});
stream.pipe(res);
});
app.get('/umi.js',(req,res) => {
let stream = send(req, path.join(__dirname, './dist/umi.js'), {});
stream.pipe(res);
});
app.use((req, res, next) => {
console.dir(req.url)
let dir = (req.hostname || '').split('.')[0];
let originalUrl = parseUrl.original(req);
let _path = parseUrl(req).pathname
if (_path === '/' && originalUrl.pathname.substr(-1) !== '/') {
_path = ''
}
if(pagePaths.indexOf(_path) >= 0) {
let stream = send(req, path.join(__dirname, './dist/index.html'), {});
stream.pipe(res);
} else next();
});
app.listen(port, () => console.log(`index page app listening on port ${port}!`))
\ No newline at end of file
This diff is collapsed.
{
"name": "yunbao-server",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1",
"parseurl": "^1.3.3"
}
}
Arguments:
/usr/local/bin/node /usr/local/Cellar/yarn/1.22.4/libexec/bin/yarn.js add express body-parser parseUrl --save
PATH:
/usr/local/opt/scala@2.11/bin:/usr/local/sbin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:/usr/local/hive/bin:/Users/liusong/desktop/hadoop-2.7.7/bin
Yarn version:
1.22.4
Node version:
14.5.0
Platform:
darwin x64
Trace:
Error: https://registry.npm.taobao.org/parseUrl: Not found
at Request.params.callback [as _callback] (/usr/local/Cellar/yarn/1.22.4/libexec/lib/cli.js:66987:18)
at Request.self.callback (/usr/local/Cellar/yarn/1.22.4/libexec/lib/cli.js:140748:22)
at Request.emit (events.js:314:20)
at Request.<anonymous> (/usr/local/Cellar/yarn/1.22.4/libexec/lib/cli.js:141720:10)
at Request.emit (events.js:314:20)
at IncomingMessage.<anonymous> (/usr/local/Cellar/yarn/1.22.4/libexec/lib/cli.js:141642:12)
at Object.onceWrapper (events.js:420:28)
at IncomingMessage.emit (events.js:326:22)
at endReadableNT (_stream_readable.js:1226:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
npm manifest:
{
"name": "yunbao-server",
"version": "1.0.0",
"main": "index.js",
"license": "MIT"
}
yarn manifest:
No manifest
Lockfile:
No lockfile
This diff is collapsed.
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