mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-22 22:36:06 +08:00
初始化api
This commit is contained in:
parent
f1f8ece8a2
commit
99a8dc78db
8
.env.example
Normal file
8
.env.example
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
MONGODB_URI='mongodb://'
|
||||||
|
YIYAN_MONGODB_URI=''
|
||||||
|
|
||||||
|
PORT=8080
|
||||||
|
|
||||||
|
LOG_LEVEL='debug'
|
||||||
|
|
||||||
|
SECRET='test'
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -19,3 +19,4 @@
|
||||||
/src/.umi-test
|
/src/.umi-test
|
||||||
/.env.local
|
/.env.local
|
||||||
/config
|
/config
|
||||||
|
.env
|
42
back/api/auth.ts
Normal file
42
back/api/auth.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
|
import { Container } from 'typedi';
|
||||||
|
import { Logger } from 'winston';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import config from '../config';
|
||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
const route = Router();
|
||||||
|
|
||||||
|
export default (app: Router) => {
|
||||||
|
app.use('/', route);
|
||||||
|
route.post(
|
||||||
|
'/auth',
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
let username = req.body.username;
|
||||||
|
let password = req.body.password;
|
||||||
|
fs.readFile(config.authConfigFile, 'utf8', function (err, data) {
|
||||||
|
if (err) console.log(err);
|
||||||
|
var con = JSON.parse(data);
|
||||||
|
if (username && password) {
|
||||||
|
if (username == con.user && password == con.password) {
|
||||||
|
let token = jwt.sign(
|
||||||
|
{ username, password },
|
||||||
|
config.secret as any,
|
||||||
|
{ expiresIn: 60 * 60 * 24 * 7, algorithm: 'HS384' },
|
||||||
|
);
|
||||||
|
res.send({ err: 0, token });
|
||||||
|
} else {
|
||||||
|
res.send({ err: 1, msg: config.authError });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.send({ err: 1, msg: '请输入用户名密码!' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
70
back/api/config.ts
Normal file
70
back/api/config.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
|
import { Container } from 'typedi';
|
||||||
|
import { Logger } from 'winston';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import config from '../config';
|
||||||
|
const route = Router();
|
||||||
|
|
||||||
|
export default (app: Router) => {
|
||||||
|
app.use('/', route);
|
||||||
|
route.get(
|
||||||
|
'/config/:key',
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
let content = '未找到文件';
|
||||||
|
switch (req.params.key) {
|
||||||
|
case 'config':
|
||||||
|
content = getFileContentByName(config.confFile);
|
||||||
|
break;
|
||||||
|
case 'sample':
|
||||||
|
content = getFileContentByName(config.sampleFile);
|
||||||
|
break;
|
||||||
|
case 'crontab':
|
||||||
|
content = getFileContentByName(config.crontabFile);
|
||||||
|
break;
|
||||||
|
case 'shareCode':
|
||||||
|
let shareCodeFile = getLastModifyFilePath(config.shareCodeDir);
|
||||||
|
content = getFileContentByName(shareCodeFile);
|
||||||
|
break;
|
||||||
|
case 'diy':
|
||||||
|
content = getFileContentByName(config.diyFile);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res.send({ code: 200, content });
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function getFileContentByName(fileName) {
|
||||||
|
if (fs.existsSync(fileName)) {
|
||||||
|
return fs.readFileSync(fileName, 'utf8');
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
function getLastModifyFilePath(dir) {
|
||||||
|
var filePath = '';
|
||||||
|
|
||||||
|
if (fs.existsSync(dir)) {
|
||||||
|
var lastmtime = 0;
|
||||||
|
|
||||||
|
var arr = fs.readdirSync(dir);
|
||||||
|
|
||||||
|
arr.forEach(function (item) {
|
||||||
|
var fullpath = path.join(dir, item);
|
||||||
|
var stats = fs.statSync(fullpath);
|
||||||
|
if (stats.isFile()) {
|
||||||
|
if (stats.mtimeMs >= lastmtime) {
|
||||||
|
filePath = fullpath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return filePath;
|
||||||
|
}
|
28
back/api/cookie.ts
Normal file
28
back/api/cookie.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
|
import { Container } from 'typedi';
|
||||||
|
import CookieService from '../services/cookie';
|
||||||
|
import { celebrate, Joi } from 'celebrate';
|
||||||
|
import { Logger } from 'winston';
|
||||||
|
const route = Router();
|
||||||
|
|
||||||
|
export default (app: Router) => {
|
||||||
|
app.use('/', route);
|
||||||
|
route.get(
|
||||||
|
'/qrcode',
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
if (req) {
|
||||||
|
const cookieService = Container.get(CookieService);
|
||||||
|
const { shici } = await cookieService.getYiYan();
|
||||||
|
return res.status(200).json({ code: 200, data: shici });
|
||||||
|
} else {
|
||||||
|
return res.status(200).json({ err: 1, msg: 'loginFaild' });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
12
back/api/index.ts
Normal file
12
back/api/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { Router } from 'express';
|
||||||
|
import auth from './auth';
|
||||||
|
import cookie from './cookie';
|
||||||
|
import config from './config';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const app = Router();
|
||||||
|
auth(app);
|
||||||
|
cookie(app);
|
||||||
|
config(app);
|
||||||
|
return app;
|
||||||
|
};
|
28
back/app.ts
Normal file
28
back/app.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import 'reflect-metadata'; // We need this in order to use @Decorators
|
||||||
|
|
||||||
|
import config from './config';
|
||||||
|
|
||||||
|
import express from 'express';
|
||||||
|
|
||||||
|
import Logger from './loaders/logger';
|
||||||
|
|
||||||
|
async function startServer() {
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
await require('./loaders').default({ expressApp: app });
|
||||||
|
|
||||||
|
app
|
||||||
|
.listen(config.port, () => {
|
||||||
|
Logger.info(`
|
||||||
|
################################################
|
||||||
|
🛡️ Server listening on port: ${config.port} 🛡️
|
||||||
|
################################################
|
||||||
|
`);
|
||||||
|
})
|
||||||
|
.on('error', (err) => {
|
||||||
|
Logger.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
startServer();
|
44
back/config/index.ts
Normal file
44
back/config/index.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
|
const envFound = dotenv.config();
|
||||||
|
const rootPath = path.resolve(__dirname, '../../');
|
||||||
|
const confFile = path.join(rootPath, 'config/config.sh');
|
||||||
|
const sampleFile = path.join(rootPath, 'sample/config.sh.sample');
|
||||||
|
const crontabFile = path.join(rootPath, 'config/crontab.list');
|
||||||
|
const confBakDir = path.join(rootPath, 'config/bak/');
|
||||||
|
const authConfigFile = path.join(rootPath, 'config/auth.json');
|
||||||
|
const shareCodeDir = path.join(rootPath, 'log/jd_get_share_code/');
|
||||||
|
const diyFile = path.join(rootPath, 'config/diy.sh');
|
||||||
|
const logPath = path.join(rootPath, 'log/');
|
||||||
|
const authError = '错误的用户名密码,请重试';
|
||||||
|
const loginFaild = '请先登录!';
|
||||||
|
const configString = 'config sample crontab shareCode diy';
|
||||||
|
|
||||||
|
if (envFound.error) {
|
||||||
|
throw new Error("⚠️ Couldn't find .env file ⚠️");
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
port: parseInt(process.env.PORT, 10),
|
||||||
|
secret: process.env.SECRET,
|
||||||
|
logs: {
|
||||||
|
level: process.env.LOG_LEVEL || 'silly',
|
||||||
|
},
|
||||||
|
api: {
|
||||||
|
prefix: '/api',
|
||||||
|
},
|
||||||
|
configString,
|
||||||
|
loginFaild,
|
||||||
|
authError,
|
||||||
|
logPath,
|
||||||
|
diyFile,
|
||||||
|
shareCodeDir,
|
||||||
|
authConfigFile,
|
||||||
|
confBakDir,
|
||||||
|
crontabFile,
|
||||||
|
sampleFile,
|
||||||
|
confFile,
|
||||||
|
};
|
27
back/interfaces/ICommon.ts
Normal file
27
back/interfaces/ICommon.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
export interface ICommon {
|
||||||
|
_id: string;
|
||||||
|
value: String;
|
||||||
|
name: String;
|
||||||
|
type: Number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICommonInputDTO {
|
||||||
|
value: String;
|
||||||
|
name: String;
|
||||||
|
type: Number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ShareCodeType {
|
||||||
|
ddFactory = 1,
|
||||||
|
ddXw,
|
||||||
|
jxCfd,
|
||||||
|
jxFactory,
|
||||||
|
jxFactoryTuan,
|
||||||
|
jxNc,
|
||||||
|
jxStory,
|
||||||
|
jxCfdGroup,
|
||||||
|
jdZz,
|
||||||
|
jdZjdTuan,
|
||||||
|
didi,
|
||||||
|
jd818,
|
||||||
|
}
|
7
back/interfaces/IContent.ts
Normal file
7
back/interfaces/IContent.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export interface IContent {
|
||||||
|
author: String;
|
||||||
|
paragraphs: [String];
|
||||||
|
title: String;
|
||||||
|
id: String;
|
||||||
|
created_at: Number;
|
||||||
|
}
|
15
back/loaders/dependencyInjector.ts
Normal file
15
back/loaders/dependencyInjector.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { Container } from 'typedi';
|
||||||
|
import LoggerInstance from './logger';
|
||||||
|
|
||||||
|
export default ({ models }: { models: { name: string; model: any }[] }) => {
|
||||||
|
try {
|
||||||
|
models.forEach((m) => {
|
||||||
|
Container.set(m.name, m.model);
|
||||||
|
});
|
||||||
|
|
||||||
|
Container.set('logger', LoggerInstance);
|
||||||
|
} catch (e) {
|
||||||
|
LoggerInstance.error('🔥 Error on dependency injector loader: %o', e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
55
back/loaders/express.ts
Normal file
55
back/loaders/express.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import { Request, Response, NextFunction, Application } from 'express';
|
||||||
|
import bodyParser from 'body-parser';
|
||||||
|
import cors from 'cors';
|
||||||
|
import routes from '../api';
|
||||||
|
import config from '../config';
|
||||||
|
import jwt from 'express-jwt';
|
||||||
|
|
||||||
|
export default ({ app }: { app: Application }) => {
|
||||||
|
app.enable('trust proxy');
|
||||||
|
app.use(cors());
|
||||||
|
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
app.use(
|
||||||
|
jwt({ secret: config.secret as string, algorithms: ['HS384'] }).unless({
|
||||||
|
path: ['/api/auth'],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
app.use(config.api.prefix, routes());
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
const err: any = new Error('Not Found');
|
||||||
|
err['status'] = 404;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
(
|
||||||
|
err: Error & { status: number },
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction,
|
||||||
|
) => {
|
||||||
|
if (err.name === 'UnauthorizedError') {
|
||||||
|
return res.status(err.status).send({ message: err.message }).end();
|
||||||
|
}
|
||||||
|
return next(err);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
(
|
||||||
|
err: Error & { status: number },
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction,
|
||||||
|
) => {
|
||||||
|
res.status(err.status || 500);
|
||||||
|
res.json({
|
||||||
|
errors: {
|
||||||
|
message: err.message,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
15
back/loaders/index.ts
Normal file
15
back/loaders/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import expressLoader from './express';
|
||||||
|
import dependencyInjectorLoader from './dependencyInjector';
|
||||||
|
import Logger from './logger';
|
||||||
|
|
||||||
|
export default async ({ expressApp }) => {
|
||||||
|
Logger.info('✌️ DB loaded and connected!');
|
||||||
|
|
||||||
|
await dependencyInjectorLoader({
|
||||||
|
models: [],
|
||||||
|
});
|
||||||
|
Logger.info('✌️ Dependency Injector loaded');
|
||||||
|
|
||||||
|
await expressLoader({ app: expressApp });
|
||||||
|
Logger.info('✌️ Express loaded');
|
||||||
|
};
|
32
back/loaders/logger.ts
Normal file
32
back/loaders/logger.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import winston from 'winston';
|
||||||
|
import config from '../config';
|
||||||
|
|
||||||
|
const transports = [];
|
||||||
|
if (process.env.NODE_ENV !== 'development') {
|
||||||
|
transports.push(new winston.transports.Console());
|
||||||
|
} else {
|
||||||
|
transports.push(
|
||||||
|
new winston.transports.Console({
|
||||||
|
format: winston.format.combine(
|
||||||
|
winston.format.cli(),
|
||||||
|
winston.format.splat(),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LoggerInstance = winston.createLogger({
|
||||||
|
level: config.logs.level,
|
||||||
|
levels: winston.config.npm.levels,
|
||||||
|
format: winston.format.combine(
|
||||||
|
winston.format.timestamp({
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
}),
|
||||||
|
winston.format.errors({ stack: true }),
|
||||||
|
winston.format.splat(),
|
||||||
|
winston.format.json(),
|
||||||
|
),
|
||||||
|
transports,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default LoggerInstance;
|
125
back/services/cookie.ts
Normal file
125
back/services/cookie.ts
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
import { Service, Inject } from 'typedi';
|
||||||
|
import winston from 'winston';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class CookieService {
|
||||||
|
private cookies: string = '';
|
||||||
|
private s_token: string = '';
|
||||||
|
private guid: string = '';
|
||||||
|
private lsid: string = '';
|
||||||
|
private lstoken: string = '';
|
||||||
|
private okl_token: string = '';
|
||||||
|
private token: string = '';
|
||||||
|
constructor(@Inject('logger') private logger: winston.Logger) {}
|
||||||
|
|
||||||
|
public async getYiYan(): Promise<any> {
|
||||||
|
return { yiYan: 'test' };
|
||||||
|
}
|
||||||
|
|
||||||
|
private async step1() {
|
||||||
|
try {
|
||||||
|
let timeStamp = new Date().getTime();
|
||||||
|
let url =
|
||||||
|
'https://plogin.m.jd.com/cgi-bin/mm/new_login_entrance?lang=chs&appid=300&returnurl=https://wq.jd.com/passport/LoginRedirect?state=' +
|
||||||
|
timeStamp +
|
||||||
|
'&returnurl=https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport';
|
||||||
|
const text = await fetch(url, {
|
||||||
|
method: 'get',
|
||||||
|
headers: {
|
||||||
|
Connection: 'Keep-Alive',
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
Accept: 'application/json, text/plain, */*',
|
||||||
|
'Accept-Language': 'zh-cn',
|
||||||
|
Referer:
|
||||||
|
'https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wq.jd.com/passport/LoginRedirect?state=' +
|
||||||
|
timeStamp +
|
||||||
|
'&returnurl=https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport',
|
||||||
|
'User-Agent':
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
|
||||||
|
Host: 'plogin.m.jd.com',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.praseSetCookies(text);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(error.response.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async step2() {
|
||||||
|
try {
|
||||||
|
if (this.cookies == '') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let timeStamp = new Date().getTime();
|
||||||
|
let url =
|
||||||
|
'https://plogin.m.jd.com/cgi-bin/m/tmauthreflogurl?s_token=' +
|
||||||
|
this.s_token +
|
||||||
|
'&v=' +
|
||||||
|
timeStamp +
|
||||||
|
'&remember=true';
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'post',
|
||||||
|
body: JSON.stringify({
|
||||||
|
lang: 'chs',
|
||||||
|
appid: 300,
|
||||||
|
returnurl:
|
||||||
|
'https://wqlogin2.jd.com/passport/LoginRedirect?state=' +
|
||||||
|
timeStamp +
|
||||||
|
'&returnurl=//home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action',
|
||||||
|
source: 'wq_passport',
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
Connection: 'Keep-Alive',
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded; Charset=UTF-8',
|
||||||
|
Accept: 'application/json, text/plain, */*',
|
||||||
|
Cookie: this.cookies,
|
||||||
|
Referer:
|
||||||
|
'https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wqlogin2.jd.com/passport/LoginRedirect?state=' +
|
||||||
|
timeStamp +
|
||||||
|
'&returnurl=//home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport',
|
||||||
|
'User-Agent':
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
|
||||||
|
Host: 'plogin.m.jd.com',
|
||||||
|
},
|
||||||
|
}).then((res) => res.json);
|
||||||
|
// this.token = response.body.token
|
||||||
|
// this.okl_token = response.headers['set-cookie'][0]
|
||||||
|
// this.okl_token = this.okl_token.substring(this.okl_token.indexOf("=") + 1, this.okl_token.indexOf(";"))
|
||||||
|
var qrUrl =
|
||||||
|
'https://plogin.m.jd.com/cgi-bin/m/tmauth?appid=300&client_type=m&token=' +
|
||||||
|
this.token;
|
||||||
|
return qrUrl;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error.response.body);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private praseSetCookies(response: any) {
|
||||||
|
this.s_token = response.body.s_token;
|
||||||
|
this.guid = response.headers['set-cookie'][0];
|
||||||
|
this.guid = this.guid.substring(
|
||||||
|
this.guid.indexOf('=') + 1,
|
||||||
|
this.guid.indexOf(';'),
|
||||||
|
);
|
||||||
|
this.lsid = response.headers['set-cookie'][2];
|
||||||
|
this.lsid = this.lsid.substring(
|
||||||
|
this.lsid.indexOf('=') + 1,
|
||||||
|
this.lsid.indexOf(';'),
|
||||||
|
);
|
||||||
|
this.lstoken = response.headers['set-cookie'][3];
|
||||||
|
this.lstoken = this.lstoken.substring(
|
||||||
|
this.lstoken.indexOf('=') + 1,
|
||||||
|
this.lstoken.indexOf(';'),
|
||||||
|
);
|
||||||
|
this.cookies =
|
||||||
|
'guid=' +
|
||||||
|
this.guid +
|
||||||
|
'; lang=chs; lsid=' +
|
||||||
|
this.lsid +
|
||||||
|
'; lstoken=' +
|
||||||
|
this.lstoken +
|
||||||
|
'; ';
|
||||||
|
}
|
||||||
|
}
|
9
back/types/express/index.d.ts
vendored
Normal file
9
back/types/express/index.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { Document, Model } from 'mongoose';
|
||||||
|
import { IContent } from '../../interfaces/IContent';
|
||||||
|
import { ICommon } from '../../interfaces/ICommon';
|
||||||
|
declare global {
|
||||||
|
namespace Models {
|
||||||
|
export type IContentModel = Model<IContent & Document>;
|
||||||
|
export type ICommonModel = Model<ICommon & Document>;
|
||||||
|
}
|
||||||
|
}
|
6
nodemon.json
Normal file
6
nodemon.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"watch": ["back", ".env"],
|
||||||
|
"ext": "js,ts,json",
|
||||||
|
"ignore": ["src/**/*.spec.ts"],
|
||||||
|
"exec": "ts-node --transpile-only ./back/app.ts"
|
||||||
|
}
|
49
package.json
49
package.json
|
@ -3,6 +3,9 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "umi dev",
|
"start": "umi dev",
|
||||||
"build": "umi build",
|
"build": "umi build",
|
||||||
|
"build-back": "tsc",
|
||||||
|
"start-back": "nodemon",
|
||||||
|
"pm2": "npm run build && node build/app.js",
|
||||||
"postinstall": "umi generate tmp",
|
"postinstall": "umi generate tmp",
|
||||||
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
|
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
|
||||||
"test": "umi-test",
|
"test": "umi-test",
|
||||||
|
@ -22,22 +25,66 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/pro-layout": "^6.5.0",
|
"@ant-design/pro-layout": "^6.5.0",
|
||||||
"@umijs/preset-react": "1.x",
|
"@umijs/preset-react": "1.x",
|
||||||
|
"agenda": "^3.1.0",
|
||||||
|
"agendash": "^1.0.0",
|
||||||
|
"argon2": "^0.27.0",
|
||||||
|
"body-parser": "^1.19.0",
|
||||||
|
"celebrate": "^13.0.3",
|
||||||
"codemirror": "^5.59.4",
|
"codemirror": "^5.59.4",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"errorhandler": "^1.5.1",
|
||||||
|
"event-dispatch": "^0.4.1",
|
||||||
|
"eventemitter3": "^4.0.7",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"express-basic-auth": "^1.2.0",
|
||||||
|
"express-jwt": "^6.0.0",
|
||||||
|
"jsonwebtoken": "^8.5.1",
|
||||||
|
"lodash": "^4.17.20",
|
||||||
|
"mailgun-js": "^0.22.0",
|
||||||
|
"method-override": "^3.0.0",
|
||||||
|
"moment": "^2.29.0",
|
||||||
|
"moment-timezone": "^0.5.31",
|
||||||
|
"mongoose": "^5.10.6",
|
||||||
|
"morgan": "^1.10.0",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
"qrcode.react": "^1.0.1",
|
"qrcode.react": "^1.0.1",
|
||||||
"react-codemirror2": "^7.2.1",
|
"react-codemirror2": "^7.2.1",
|
||||||
"react-diff-viewer": "^3.1.1",
|
"react-diff-viewer": "^3.1.1",
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"socks-proxy-agent": "^4.0.2",
|
||||||
|
"telegraf": "^4.0.3",
|
||||||
|
"typedi": "^0.8.0",
|
||||||
"umi": "^3.3.9",
|
"umi": "^3.3.9",
|
||||||
"umi-request": "^1.3.5"
|
"umi-request": "^1.3.5",
|
||||||
|
"winston": "^3.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/agenda": "^2.0.9",
|
||||||
|
"@types/cors": "^2.8.10",
|
||||||
|
"@types/express": "^4.17.8",
|
||||||
|
"@types/express-jwt": "^6.0.1",
|
||||||
|
"@types/jsonwebtoken": "^8.5.0",
|
||||||
|
"@types/lodash": "^4.14.161",
|
||||||
|
"@types/mongoose": "^5.7.36",
|
||||||
|
"@types/node": "^14.11.2",
|
||||||
|
"@types/node-fetch": "^2.5.8",
|
||||||
"@types/qrcode.react": "^1.0.1",
|
"@types/qrcode.react": "^1.0.1",
|
||||||
"@types/react": "^17.0.0",
|
"@types/react": "^17.0.0",
|
||||||
"@types/react-dom": "^17.0.0",
|
"@types/react-dom": "^17.0.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.2.0",
|
||||||
|
"@typescript-eslint/parser": "^4.2.0",
|
||||||
"@umijs/test": "^3.3.9",
|
"@umijs/test": "^3.3.9",
|
||||||
|
"eslint": "^7.9.0",
|
||||||
|
"eslint-config-prettier": "^6.11.0",
|
||||||
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"lint-staged": "^10.0.7",
|
"lint-staged": "^10.0.7",
|
||||||
|
"nodemon": "^2.0.4",
|
||||||
"prettier": "^2.2.0",
|
"prettier": "^2.2.0",
|
||||||
"react": "17.x",
|
"react": "17.x",
|
||||||
"react-dom": "17.x",
|
"react-dom": "17.x",
|
||||||
|
"ts-node": "^9.0.0",
|
||||||
|
"tslint": "^5.20.1",
|
||||||
"typescript": "^4.1.2",
|
"typescript": "^4.1.2",
|
||||||
"yorkie": "^2.0.0"
|
"yorkie": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,12 @@ const Crontab = () => {
|
||||||
|
|
||||||
const getConfig = () => {
|
const getConfig = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request.get(`${config.apiPrefix}config/shareCode`).then((data) => {
|
request
|
||||||
setValue(data);
|
.get(`${config.apiPrefix}config/shareCode`)
|
||||||
}).finally(() => setLoading(false));
|
.then((data) => {
|
||||||
|
setValue(data.content);
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateConfig = () => {
|
const updateConfig = () => {
|
||||||
|
|
|
@ -15,9 +15,12 @@ const Config = () => {
|
||||||
|
|
||||||
const getConfig = () => {
|
const getConfig = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request.get(`${config.apiPrefix}config/config`).then((data) => {
|
request
|
||||||
setValue(data);
|
.get(`${config.apiPrefix}config/config`)
|
||||||
}).finally(() => setLoading(false));
|
.then((data) => {
|
||||||
|
setValue(data.content);
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateConfig = () => {
|
const updateConfig = () => {
|
||||||
|
|
|
@ -25,9 +25,7 @@ const columns = [
|
||||||
title: '状态',
|
title: '状态',
|
||||||
key: 'status',
|
key: 'status',
|
||||||
dataIndex: 'status',
|
dataIndex: 'status',
|
||||||
render: (text: string, record: any) => (
|
render: (text: string, record: any) => <Tag color="success">success</Tag>,
|
||||||
<Tag color="success">success</Tag>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
|
@ -74,9 +72,12 @@ const Config = () => {
|
||||||
|
|
||||||
const getConfig = () => {
|
const getConfig = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request.get(`${config.apiPrefix}config/config`).then((data) => {
|
request
|
||||||
setValue(data);
|
.get(`${config.apiPrefix}config/config`)
|
||||||
}).finally(() => setLoading(false));
|
.then((data) => {
|
||||||
|
setValue(data.content);
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateConfig = () => {
|
const updateConfig = () => {
|
||||||
|
@ -182,7 +183,11 @@ const Config = () => {
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Table columns={columns} pagination={{hideOnSinglePage: true}} dataSource={data} />
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
pagination={{ hideOnSinglePage: true }}
|
||||||
|
dataSource={data}
|
||||||
|
/>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,9 +14,12 @@ const Crontab = () => {
|
||||||
|
|
||||||
const getConfig = () => {
|
const getConfig = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request.get(`${config.apiPrefix}config/crontab`).then((data) => {
|
request
|
||||||
setValue(data);
|
.get(`${config.apiPrefix}config/crontab`)
|
||||||
}).finally(() => setLoading(false));
|
.then((data) => {
|
||||||
|
setValue(data.content);
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateConfig = () => {
|
const updateConfig = () => {
|
||||||
|
|
|
@ -16,15 +16,18 @@ const Crontab = () => {
|
||||||
|
|
||||||
const getConfig = () => {
|
const getConfig = () => {
|
||||||
request.get(`${config.apiPrefix}config/config`).then((data) => {
|
request.get(`${config.apiPrefix}config/config`).then((data) => {
|
||||||
setValue(data);
|
setValue(data.content);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSample = () => {
|
const getSample = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request.get(`${config.apiPrefix}config/sample`).then((data) => {
|
request
|
||||||
setSample(data);
|
.get(`${config.apiPrefix}config/sample`)
|
||||||
}).finally(() => setLoading(false));
|
.then((data) => {
|
||||||
|
setSample(data.content);
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -63,16 +66,19 @@ const Crontab = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ReactDiffViewer
|
<ReactDiffViewer
|
||||||
styles={{ diffRemoved: {
|
styles={{
|
||||||
overflowX: 'auto',
|
diffRemoved: {
|
||||||
maxWidth: 300,
|
overflowX: 'auto',
|
||||||
},
|
maxWidth: 300,
|
||||||
diffAdded: {
|
},
|
||||||
overflowX: 'auto',
|
diffAdded: {
|
||||||
maxWidth: 300,
|
overflowX: 'auto',
|
||||||
},line: {
|
maxWidth: 300,
|
||||||
wordBreak: 'break-word',
|
},
|
||||||
}, }}
|
line: {
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
},
|
||||||
|
}}
|
||||||
oldValue={value}
|
oldValue={value}
|
||||||
newValue={sample}
|
newValue={sample}
|
||||||
splitView={true}
|
splitView={true}
|
||||||
|
|
|
@ -14,9 +14,12 @@ const Crontab = () => {
|
||||||
|
|
||||||
const getConfig = () => {
|
const getConfig = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request.get(`${config.apiPrefix}config/diy`).then((data) => {
|
request
|
||||||
setValue(data);
|
.get(`${config.apiPrefix}config/diy`)
|
||||||
}).finally(() => setLoading(false));
|
.then((data) => {
|
||||||
|
setValue(data.content);
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateConfig = () => {
|
const updateConfig = () => {
|
||||||
|
|
|
@ -18,7 +18,7 @@ const Login = () => {
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.err == 0) {
|
if (data.err == 0) {
|
||||||
localStorage.setItem(config.authKey, 'true');
|
localStorage.setItem(config.authKey, data.token);
|
||||||
history.push('/cookie');
|
history.push('/cookie');
|
||||||
} else {
|
} else {
|
||||||
notification.open({
|
notification.open({
|
||||||
|
@ -36,7 +36,7 @@ const Login = () => {
|
||||||
if (isAuth) {
|
if (isAuth) {
|
||||||
history.push('/cookie');
|
history.push('/cookie');
|
||||||
}
|
}
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
@ -50,7 +50,7 @@ const Login = () => {
|
||||||
rules={[{ required: true, message: '请输入用户名' }]}
|
rules={[{ required: true, message: '请输入用户名' }]}
|
||||||
hasFeedback
|
hasFeedback
|
||||||
>
|
>
|
||||||
<Input placeholder="用户名" autoFocus/>
|
<Input placeholder="用户名" autoFocus />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem
|
<FormItem
|
||||||
name="password"
|
name="password"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export default {
|
export default {
|
||||||
siteName: '京东羊毛脚本控制面板',
|
siteName: '京东羊毛脚本控制面板',
|
||||||
apiPrefix: '/api/',
|
apiPrefix: '/api/',
|
||||||
authKey: 'whyour',
|
authKey: 'token',
|
||||||
|
|
||||||
/* Layout configuration, specify which layout to use for route. */
|
/* Layout configuration, specify which layout to use for route. */
|
||||||
layouts: [
|
layouts: [
|
||||||
|
|
|
@ -1,29 +1,39 @@
|
||||||
import { extend } from 'umi-request';
|
import { extend } from 'umi-request';
|
||||||
import { history } from 'umi';
|
import { history } from 'umi';
|
||||||
|
import config from './config';
|
||||||
|
|
||||||
const time = Date.now();
|
const time = Date.now();
|
||||||
const errorHandler = function (error: any) {
|
const errorHandler = function (error: any) {
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
console.log(error.response)
|
console.log(error.response);
|
||||||
} else {
|
} else {
|
||||||
console.log(error.message);
|
console.log(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error; // 如果throw. 错误将继续抛出.
|
throw error; // 如果throw. 错误将继续抛出.
|
||||||
// return {some: 'data'};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const _request = extend({ timeout: 5000, params: { t: time }, errorHandler });
|
const _request = extend({ timeout: 5000, params: { t: time }, errorHandler });
|
||||||
|
|
||||||
_request.interceptors.response.use(async response => {
|
_request.interceptors.request.use((url, options) => {
|
||||||
const res = await response.clone().text()
|
const token = localStorage.getItem(config.authKey);
|
||||||
if (res === '请先登录!') {
|
if (token) {
|
||||||
|
const headers = {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
};
|
||||||
|
return { url, options: { ...options, headers } };
|
||||||
|
}
|
||||||
|
return { url, options };
|
||||||
|
});
|
||||||
|
|
||||||
|
_request.interceptors.response.use(async (response) => {
|
||||||
|
const res = await response.clone();
|
||||||
|
if (res.status === 401) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
localStorage.removeItem('whyour');
|
|
||||||
history.push('/login');
|
history.push('/login');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
})
|
});
|
||||||
|
|
||||||
export const request = _request;
|
export const request = _request;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "esnext",
|
"target": "es2017",
|
||||||
"module": "esnext",
|
"module": "commonjs",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
|
@ -13,11 +13,22 @@
|
||||||
"@/*": ["src/*"],
|
"@/*": ["src/*"],
|
||||||
"@@/*": ["src/.umi/*"]
|
"@@/*": ["src/.umi/*"]
|
||||||
},
|
},
|
||||||
|
"lib": ["dom", "es2017", "esnext.asynciterable"],
|
||||||
|
"typeRoots": [
|
||||||
|
"./node_modules/@types",
|
||||||
|
"./back/types",
|
||||||
|
"./node_modules/celebrate/lib/index.d.ts"
|
||||||
|
],
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"experimentalDecorators": true
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"pretty": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"noEmit": false
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"mock/**/*",
|
"back/**/*",
|
||||||
"src/**/*",
|
"src/**/*",
|
||||||
"config/**/*",
|
"config/**/*",
|
||||||
".umirc.ts",
|
".umirc.ts",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user