mirror of
https://github.com/whyour/qinglong.git
synced 2025-07-07 11:56:08 +08:00
重构环境变量管理,添加脚本查看
This commit is contained in:
parent
7ed1abde36
commit
0fade7a5a9
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -25,4 +25,5 @@
|
||||||
/config
|
/config
|
||||||
/log
|
/log
|
||||||
/db
|
/db
|
||||||
/manual_log
|
/manual_log
|
||||||
|
/scripts
|
|
@ -5,33 +5,40 @@ import { Logger } from 'winston';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { celebrate, Joi } from 'celebrate';
|
import { celebrate, Joi } from 'celebrate';
|
||||||
import { execSync } from 'child_process';
|
|
||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/', route);
|
app.use('/', route);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/config/:key',
|
'/configs/files',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
let content = '未找到文件';
|
const fileList = fs.readdirSync(config.configPath, 'utf-8');
|
||||||
switch (req.params.key) {
|
res.send({
|
||||||
case 'config':
|
code: 200,
|
||||||
content = getFileContentByName(config.confFile);
|
data: fileList
|
||||||
break;
|
.filter((x) => !config.blackFileList.includes(x))
|
||||||
case 'sample':
|
.map((x) => {
|
||||||
content = getFileContentByName(config.sampleFile);
|
return { title: x, value: x };
|
||||||
break;
|
}),
|
||||||
case 'crontab':
|
});
|
||||||
content = getFileContentByName(config.crontabFile);
|
} catch (e) {
|
||||||
break;
|
logger.error('🔥 error: %o', e);
|
||||||
case 'extra':
|
return next(e);
|
||||||
content = getFileContentByName(config.extraFile);
|
}
|
||||||
break;
|
},
|
||||||
default:
|
);
|
||||||
break;
|
|
||||||
}
|
route.get(
|
||||||
|
'/configs/:file',
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
const content = getFileContentByName(
|
||||||
|
`${config.configPath}${req.params.file}`,
|
||||||
|
);
|
||||||
res.send({ code: 200, data: content });
|
res.send({ code: 200, data: content });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
|
@ -41,7 +48,7 @@ export default (app: Router) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/save',
|
'/configs/save',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
|
@ -52,11 +59,8 @@ export default (app: Router) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const { name, content } = req.body;
|
const { name, content } = req.body;
|
||||||
const path = (config.fileMap as any)[name];
|
const path = `${config.configPath}${name}`;
|
||||||
fs.writeFileSync(path, content);
|
fs.writeFileSync(path, content);
|
||||||
if (name === 'crontab.list') {
|
|
||||||
execSync(`crontab ${path}`);
|
|
||||||
}
|
|
||||||
res.send({ code: 200, msg: '保存成功' });
|
res.send({ code: 200, msg: '保存成功' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Router, Request, Response, NextFunction } from 'express';
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import CookieService from '../services/cookie';
|
import EnvService from '../services/env';
|
||||||
import { Logger } from 'winston';
|
import { Logger } from 'winston';
|
||||||
import { celebrate, Joi } from 'celebrate';
|
import { celebrate, Joi } from 'celebrate';
|
||||||
const route = Router();
|
const route = Router();
|
||||||
|
@ -8,12 +8,12 @@ const route = Router();
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/', route);
|
app.use('/', route);
|
||||||
route.get(
|
route.get(
|
||||||
'/cookies',
|
'/envs',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cookieService = Container.get(CookieService);
|
const envService = Container.get(EnvService);
|
||||||
const data = await cookieService.cookies('', { position: -1 }, true);
|
const data = await envService.envs('', { position: -1 });
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
|
@ -23,15 +23,19 @@ export default (app: Router) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/cookies',
|
'/envs',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()).min(1),
|
body: Joi.object({
|
||||||
|
value: Joi.string().required(),
|
||||||
|
name: Joi.string().required(),
|
||||||
|
remarks: Joi.string().optional(),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cookieService = Container.get(CookieService);
|
const envService = Container.get(EnvService);
|
||||||
const data = await cookieService.create(req.body);
|
const data = await envService.create(req.body);
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
|
@ -41,18 +45,20 @@ export default (app: Router) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/cookies',
|
'/envs',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
value: Joi.string().required(),
|
value: Joi.string().required(),
|
||||||
|
name: Joi.string().required(),
|
||||||
|
remarks: Joi.string().optional(),
|
||||||
_id: Joi.string().required(),
|
_id: Joi.string().required(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cookieService = Container.get(CookieService);
|
const envService = Container.get(EnvService);
|
||||||
const data = await cookieService.update(req.body);
|
const data = await envService.update(req.body);
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
|
@ -62,15 +68,15 @@ export default (app: Router) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
route.delete(
|
route.delete(
|
||||||
'/cookies',
|
'/envs',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cookieService = Container.get(CookieService);
|
const envService = Container.get(EnvService);
|
||||||
const data = await cookieService.remove(req.body);
|
const data = await envService.remove(req.body);
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
|
@ -80,7 +86,7 @@ export default (app: Router) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/cookies/:id/move',
|
'/envs/:id/move',
|
||||||
celebrate({
|
celebrate({
|
||||||
params: Joi.object({
|
params: Joi.object({
|
||||||
id: Joi.string().required(),
|
id: Joi.string().required(),
|
||||||
|
@ -93,28 +99,8 @@ export default (app: Router) => {
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cookieService = Container.get(CookieService);
|
const envService = Container.get(EnvService);
|
||||||
const data = await cookieService.move(req.params.id, req.body);
|
const data = await envService.move(req.params.id, req.body);
|
||||||
return res.send({ code: 200, data });
|
|
||||||
} catch (e) {
|
|
||||||
logger.error('🔥 error: %o', e);
|
|
||||||
return next(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
route.get(
|
|
||||||
'/cookies/:id/refresh',
|
|
||||||
celebrate({
|
|
||||||
params: Joi.object({
|
|
||||||
id: Joi.string().required(),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
|
||||||
const logger: Logger = Container.get('logger');
|
|
||||||
try {
|
|
||||||
const cookieService = Container.get(CookieService);
|
|
||||||
const data = await cookieService.refreshCookie(req.params.id);
|
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
|
@ -124,15 +110,15 @@ export default (app: Router) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/cookies/disable',
|
'/envs/disable',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cookieService = Container.get(CookieService);
|
const envService = Container.get(EnvService);
|
||||||
const data = await cookieService.disabled(req.body);
|
const data = await envService.disabled(req.body);
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
|
@ -142,15 +128,36 @@ export default (app: Router) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/cookies/enable',
|
'/envs/enable',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cookieService = Container.get(CookieService);
|
const envService = Container.get(EnvService);
|
||||||
const data = await cookieService.enabled(req.body);
|
const data = await envService.enabled(req.body);
|
||||||
|
return res.send({ code: 200, data });
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
route.put(
|
||||||
|
'/envs/name',
|
||||||
|
celebrate({
|
||||||
|
body: Joi.object({
|
||||||
|
ids: Joi.array().items(Joi.string().required()),
|
||||||
|
name: Joi.string().required(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
const envService = Container.get(EnvService);
|
||||||
|
const data = await envService.updateNames(req.body);
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
|
@ -160,7 +167,7 @@ export default (app: Router) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/cookies/:id',
|
'/envs/:id',
|
||||||
celebrate({
|
celebrate({
|
||||||
params: Joi.object({
|
params: Joi.object({
|
||||||
id: Joi.string().required(),
|
id: Joi.string().required(),
|
||||||
|
@ -169,8 +176,8 @@ export default (app: Router) => {
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cookieService = Container.get(CookieService);
|
const envService = Container.get(EnvService);
|
||||||
const data = await cookieService.get(req.params.id);
|
const data = await envService.get(req.params.id);
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
|
@ -1,17 +1,19 @@
|
||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import auth from './auth';
|
import auth from './auth';
|
||||||
import cookie from './cookie';
|
import env from './env';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import log from './log';
|
import log from './log';
|
||||||
import cron from './cron';
|
import cron from './cron';
|
||||||
|
import script from './script';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const app = Router();
|
const app = Router();
|
||||||
auth(app);
|
auth(app);
|
||||||
cookie(app);
|
env(app);
|
||||||
config(app);
|
config(app);
|
||||||
log(app);
|
log(app);
|
||||||
cron(app);
|
cron(app);
|
||||||
|
script(app);
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
};
|
};
|
||||||
|
|
48
back/api/script.ts
Normal file
48
back/api/script.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { getFileContentByName, getLastModifyFilePath } from '../config/util';
|
||||||
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
|
import { Container } from 'typedi';
|
||||||
|
import { Logger } from 'winston';
|
||||||
|
import config from '../config';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import { celebrate, Joi } from 'celebrate';
|
||||||
|
const route = Router();
|
||||||
|
|
||||||
|
export default (app: Router) => {
|
||||||
|
app.use('/', route);
|
||||||
|
|
||||||
|
route.get(
|
||||||
|
'/scripts/files',
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
const fileList = fs.readdirSync(config.scriptPath, 'utf-8');
|
||||||
|
res.send({
|
||||||
|
code: 200,
|
||||||
|
data: fileList.map((x) => {
|
||||||
|
return { title: x, value: x, key: x };
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
route.get(
|
||||||
|
'/scripts/:file',
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
console.log(req.params.file);
|
||||||
|
const content = getFileContentByName(
|
||||||
|
`${config.scriptPath}${req.params.file}`,
|
||||||
|
);
|
||||||
|
res.send({ code: 200, data: content });
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
|
@ -5,13 +5,15 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
const envFound = dotenv.config();
|
const envFound = dotenv.config();
|
||||||
const rootPath = path.resolve(__dirname, '../../');
|
const rootPath = path.resolve(__dirname, '../../');
|
||||||
const cookieFile = path.join(rootPath, 'config/cookie.sh');
|
const envFile = path.join(rootPath, 'config/env.sh');
|
||||||
const confFile = path.join(rootPath, 'config/config.sh');
|
const confFile = path.join(rootPath, 'config/config.sh');
|
||||||
const sampleFile = path.join(rootPath, 'sample/config.sample.sh');
|
const sampleFile = path.join(rootPath, 'sample/config.sample.sh');
|
||||||
const crontabFile = path.join(rootPath, 'config/crontab.list');
|
const crontabFile = path.join(rootPath, 'config/crontab.list');
|
||||||
const confBakDir = path.join(rootPath, 'config/bak/');
|
const confBakDir = path.join(rootPath, 'config/bak/');
|
||||||
const authConfigFile = path.join(rootPath, 'config/auth.json');
|
const authConfigFile = path.join(rootPath, 'config/auth.json');
|
||||||
const extraFile = path.join(rootPath, 'config/extra.sh');
|
const extraFile = path.join(rootPath, 'config/extra.sh');
|
||||||
|
const configPath = path.join(rootPath, 'config/');
|
||||||
|
const scriptPath = path.join(rootPath, 'scripts/');
|
||||||
const logPath = path.join(rootPath, 'log/');
|
const logPath = path.join(rootPath, 'log/');
|
||||||
const authError = '错误的用户名密码,请重试';
|
const authError = '错误的用户名密码,请重试';
|
||||||
const loginFaild = '请先登录!';
|
const loginFaild = '请先登录!';
|
||||||
|
@ -19,7 +21,7 @@ const configString = 'config sample crontab shareCode diy';
|
||||||
const dbPath = path.join(rootPath, 'db/');
|
const dbPath = path.join(rootPath, 'db/');
|
||||||
const manualLogPath = path.join(rootPath, 'manual_log/');
|
const manualLogPath = path.join(rootPath, 'manual_log/');
|
||||||
const cronDbFile = path.join(rootPath, 'db/crontab.db');
|
const cronDbFile = path.join(rootPath, 'db/crontab.db');
|
||||||
const cookieDbFile = path.join(rootPath, 'db/cookie.db');
|
const envDbFile = path.join(rootPath, 'db/env.db');
|
||||||
const configFound = dotenv.config({ path: confFile });
|
const configFound = dotenv.config({ path: confFile });
|
||||||
|
|
||||||
if (envFound.error) {
|
if (envFound.error) {
|
||||||
|
@ -50,14 +52,12 @@ export default {
|
||||||
crontabFile,
|
crontabFile,
|
||||||
sampleFile,
|
sampleFile,
|
||||||
confFile,
|
confFile,
|
||||||
cookieFile,
|
envFile,
|
||||||
fileMap: {
|
|
||||||
'config.sh': confFile,
|
|
||||||
'crontab.list': crontabFile,
|
|
||||||
'extra.sh': extraFile,
|
|
||||||
},
|
|
||||||
dbPath,
|
dbPath,
|
||||||
cronDbFile,
|
cronDbFile,
|
||||||
cookieDbFile,
|
envDbFile,
|
||||||
manualLogPath,
|
manualLogPath,
|
||||||
|
configPath,
|
||||||
|
scriptPath,
|
||||||
|
blackFileList: ['auth.json', 'config.sh.sample', 'cookie.sh', 'crontab.list'],
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
export class Cookie {
|
export class Env {
|
||||||
value?: string;
|
value?: string;
|
||||||
timestamp?: string;
|
timestamp?: string;
|
||||||
created?: number;
|
created?: number;
|
||||||
_id?: string;
|
_id?: string;
|
||||||
status?: CookieStatus;
|
status?: EnvStatus;
|
||||||
position?: number;
|
position?: number;
|
||||||
|
name?: number;
|
||||||
|
remarks?: number;
|
||||||
|
|
||||||
constructor(options: Cookie) {
|
constructor(options: Env) {
|
||||||
this.value = options.value;
|
this.value = options.value;
|
||||||
this._id = options._id;
|
this._id = options._id;
|
||||||
this.created = options.created || new Date().valueOf();
|
this.created = options.created || new Date().valueOf();
|
||||||
this.status = options.status || CookieStatus.noacquired;
|
this.status = options.status || EnvStatus.noacquired;
|
||||||
this.timestamp = new Date().toString();
|
this.timestamp = new Date().toString();
|
||||||
this.position = options.position;
|
this.name = options.name;
|
||||||
|
this.remarks = options.remarks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CookieStatus {
|
export enum EnvStatus {
|
||||||
'noacquired',
|
'noacquired',
|
||||||
'normal',
|
'normal',
|
||||||
'disabled',
|
'disabled',
|
||||||
|
@ -24,4 +27,4 @@ export enum CookieStatus {
|
||||||
'abnormal',
|
'abnormal',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initCookiePosition = 9999999999;
|
export const initEnvPosition = 9999999999;
|
|
@ -2,7 +2,7 @@ import { exec } from 'child_process';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { Crontab, CrontabStatus } from '../data/cron';
|
import { Crontab, CrontabStatus } from '../data/cron';
|
||||||
import CronService from '../services/cron';
|
import CronService from '../services/cron';
|
||||||
import CookieService from '../services/cookie';
|
import EnvService from '../services/env';
|
||||||
|
|
||||||
const initData = [
|
const initData = [
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,7 @@ const initData = [
|
||||||
|
|
||||||
export default async () => {
|
export default async () => {
|
||||||
const cronService = Container.get(CronService);
|
const cronService = Container.get(CronService);
|
||||||
const cookieService = Container.get(CookieService);
|
const envService = Container.get(EnvService);
|
||||||
const cronDb = cronService.getDb();
|
const cronDb = cronService.getDb();
|
||||||
|
|
||||||
cronDb.count({}, async (err, count) => {
|
cronDb.count({}, async (err, count) => {
|
||||||
|
@ -97,7 +97,7 @@ export default async () => {
|
||||||
|
|
||||||
// 初始化保存一次ck和定时任务数据
|
// 初始化保存一次ck和定时任务数据
|
||||||
await cronService.autosave_crontab();
|
await cronService.autosave_crontab();
|
||||||
await cookieService.set_cookies();
|
await envService.set_envs();
|
||||||
};
|
};
|
||||||
|
|
||||||
function randomSchedule(from: number, to: number) {
|
function randomSchedule(from: number, to: number) {
|
||||||
|
|
|
@ -1,333 +0,0 @@
|
||||||
import { Service, Inject } from 'typedi';
|
|
||||||
import winston from 'winston';
|
|
||||||
import fetch from 'node-fetch';
|
|
||||||
import { getFileContentByName } from '../config/util';
|
|
||||||
import config from '../config';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import got from 'got';
|
|
||||||
import DataStore from 'nedb';
|
|
||||||
import { Cookie, CookieStatus, initCookiePosition } from '../data/cookie';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export default class CookieService {
|
|
||||||
private cronDb = new DataStore({ filename: config.cookieDbFile });
|
|
||||||
constructor(@Inject('logger') private logger: winston.Logger) {
|
|
||||||
this.cronDb.loadDatabase((err) => {
|
|
||||||
if (err) throw err;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getCookies() {
|
|
||||||
const content = getFileContentByName(config.cookieFile);
|
|
||||||
return this.formatCookie(content.split('\n').filter((x) => !!x));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async addCookie(cookies: string[]) {
|
|
||||||
let content = getFileContentByName(config.cookieFile);
|
|
||||||
const originCookies = content.split('\n').filter((x) => !!x);
|
|
||||||
const result = originCookies.concat(cookies);
|
|
||||||
fs.writeFileSync(config.cookieFile, result.join('\n'));
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public async updateCookie({ cookie, oldCookie }) {
|
|
||||||
let content = getFileContentByName(config.cookieFile);
|
|
||||||
const cookies = content.split('\n');
|
|
||||||
const index = cookies.findIndex((x) => x === oldCookie);
|
|
||||||
if (index !== -1) {
|
|
||||||
cookies[index] = cookie;
|
|
||||||
fs.writeFileSync(config.cookieFile, cookies.join('\n'));
|
|
||||||
return '';
|
|
||||||
} else {
|
|
||||||
return '未找到要原有Cookie';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async deleteCookie(cookie: string) {
|
|
||||||
let content = getFileContentByName(config.cookieFile);
|
|
||||||
const cookies = content.split('\n');
|
|
||||||
const index = cookies.findIndex((x) => x === cookie);
|
|
||||||
if (index !== -1) {
|
|
||||||
cookies.splice(index, 1);
|
|
||||||
fs.writeFileSync(config.cookieFile, cookies.join('\n'));
|
|
||||||
return '';
|
|
||||||
} else {
|
|
||||||
return '未找到要删除的Cookie';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async formatCookie(data: any[]) {
|
|
||||||
const result = [];
|
|
||||||
for (const x of data) {
|
|
||||||
const { nickname, status } = await this.getJdInfo(x);
|
|
||||||
if (/pt_pin=(.+?);/.test(x)) {
|
|
||||||
result.push({
|
|
||||||
pin: x.match(/pt_pin=(.+?);/)[1],
|
|
||||||
cookie: x,
|
|
||||||
status,
|
|
||||||
nickname: nickname,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
result.push({
|
|
||||||
pin: 'pin未匹配到',
|
|
||||||
cookie: x,
|
|
||||||
status,
|
|
||||||
nickname: nickname,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async refreshCookie(_id: string) {
|
|
||||||
const current = await this.get(_id);
|
|
||||||
const { status, nickname } = await this.getJdInfo(current.value);
|
|
||||||
return {
|
|
||||||
...current,
|
|
||||||
status,
|
|
||||||
nickname,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private getJdInfo(cookie: string) {
|
|
||||||
return fetch(
|
|
||||||
`https://me-api.jd.com/user_new/info/GetJDUserInfoUnion?orgFlag=JD_PinGou_New&callSource=mainorder&channel=4&isHomewhite=0&sceneval=2&_=${Date.now()}&sceneval=2&g_login_type=1&g_ty=ls`,
|
|
||||||
{
|
|
||||||
method: 'get',
|
|
||||||
headers: {
|
|
||||||
Accept: '*/*',
|
|
||||||
'Accept-Encoding': 'gzip, deflate, br',
|
|
||||||
'Accept-Language': 'zh-cn',
|
|
||||||
Connection: 'keep-alive',
|
|
||||||
Cookie: cookie,
|
|
||||||
Referer: 'https://home.m.jd.com/myJd/newhome.action',
|
|
||||||
'User-Agent':
|
|
||||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1',
|
|
||||||
Host: 'me-api.jd.com',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.then((x) => x.json())
|
|
||||||
.then((x) => {
|
|
||||||
if (x.retcode === '0' && x.data && x.data.userInfo) {
|
|
||||||
return {
|
|
||||||
nickname: x.data.userInfo.baseInfo.nickname,
|
|
||||||
status: CookieStatus.normal,
|
|
||||||
};
|
|
||||||
} else if (x.retcode === 13) {
|
|
||||||
return { status: CookieStatus.invalid, nickname: '-' };
|
|
||||||
}
|
|
||||||
return { status: CookieStatus.abnormal, nickname: '-' };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async formatCookies(cookies: Cookie[]) {
|
|
||||||
const result = [];
|
|
||||||
for (let i = 0; i < cookies.length; i++) {
|
|
||||||
const cookie = cookies[i];
|
|
||||||
if (cookie.status !== CookieStatus.disabled) {
|
|
||||||
const { status, nickname } = await this.getJdInfo(cookie.value);
|
|
||||||
result.push({ ...cookie, status, nickname });
|
|
||||||
} else {
|
|
||||||
result.push({ ...cookie, nickname: '-' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async create(payload: string[]): Promise<Cookie[]> {
|
|
||||||
const cookies = await this.cookies();
|
|
||||||
let position = initCookiePosition;
|
|
||||||
if (cookies && cookies.length > 0) {
|
|
||||||
position = cookies[cookies.length - 1].position;
|
|
||||||
}
|
|
||||||
const tabs = payload.map((x) => {
|
|
||||||
const cookie = new Cookie({ value: x, position });
|
|
||||||
position = position / 2;
|
|
||||||
cookie.position = position;
|
|
||||||
return cookie;
|
|
||||||
});
|
|
||||||
const docs = await this.insert(tabs);
|
|
||||||
await this.set_cookies();
|
|
||||||
return await this.formatCookies(docs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async insert(payload: Cookie[]): Promise<Cookie[]> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.cronDb.insert(payload, (err, docs) => {
|
|
||||||
if (err) {
|
|
||||||
this.logger.error(err);
|
|
||||||
} else {
|
|
||||||
resolve(docs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async update(payload: Cookie): Promise<Cookie> {
|
|
||||||
const { _id, ...other } = payload;
|
|
||||||
const doc = await this.get(_id);
|
|
||||||
const tab = new Cookie({ ...doc, ...other });
|
|
||||||
const newDoc = await this.updateDb(tab);
|
|
||||||
await this.set_cookies();
|
|
||||||
const [newCookie] = await this.formatCookies([newDoc]);
|
|
||||||
return newCookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async updateDb(payload: Cookie): Promise<Cookie> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.cronDb.update(
|
|
||||||
{ _id: payload._id },
|
|
||||||
payload,
|
|
||||||
{ returnUpdatedDocs: true },
|
|
||||||
(err, num, doc) => {
|
|
||||||
if (err) {
|
|
||||||
this.logger.error(err);
|
|
||||||
} else {
|
|
||||||
resolve(doc as Cookie);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async remove(ids: string[]) {
|
|
||||||
return new Promise((resolve: any) => {
|
|
||||||
this.cronDb.remove(
|
|
||||||
{ _id: { $in: ids } },
|
|
||||||
{ multi: true },
|
|
||||||
async (err) => {
|
|
||||||
await this.set_cookies();
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async move(
|
|
||||||
_id: string,
|
|
||||||
{
|
|
||||||
fromIndex,
|
|
||||||
toIndex,
|
|
||||||
}: {
|
|
||||||
fromIndex: number;
|
|
||||||
toIndex: number;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
let targetPosition: number;
|
|
||||||
const isUpward = fromIndex > toIndex;
|
|
||||||
const cookies = await this.cookies();
|
|
||||||
if (toIndex === 0 || toIndex === cookies.length - 1) {
|
|
||||||
targetPosition = isUpward
|
|
||||||
? cookies[0].position * 2
|
|
||||||
: cookies[toIndex].position / 2;
|
|
||||||
} else {
|
|
||||||
targetPosition = isUpward
|
|
||||||
? (cookies[toIndex].position + cookies[toIndex - 1].position) / 2
|
|
||||||
: (cookies[toIndex].position + cookies[toIndex + 1].position) / 2;
|
|
||||||
}
|
|
||||||
this.update({
|
|
||||||
_id,
|
|
||||||
position: targetPosition,
|
|
||||||
});
|
|
||||||
await this.set_cookies();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async cookies(
|
|
||||||
searchText?: string,
|
|
||||||
sort: any = { position: -1 },
|
|
||||||
needDetail: boolean = false,
|
|
||||||
): Promise<Cookie[]> {
|
|
||||||
let query = {};
|
|
||||||
if (searchText) {
|
|
||||||
const reg = new RegExp(searchText);
|
|
||||||
query = {
|
|
||||||
$or: [
|
|
||||||
{
|
|
||||||
name: reg,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
command: reg,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const newDocs = await this.find(query, sort);
|
|
||||||
if (needDetail) {
|
|
||||||
return await this.formatCookies(newDocs);
|
|
||||||
} else {
|
|
||||||
return newDocs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async find(query: any, sort: any): Promise<Cookie[]> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.cronDb
|
|
||||||
.find(query)
|
|
||||||
.sort({ ...sort })
|
|
||||||
.exec((err, docs) => {
|
|
||||||
resolve(docs);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async get(_id: string): Promise<Cookie> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.cronDb.find({ _id }).exec((err, docs) => {
|
|
||||||
resolve(docs[0]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getBySort(sort: any): Promise<Cookie> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.cronDb
|
|
||||||
.find({})
|
|
||||||
.sort({ ...sort })
|
|
||||||
.limit(1)
|
|
||||||
.exec((err, docs) => {
|
|
||||||
resolve(docs[0]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async disabled(ids: string[]) {
|
|
||||||
return new Promise((resolve: any) => {
|
|
||||||
this.cronDb.update(
|
|
||||||
{ _id: { $in: ids } },
|
|
||||||
{ $set: { status: CookieStatus.disabled } },
|
|
||||||
{ multi: true },
|
|
||||||
async (err) => {
|
|
||||||
await this.set_cookies();
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async enabled(ids: string[]) {
|
|
||||||
return new Promise((resolve: any) => {
|
|
||||||
this.cronDb.update(
|
|
||||||
{ _id: { $in: ids } },
|
|
||||||
{ $set: { status: CookieStatus.noacquired } },
|
|
||||||
{ multi: true },
|
|
||||||
async (err, num) => {
|
|
||||||
await this.set_cookies();
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async set_cookies() {
|
|
||||||
const cookies = await this.cookies();
|
|
||||||
let cookie_string = '';
|
|
||||||
cookies.forEach((tab) => {
|
|
||||||
if (tab.status !== CookieStatus.disabled) {
|
|
||||||
cookie_string += tab.value;
|
|
||||||
cookie_string += '\n';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fs.writeFileSync(config.cookieFile, cookie_string);
|
|
||||||
}
|
|
||||||
}
|
|
227
back/services/env.ts
Normal file
227
back/services/env.ts
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
import { Service, Inject } from 'typedi';
|
||||||
|
import winston from 'winston';
|
||||||
|
import { getFileContentByName } from '../config/util';
|
||||||
|
import config from '../config';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import DataStore from 'nedb';
|
||||||
|
import { Env, EnvStatus, initEnvPosition } from '../data/env';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class EnvService {
|
||||||
|
private cronDb = new DataStore({ filename: config.envDbFile });
|
||||||
|
constructor(@Inject('logger') private logger: winston.Logger) {
|
||||||
|
this.cronDb.loadDatabase((err) => {
|
||||||
|
if (err) throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async create(payload: Env): Promise<Env> {
|
||||||
|
const envs = await this.envs();
|
||||||
|
let position = initEnvPosition;
|
||||||
|
if (envs && envs.length > 0) {
|
||||||
|
position = envs[envs.length - 1].position;
|
||||||
|
}
|
||||||
|
const tab = new Env({ ...payload, position: position / 2 });
|
||||||
|
const doc = await this.insert(tab);
|
||||||
|
await this.set_envs();
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async insert(payload: Env): Promise<Env> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.cronDb.insert(payload, (err, doc) => {
|
||||||
|
if (err) {
|
||||||
|
this.logger.error(err);
|
||||||
|
} else {
|
||||||
|
resolve(doc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async update(payload: Env): Promise<Env> {
|
||||||
|
const { _id, ...other } = payload;
|
||||||
|
const doc = await this.get(_id);
|
||||||
|
const tab = new Env({ ...doc, ...other });
|
||||||
|
const newDoc = await this.updateDb(tab);
|
||||||
|
await this.set_envs();
|
||||||
|
return newDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateDb(payload: Env): Promise<Env> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.cronDb.update(
|
||||||
|
{ _id: payload._id },
|
||||||
|
payload,
|
||||||
|
{ returnUpdatedDocs: true },
|
||||||
|
(err, num, doc) => {
|
||||||
|
if (err) {
|
||||||
|
this.logger.error(err);
|
||||||
|
} else {
|
||||||
|
resolve(doc as Env);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async remove(ids: string[]) {
|
||||||
|
return new Promise((resolve: any) => {
|
||||||
|
this.cronDb.remove(
|
||||||
|
{ _id: { $in: ids } },
|
||||||
|
{ multi: true },
|
||||||
|
async (err) => {
|
||||||
|
await this.set_envs();
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async move(
|
||||||
|
_id: string,
|
||||||
|
{
|
||||||
|
fromIndex,
|
||||||
|
toIndex,
|
||||||
|
}: {
|
||||||
|
fromIndex: number;
|
||||||
|
toIndex: number;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
let targetPosition: number;
|
||||||
|
const isUpward = fromIndex > toIndex;
|
||||||
|
const envs = await this.envs();
|
||||||
|
if (toIndex === 0 || toIndex === envs.length - 1) {
|
||||||
|
targetPosition = isUpward
|
||||||
|
? envs[0].position * 2
|
||||||
|
: envs[toIndex].position / 2;
|
||||||
|
} else {
|
||||||
|
targetPosition = isUpward
|
||||||
|
? (envs[toIndex].position + envs[toIndex - 1].position) / 2
|
||||||
|
: (envs[toIndex].position + envs[toIndex + 1].position) / 2;
|
||||||
|
}
|
||||||
|
this.update({
|
||||||
|
_id,
|
||||||
|
position: targetPosition,
|
||||||
|
});
|
||||||
|
await this.set_envs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async envs(
|
||||||
|
searchText?: string,
|
||||||
|
sort: any = { position: -1 },
|
||||||
|
query: any = {},
|
||||||
|
): Promise<Env[]> {
|
||||||
|
let condition = { ...query };
|
||||||
|
if (searchText) {
|
||||||
|
const reg = new RegExp(searchText);
|
||||||
|
condition = {
|
||||||
|
$or: [
|
||||||
|
{
|
||||||
|
value: reg,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: reg,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
remarks: reg,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const newDocs = await this.find(condition, sort);
|
||||||
|
return newDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async find(query: any, sort: any): Promise<Env[]> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.cronDb
|
||||||
|
.find(query)
|
||||||
|
.sort({ ...sort })
|
||||||
|
.exec((err, docs) => {
|
||||||
|
resolve(docs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(_id: string): Promise<Env> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.cronDb.find({ _id }).exec((err, docs) => {
|
||||||
|
resolve(docs[0]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getBySort(sort: any): Promise<Env> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.cronDb
|
||||||
|
.find({})
|
||||||
|
.sort({ ...sort })
|
||||||
|
.limit(1)
|
||||||
|
.exec((err, docs) => {
|
||||||
|
resolve(docs[0]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async disabled(ids: string[]) {
|
||||||
|
return new Promise((resolve: any) => {
|
||||||
|
this.cronDb.update(
|
||||||
|
{ _id: { $in: ids } },
|
||||||
|
{ $set: { status: EnvStatus.disabled } },
|
||||||
|
{ multi: true },
|
||||||
|
async (err) => {
|
||||||
|
await this.set_envs();
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async enabled(ids: string[]) {
|
||||||
|
return new Promise((resolve: any) => {
|
||||||
|
this.cronDb.update(
|
||||||
|
{ _id: { $in: ids } },
|
||||||
|
{ $set: { status: EnvStatus.noacquired } },
|
||||||
|
{ multi: true },
|
||||||
|
async (err, num) => {
|
||||||
|
await this.set_envs();
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateNames({ ids, name }: { ids: string[]; name: string }) {
|
||||||
|
return new Promise((resolve: any) => {
|
||||||
|
this.cronDb.update(
|
||||||
|
{ _id: { $in: ids } },
|
||||||
|
{ $set: { name } },
|
||||||
|
{ multi: true },
|
||||||
|
async (err, num) => {
|
||||||
|
await this.set_envs();
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async set_envs() {
|
||||||
|
const envs = await this.envs(
|
||||||
|
'',
|
||||||
|
{ position: -1 },
|
||||||
|
{ status: { $ne: EnvStatus.disabled }, name: { $exists: true } },
|
||||||
|
);
|
||||||
|
const groups = _.groupBy(envs, 'name');
|
||||||
|
console.log(groups);
|
||||||
|
let env_string = '';
|
||||||
|
for (const key in groups) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(groups, key)) {
|
||||||
|
const group = groups[key];
|
||||||
|
env_string += `export ${key}="${_.map(group, 'value').join('&')}"\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fs.writeFileSync(config.envFile, env_string);
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,6 @@
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-jwt": "^6.0.0",
|
"express-jwt": "^6.0.0",
|
||||||
"got": "^11.8.2",
|
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"nedb": "^1.8.0",
|
"nedb": "^1.8.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
|
@ -42,12 +41,13 @@
|
||||||
"winston": "^3.3.3"
|
"winston": "^3.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ant-design/pro-layout": "^6.5.0",
|
|
||||||
"@ant-design/icons": "^4.6.2",
|
"@ant-design/icons": "^4.6.2",
|
||||||
|
"@ant-design/pro-layout": "^6.5.0",
|
||||||
"@types/cors": "^2.8.10",
|
"@types/cors": "^2.8.10",
|
||||||
"@types/express": "^4.17.8",
|
"@types/express": "^4.17.8",
|
||||||
"@types/express-jwt": "^6.0.1",
|
"@types/express-jwt": "^6.0.1",
|
||||||
"@types/jsonwebtoken": "^8.5.0",
|
"@types/jsonwebtoken": "^8.5.0",
|
||||||
|
"@types/lodash": "^4.14.170",
|
||||||
"@types/nedb": "^1.8.11",
|
"@types/nedb": "^1.8.11",
|
||||||
"@types/node": "^14.11.2",
|
"@types/node": "^14.11.2",
|
||||||
"@types/node-fetch": "^2.5.8",
|
"@types/node-fetch": "^2.5.8",
|
||||||
|
@ -60,6 +60,7 @@
|
||||||
"compression-webpack-plugin": "6.1.1",
|
"compression-webpack-plugin": "6.1.1",
|
||||||
"darkreader": "^4.9.27",
|
"darkreader": "^4.9.27",
|
||||||
"lint-staged": "^10.0.7",
|
"lint-staged": "^10.0.7",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"nodemon": "^2.0.4",
|
"nodemon": "^2.0.4",
|
||||||
"prettier": "^2.2.0",
|
"prettier": "^2.2.0",
|
||||||
"qrcode.react": "^1.0.1",
|
"qrcode.react": "^1.0.1",
|
||||||
|
|
|
@ -29,16 +29,6 @@ RandomDelay="300"
|
||||||
## 如果你自己会写shell脚本,并且希望在每次运行 ql update 命令时,额外运行你的 shell 脚本,请赋值为 "true",默认为true
|
## 如果你自己会写shell脚本,并且希望在每次运行 ql update 命令时,额外运行你的 shell 脚本,请赋值为 "true",默认为true
|
||||||
EnableExtraShell="true"
|
EnableExtraShell="true"
|
||||||
|
|
||||||
## 自动按顺序进行账号间互助(选填) 设置为 true 时,将直接导入code最新日志来进行互助
|
|
||||||
AutoHelpOther=""
|
|
||||||
|
|
||||||
## 定义 jcode 脚本导出的互助码模板样式(选填)
|
|
||||||
## 不填 使用“按编号顺序助力模板”,Cookie编号在前的优先助力
|
|
||||||
## 填 0 使用“全部一致助力模板”,所有账户要助力的码全部一致
|
|
||||||
## 填 1 使用“均等机会助力模板”,所有账户获得助力次数一致
|
|
||||||
## 填 2 使用“随机顺序助力模板”,本套脚本内账号间随机顺序助力,每次生成的顺序都不一致。
|
|
||||||
HelpType=""
|
|
||||||
|
|
||||||
## 是否自动启动bot,默认不启动,设置为true时自动启动,目前需要自行克隆bot仓库所需代码,存到ql/repo目录下,文件夹命名为dockerbot
|
## 是否自动启动bot,默认不启动,设置为true时自动启动,目前需要自行克隆bot仓库所需代码,存到ql/repo目录下,文件夹命名为dockerbot
|
||||||
AutoStartBot=""
|
AutoStartBot=""
|
||||||
|
|
||||||
|
@ -117,94 +107,4 @@ export GOBOT_URL=""
|
||||||
export GOBOT_TOKEN=""
|
export GOBOT_TOKEN=""
|
||||||
export GOBOT_QQ=""
|
export GOBOT_QQ=""
|
||||||
|
|
||||||
## 如果只是想要屏蔽某个ck不执行某个脚本,可以参考下面 case 这个命令的例子来控制,脚本名称包含后缀
|
|
||||||
## case $1 in
|
|
||||||
## test.js)
|
|
||||||
## TempBlockCookie="5"
|
|
||||||
## ;;
|
|
||||||
## esac
|
|
||||||
|
|
||||||
## 需组合的环境变量列表,env_name需要和var_name一一对应,如何有新活动按照格式添加(不懂勿动)
|
|
||||||
env_name=(
|
|
||||||
JD_COOKIE
|
|
||||||
FRUITSHARECODES
|
|
||||||
PETSHARECODES
|
|
||||||
PLANT_BEAN_SHARECODES
|
|
||||||
DREAM_FACTORY_SHARE_CODES
|
|
||||||
DDFACTORY_SHARECODES
|
|
||||||
JDZZ_SHARECODES
|
|
||||||
JDJOY_SHARECODES
|
|
||||||
JXNC_SHARECODES
|
|
||||||
BOOKSHOP_SHARECODES
|
|
||||||
JD_CASH_SHARECODES
|
|
||||||
JDSGMH_SHARECODES
|
|
||||||
JDCFD_SHARECODES
|
|
||||||
JDHEALTH_SHARECODES
|
|
||||||
)
|
|
||||||
var_name=(
|
|
||||||
Cookie
|
|
||||||
ForOtherFruit
|
|
||||||
ForOtherPet
|
|
||||||
ForOtherBean
|
|
||||||
ForOtherDreamFactory
|
|
||||||
ForOtherJdFactory
|
|
||||||
ForOtherJdzz
|
|
||||||
ForOtherJoy
|
|
||||||
ForOtherJxnc
|
|
||||||
ForOtherBookShop
|
|
||||||
ForOtherCash
|
|
||||||
ForOtherSgmh
|
|
||||||
ForOtherCfd
|
|
||||||
ForOtherHealth
|
|
||||||
)
|
|
||||||
|
|
||||||
## name_js为脚本文件名,如果使用ql repo命令拉取,文件名含有作者名
|
|
||||||
## 所有有互助码的活动,把脚本名称列在 name_js 中,对应 config.sh 中互助码后缀列在 name_config 中,中文名称列在 name_chinese 中。
|
|
||||||
## name_js、name_config 和 name_chinese 中的三个名称必须一一对应。
|
|
||||||
name_js=(
|
|
||||||
jd_fruit
|
|
||||||
jd_pet
|
|
||||||
jd_plantBean
|
|
||||||
jd_dreamFactory
|
|
||||||
jd_jdfactory
|
|
||||||
jd_jdzz
|
|
||||||
jd_crazy_joy
|
|
||||||
jd_jxnc
|
|
||||||
jd_bookshop
|
|
||||||
jd_cash
|
|
||||||
jd_sgmh
|
|
||||||
jd_cfd
|
|
||||||
jd_health
|
|
||||||
)
|
|
||||||
name_config=(
|
|
||||||
Fruit
|
|
||||||
Pet
|
|
||||||
Bean
|
|
||||||
DreamFactory
|
|
||||||
JdFactory
|
|
||||||
Jdzz
|
|
||||||
Joy
|
|
||||||
Jxnc
|
|
||||||
BookShop
|
|
||||||
Cash
|
|
||||||
Sgmh
|
|
||||||
Cfd
|
|
||||||
Health
|
|
||||||
)
|
|
||||||
name_chinese=(
|
|
||||||
东东农场
|
|
||||||
东东萌宠
|
|
||||||
京东种豆得豆
|
|
||||||
京喜工厂
|
|
||||||
东东工厂
|
|
||||||
京东赚赚
|
|
||||||
crazyJoy任务
|
|
||||||
京喜农场
|
|
||||||
口袋书店
|
|
||||||
签到领现金
|
|
||||||
闪购盲盒
|
|
||||||
京喜财富岛
|
|
||||||
东东健康社区
|
|
||||||
)
|
|
||||||
|
|
||||||
## 其他需要的变量,脚本中需要的变量使用 export 变量名= 声明即可
|
## 其他需要的变量,脚本中需要的变量使用 export 变量名= 声明即可
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.0.0",
|
||||||
"download": "^8.0.0",
|
"download": "^8.0.0",
|
||||||
"got": "^11.5.1",
|
|
||||||
"http-server": "^0.12.3",
|
"http-server": "^0.12.3",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"qrcode-terminal": "^0.12.0",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
|
|
151
shell/code.sh
151
shell/code.sh
|
@ -1,151 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
## 导入通用变量与函数
|
|
||||||
dir_shell=/ql/shell
|
|
||||||
. $dir_shell/share.sh
|
|
||||||
|
|
||||||
## 生成pt_pin清单
|
|
||||||
gen_pt_pin_array() {
|
|
||||||
local tmp1 tmp2 i pt_pin_temp
|
|
||||||
for ((user_num = 1; user_num <= $user_sum; user_num++)); do
|
|
||||||
tmp1=Cookie$user_num
|
|
||||||
tmp2=${!tmp1}
|
|
||||||
i=$(($user_num - 1))
|
|
||||||
pt_pin_temp=$(echo $tmp2 | perl -pe "{s|.*pt_pin=([^; ]+)(?=;?).*|\1|; s|%|\\\x|g}")
|
|
||||||
[[ $pt_pin_temp == *\\x* ]] && pt_pin[i]=$(printf $pt_pin_temp) || pt_pin[i]=$pt_pin_temp
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
## 导出互助码的通用程序,$1:去掉后缀的脚本名称,$2:config.sh中的后缀,$3:活动中文名称
|
|
||||||
export_codes_sub() {
|
|
||||||
local task_name=$1
|
|
||||||
local config_name=$2
|
|
||||||
local chinese_name=$3
|
|
||||||
local config_name_my=My$config_name
|
|
||||||
local config_name_for_other=ForOther$config_name
|
|
||||||
local i j k m n pt_pin_in_log code tmp_grep tmp_my_code tmp_for_other user_num random_num_list
|
|
||||||
if cd $dir_log/$task_name &>/dev/null && [[ $(ls) ]]; then
|
|
||||||
## 寻找所有互助码以及对应的pt_pin
|
|
||||||
i=0
|
|
||||||
pt_pin_in_log=()
|
|
||||||
code=()
|
|
||||||
pt_pin_and_code=$(ls -r *.log | xargs awk -v var="的$chinese_name好友互助码" 'BEGIN{FS="[( )】]+"; OFS="&"} $3~var {print $2,$4}')
|
|
||||||
for line in $pt_pin_and_code; do
|
|
||||||
pt_pin_in_log[i]=$(echo $line | awk -F "&" '{print $1}')
|
|
||||||
code[i]=$(echo $line | awk -F "&" '{print $2}')
|
|
||||||
let i++
|
|
||||||
done
|
|
||||||
|
|
||||||
## 输出My系列变量
|
|
||||||
if [[ ${#code[*]} -gt 0 ]]; then
|
|
||||||
for ((m = 0; m < ${#pt_pin[*]}; m++)); do
|
|
||||||
tmp_my_code=""
|
|
||||||
j=$((m + 1))
|
|
||||||
for ((n = 0; n < ${#code[*]}; n++)); do
|
|
||||||
if [[ ${pt_pin[m]} == ${pt_pin_in_log[n]} ]]; then
|
|
||||||
tmp_my_code=${code[n]}
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "$config_name_my$j='$tmp_my_code'"
|
|
||||||
done
|
|
||||||
else
|
|
||||||
echo "## 从日志中未找到任何互助码"
|
|
||||||
fi
|
|
||||||
|
|
||||||
## 输出ForOther系列变量
|
|
||||||
if [[ ${#code[*]} -gt 0 ]]; then
|
|
||||||
echo
|
|
||||||
case $HelpType in
|
|
||||||
0) ## 全部一致
|
|
||||||
tmp_for_other=""
|
|
||||||
for ((m = 0; m < ${#pt_pin[*]}; m++)); do
|
|
||||||
j=$((m + 1))
|
|
||||||
tmp_for_other="$tmp_for_other@\${$config_name_my$j}"
|
|
||||||
done
|
|
||||||
echo "${config_name_for_other}1=\"$tmp_for_other\"" | perl -pe "s|($config_name_for_other\d+=\")@|\1|"
|
|
||||||
for ((m = 1; m < ${#pt_pin[*]}; m++)); do
|
|
||||||
j=$((m + 1))
|
|
||||||
echo "$config_name_for_other$j=\"\${${config_name_for_other}1}\""
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
|
|
||||||
1) ## 均等助力
|
|
||||||
for ((m = 0; m < ${#pt_pin[*]}; m++)); do
|
|
||||||
tmp_for_other=""
|
|
||||||
j=$((m + 1))
|
|
||||||
for ((n = $m; n < $(($user_sum + $m)); n++)); do
|
|
||||||
[[ $m -eq $n ]] && continue
|
|
||||||
if [[ $((n + 1)) -le $user_sum ]]; then
|
|
||||||
k=$((n + 1))
|
|
||||||
else
|
|
||||||
k=$((n + 1 - $user_sum))
|
|
||||||
fi
|
|
||||||
tmp_for_other="$tmp_for_other@\${$config_name_my$k}"
|
|
||||||
done
|
|
||||||
echo "$config_name_for_other$j=\"$tmp_for_other\"" | perl -pe "s|($config_name_for_other\d+=\")@|\1|"
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
|
|
||||||
2) ## 本套脚本内账号间随机顺序助力
|
|
||||||
for ((m = 0; m < ${#pt_pin[*]}; m++)); do
|
|
||||||
tmp_for_other=""
|
|
||||||
random_num_list=$(seq $user_sum | sort -R)
|
|
||||||
j=$((m + 1))
|
|
||||||
for n in $random_num_list; do
|
|
||||||
[[ $j -eq $n ]] && continue
|
|
||||||
tmp_for_other="$tmp_for_other@\${$config_name_my$n}"
|
|
||||||
done
|
|
||||||
echo "$config_name_for_other$j=\"$tmp_for_other\"" | perl -pe "s|($config_name_for_other\d+=\")@|\1|"
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
|
|
||||||
*) ## 按编号优先
|
|
||||||
for ((m = 0; m < ${#pt_pin[*]}; m++)); do
|
|
||||||
tmp_for_other=""
|
|
||||||
j=$((m + 1))
|
|
||||||
for ((n = 0; n < ${#pt_pin[*]}; n++)); do
|
|
||||||
[[ $m -eq $n ]] && continue
|
|
||||||
k=$((n + 1))
|
|
||||||
tmp_for_other="$tmp_for_other@\${$config_name_my$k}"
|
|
||||||
done
|
|
||||||
echo "$config_name_for_other$j=\"$tmp_for_other\"" | perl -pe "s|($config_name_for_other\d+=\")@|\1|"
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "## 未运行过 $task_name.js 脚本,未产生日志"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
## 汇总输出
|
|
||||||
export_all_codes() {
|
|
||||||
gen_pt_pin_array
|
|
||||||
echo -e "\n# 从日志提取互助码,编号和配置文件中Cookie编号完全对应,如果为空就是所有日志中都没有。\n\n# 即使某个MyXxx变量未赋值,也可以将其变量名填在ForOtherXxx中,jtask脚本会自动过滤空值。\n"
|
|
||||||
echo -n "# 你选择的互助码模板为:"
|
|
||||||
case $HelpType in
|
|
||||||
0)
|
|
||||||
echo "所有账号助力码全部一致。"
|
|
||||||
;;
|
|
||||||
1)
|
|
||||||
echo "所有账号机会均等助力。"
|
|
||||||
;;
|
|
||||||
2)
|
|
||||||
echo "本套脚本内账号间随机顺序助力。"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "按账号编号优先。"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
for ((i = 0; i < ${#name_js[*]}; i++)); do
|
|
||||||
echo -e "\n## ${name_chinese[i]}:"
|
|
||||||
export_codes_sub "${name_js[i]}" "${name_config[i]}" "${name_chinese[i]}"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
## 执行并写入日志
|
|
||||||
log_time=$(date "+%Y-%m-%d-%H-%M-%S")
|
|
||||||
log_path="$dir_code/$log_time.log"
|
|
||||||
make_dir "$dir_code"
|
|
||||||
export_all_codes | perl -pe "{s|京东种豆|种豆|; s|crazyJoy任务|疯狂的JOY|}" | tee $log_path
|
|
|
@ -18,7 +18,7 @@ ql_static_repo=$dir_repo/static
|
||||||
|
|
||||||
## 文件
|
## 文件
|
||||||
file_config_sample=$dir_sample/config.sample.sh
|
file_config_sample=$dir_sample/config.sample.sh
|
||||||
file_cookie=$dir_config/cookie.sh
|
file_env=$dir_config/env.sh
|
||||||
file_sharecode=$dir_config/sharecode.sh
|
file_sharecode=$dir_config/sharecode.sh
|
||||||
file_config_user=$dir_config/config.sh
|
file_config_user=$dir_config/config.sh
|
||||||
file_auth_sample=$dir_sample/auth.sample.json
|
file_auth_sample=$dir_sample/auth.sample.json
|
||||||
|
@ -53,15 +53,9 @@ original_name=(
|
||||||
## 导入配置文件
|
## 导入配置文件
|
||||||
import_config() {
|
import_config() {
|
||||||
[ -f $file_config_user ] && . $file_config_user
|
[ -f $file_config_user ] && . $file_config_user
|
||||||
user_sum=0
|
|
||||||
for line in $(cat $file_cookie); do
|
|
||||||
let user_sum+=1
|
|
||||||
eval Cookie${user_sum}="\"${line}\""
|
|
||||||
done
|
|
||||||
|
|
||||||
command_timeout_time=${CommandTimeoutTime:-"1h"}
|
command_timeout_time=${CommandTimeoutTime:-"1h"}
|
||||||
github_proxy_url=${GithubProxyUrl:-""}
|
github_proxy_url=${GithubProxyUrl:-""}
|
||||||
block_cookie=${TempBlockCookie:-""}
|
|
||||||
file_extensions=${RepoFileExtensions:-"js py"}
|
file_extensions=${RepoFileExtensions:-"js py"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,9 +155,9 @@ fix_config() {
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f $file_cookie ]; then
|
if [ ! -f $file_env ]; then
|
||||||
echo -e "检测到config配置目录下不存在cookie.sh,创建一个空文件用于初始化...\n"
|
echo -e "检测到config配置目录下不存在env.sh,创建一个空文件用于初始化...\n"
|
||||||
touch $file_cookie
|
touch $file_env
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -289,13 +283,8 @@ git_pull_scripts() {
|
||||||
cd $dir_current
|
cd $dir_current
|
||||||
}
|
}
|
||||||
|
|
||||||
init_env() {
|
|
||||||
TempBlockCookie=""
|
|
||||||
}
|
|
||||||
|
|
||||||
## 导入配置文件,检测平台,创建软连接,识别命令,修复配置文件
|
## 导入配置文件,检测平台,创建软连接,识别命令,修复配置文件
|
||||||
detect_termux
|
detect_termux
|
||||||
detect_macos
|
detect_macos
|
||||||
define_cmd
|
define_cmd
|
||||||
init_env
|
|
||||||
import_config $1
|
import_config $1
|
||||||
|
|
|
@ -5,41 +5,6 @@ dir_shell=/ql/shell
|
||||||
. $dir_shell/share.sh
|
. $dir_shell/share.sh
|
||||||
. $dir_shell/api.sh
|
. $dir_shell/api.sh
|
||||||
|
|
||||||
## 组合Cookie和互助码子程序,$1:要组合的内容
|
|
||||||
combine_sub() {
|
|
||||||
local what_combine=$1
|
|
||||||
local combined_all=""
|
|
||||||
local tmp1 tmp2
|
|
||||||
for ((i = 1; i <= $user_sum; i++)); do
|
|
||||||
for num in $block_cookie; do
|
|
||||||
[[ $i -eq $num ]] && continue 2
|
|
||||||
done
|
|
||||||
local tmp1=$what_combine$i
|
|
||||||
local tmp2=${!tmp1}
|
|
||||||
combined_all="$combined_all&$tmp2"
|
|
||||||
done
|
|
||||||
echo $combined_all | perl -pe "{s|^&||; s|^@+||; s|&@|&|g; s|@+&|&|g; s|@+|@|g; s|@+$||}"
|
|
||||||
}
|
|
||||||
|
|
||||||
## 正常依次运行时,组合所有账号的Cookie与互助码
|
|
||||||
combine_all() {
|
|
||||||
for ((i = 0; i < ${#env_name[*]}; i++)); do
|
|
||||||
result=$(combine_sub ${var_name[i]})
|
|
||||||
if [[ $result ]]; then
|
|
||||||
export ${env_name[i]}="$result"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
## 并发运行时,直接申明每个账号的Cookie与互助码,$1:用户Cookie编号
|
|
||||||
combine_one() {
|
|
||||||
local user_num=$1
|
|
||||||
for ((i = 0; i < ${#env_name[*]}; i++)); do
|
|
||||||
local tmp=${var_name[i]}$user_num
|
|
||||||
export ${env_name[i]}=${!tmp}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
## 选择python3还是node
|
## 选择python3还是node
|
||||||
define_program() {
|
define_program() {
|
||||||
local p1=$1
|
local p1=$1
|
||||||
|
@ -118,7 +83,6 @@ run_normal() {
|
||||||
random_delay
|
random_delay
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
combine_all
|
|
||||||
log_time=$(date "+%Y-%m-%d-%H-%M-%S")
|
log_time=$(date "+%Y-%m-%d-%H-%M-%S")
|
||||||
log_dir_tmp="${p1##*/}"
|
log_dir_tmp="${p1##*/}"
|
||||||
log_dir="$dir_log/${log_dir_tmp%%.*}"
|
log_dir="$dir_log/${log_dir_tmp%%.*}"
|
||||||
|
@ -131,18 +95,20 @@ run_normal() {
|
||||||
update_cron_status "\"$id\"" "1"
|
update_cron_status "\"$id\"" "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
## 并发执行,因为是并发,所以日志只能直接记录在日志文件中(日志文件以Cookie编号结尾),前台执行并发跑时不会输出日志
|
|
||||||
## 并发执行时,设定的 RandomDelay 不会生效,即所有任务立即执行
|
## 并发执行时,设定的 RandomDelay 不会生效,即所有任务立即执行
|
||||||
run_concurrent() {
|
run_concurrent() {
|
||||||
local p1=$1
|
local p1=$1
|
||||||
|
local p3=$3
|
||||||
|
local envs=$(eval echo "\$${p3}")
|
||||||
|
local array=(${envs//&/})
|
||||||
cd $dir_scripts
|
cd $dir_scripts
|
||||||
define_program "$p1"
|
define_program "$p1"
|
||||||
log_dir="$dir_log/${p1%%.*}"
|
log_dir="$dir_log/${p1%%.*}"
|
||||||
make_dir $log_dir
|
make_dir $log_dir
|
||||||
log_time=$(date "+%Y-%m-%d-%H-%M-%S.%N")
|
log_time=$(date "+%Y-%m-%d-%H-%M-%S.%N")
|
||||||
echo -e "\n各账号间已经在后台开始并发执行,前台不输入日志,日志直接写入文件中。\n"
|
echo -e "\n各账号间已经在后台开始并发执行,前台不输入日志,日志直接写入文件中。\n"
|
||||||
for ((user_num = 1; user_num <= $user_sum; user_num++)); do
|
for i in "${!array[@]}"; do
|
||||||
combine_one $user_num
|
export ${p3}=${array[i]}
|
||||||
log_path="$log_dir/${log_time}_${user_num}.log"
|
log_path="$log_dir/${log_time}_${user_num}.log"
|
||||||
timeout $command_timeout_time $which_program $p1 &>$log_path &
|
timeout $command_timeout_time $which_program $p1 &>$log_path &
|
||||||
done
|
done
|
||||||
|
@ -173,7 +139,7 @@ main() {
|
||||||
run_normal $1 $2
|
run_normal $1 $2
|
||||||
;;
|
;;
|
||||||
conc)
|
conc)
|
||||||
run_concurrent $1 $2
|
run_concurrent $1 $2 $3
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
run_else "$@"
|
run_else "$@"
|
||||||
|
|
|
@ -6,9 +6,9 @@ const titleMap: any = {
|
||||||
'/': '控制面板',
|
'/': '控制面板',
|
||||||
'/login': '登录',
|
'/login': '登录',
|
||||||
'/crontab': '定时任务',
|
'/crontab': '定时任务',
|
||||||
'/cookie': 'Session管理',
|
'/env': '环境变量',
|
||||||
'/config': '配置文件',
|
'/config': '配置文件',
|
||||||
'/diy': '自定义脚本',
|
'/script': '查看脚本',
|
||||||
'/diff': '对比工具',
|
'/diff': '对比工具',
|
||||||
'/log': '日志',
|
'/log': '日志',
|
||||||
'/setting': '系统设置',
|
'/setting': '系统设置',
|
||||||
|
|
|
@ -25,10 +25,10 @@ export default {
|
||||||
component: '@/pages/crontab/index',
|
component: '@/pages/crontab/index',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/cookie',
|
path: '/env',
|
||||||
name: 'Session管理',
|
name: '环境变量',
|
||||||
icon: <RadiusSettingOutlined />,
|
icon: <RadiusSettingOutlined />,
|
||||||
component: '@/pages/cookie/index',
|
component: '@/pages/env/index',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/config',
|
path: '/config',
|
||||||
|
@ -37,10 +37,10 @@ export default {
|
||||||
component: '@/pages/config/index',
|
component: '@/pages/config/index',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/diy',
|
path: '/script',
|
||||||
name: '自定义脚本',
|
name: '查看脚本',
|
||||||
icon: <FormOutlined />,
|
icon: <FormOutlined />,
|
||||||
component: '@/pages/diy/index',
|
component: '@/pages/script/index',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/diff',
|
path: '/diff',
|
||||||
|
|
|
@ -36,7 +36,7 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.session-wrapper {
|
.env-wrapper {
|
||||||
th {
|
th {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,15 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.config-wrapper {
|
||||||
|
.config-select {
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
.ant-page-header-heading-left {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.ant-pro-grid-content.wide {
|
.ant-pro-grid-content.wide {
|
||||||
.ant-pro-page-container-children-content {
|
.ant-pro-page-container-children-content {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
||||||
import { Button, message, Modal } from 'antd';
|
import { Button, message, Modal, TreeSelect } from 'antd';
|
||||||
import config from '@/utils/config';
|
import config from '@/utils/config';
|
||||||
import { PageContainer } from '@ant-design/pro-layout';
|
import { PageContainer } from '@ant-design/pro-layout';
|
||||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||||
|
@ -11,27 +11,42 @@ const Config = () => {
|
||||||
const [marginTop, setMarginTop] = useState(-72);
|
const [marginTop, setMarginTop] = useState(-72);
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState('');
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [title, setTitle] = useState('config.sh');
|
||||||
|
const [select, setSelect] = useState('config.sh');
|
||||||
|
const [data, setData] = useState<any[]>([]);
|
||||||
|
|
||||||
const getConfig = () => {
|
const getConfig = (name: string) => {
|
||||||
|
request.get(`${config.apiPrefix}configs/${name}`).then((data: any) => {
|
||||||
|
setValue(data.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFiles = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request
|
request
|
||||||
.get(`${config.apiPrefix}config/config`)
|
.get(`${config.apiPrefix}configs/files`)
|
||||||
.then((data: any) => {
|
.then((data: any) => {
|
||||||
setValue(data.data);
|
setData(data.data);
|
||||||
})
|
})
|
||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateConfig = () => {
|
const updateConfig = () => {
|
||||||
request
|
request
|
||||||
.post(`${config.apiPrefix}save`, {
|
.post(`${config.apiPrefix}configs/save`, {
|
||||||
data: { content: value, name: 'config.sh' },
|
data: { content: value, name: select },
|
||||||
})
|
})
|
||||||
.then((data: any) => {
|
.then((data: any) => {
|
||||||
message.success(data.msg);
|
message.success(data.msg);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSelect = (value: any, node: any) => {
|
||||||
|
setSelect(value);
|
||||||
|
setTitle(node.value);
|
||||||
|
getConfig(node.value);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (document.body.clientWidth < 768) {
|
if (document.body.clientWidth < 768) {
|
||||||
setWidth('auto');
|
setWidth('auto');
|
||||||
|
@ -42,14 +57,24 @@ const Config = () => {
|
||||||
setMarginLeft(0);
|
setMarginLeft(0);
|
||||||
setMarginTop(-72);
|
setMarginTop(-72);
|
||||||
}
|
}
|
||||||
getConfig();
|
getFiles();
|
||||||
|
getConfig('config.sh');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer
|
<PageContainer
|
||||||
className="ql-container-wrapper"
|
className="ql-container-wrapper config-wrapper"
|
||||||
title="config.sh"
|
title={title}
|
||||||
extra={[
|
extra={[
|
||||||
|
<TreeSelect
|
||||||
|
className="config-select"
|
||||||
|
value={select}
|
||||||
|
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
||||||
|
treeData={data}
|
||||||
|
key="value"
|
||||||
|
defaultValue="config.sh"
|
||||||
|
onSelect={onSelect}
|
||||||
|
/>,
|
||||||
<Button key="1" type="primary" onClick={updateConfig}>
|
<Button key="1" type="primary" onClick={updateConfig}>
|
||||||
保存
|
保存
|
||||||
</Button>,
|
</Button>,
|
||||||
|
|
|
@ -15,7 +15,7 @@ const Crontab = () => {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const getConfig = () => {
|
const getConfig = () => {
|
||||||
request.get(`${config.apiPrefix}config/config`).then((data) => {
|
request.get(`${config.apiPrefix}configs/config.sh`).then((data) => {
|
||||||
setValue(data.data);
|
setValue(data.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -23,7 +23,7 @@ const Crontab = () => {
|
||||||
const getSample = () => {
|
const getSample = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request
|
request
|
||||||
.get(`${config.apiPrefix}config/sample`)
|
.get(`${config.apiPrefix}config/config.sample.sh`)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setSample(data.data);
|
setSample(data.data);
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
|
||||||
import { Button, message, Modal } from 'antd';
|
|
||||||
import config from '@/utils/config';
|
|
||||||
import { PageContainer } from '@ant-design/pro-layout';
|
|
||||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
|
||||||
import { request } from '@/utils/http';
|
|
||||||
|
|
||||||
const Crontab = () => {
|
|
||||||
const [width, setWidth] = useState('100%');
|
|
||||||
const [marginLeft, setMarginLeft] = useState(0);
|
|
||||||
const [marginTop, setMarginTop] = useState(-72);
|
|
||||||
const [value, setValue] = useState('');
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
|
|
||||||
const getConfig = () => {
|
|
||||||
setLoading(true);
|
|
||||||
request
|
|
||||||
.get(`${config.apiPrefix}config/extra`)
|
|
||||||
.then((data) => {
|
|
||||||
setValue(data.data);
|
|
||||||
})
|
|
||||||
.finally(() => setLoading(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateConfig = () => {
|
|
||||||
request
|
|
||||||
.post(`${config.apiPrefix}save`, {
|
|
||||||
data: { content: value, name: 'extra.sh' },
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
message.success(data.msg);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (document.body.clientWidth < 768) {
|
|
||||||
setWidth('auto');
|
|
||||||
setMarginLeft(0);
|
|
||||||
setMarginTop(0);
|
|
||||||
} else {
|
|
||||||
setWidth('100%');
|
|
||||||
setMarginLeft(0);
|
|
||||||
setMarginTop(-72);
|
|
||||||
}
|
|
||||||
getConfig();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer
|
|
||||||
className="ql-container-wrapper"
|
|
||||||
title="extra.sh"
|
|
||||||
extra={[
|
|
||||||
<Button key="1" type="primary" onClick={updateConfig}>
|
|
||||||
保存
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
header={{
|
|
||||||
style: {
|
|
||||||
padding: '4px 16px 4px 15px',
|
|
||||||
position: 'sticky',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
zIndex: 20,
|
|
||||||
marginTop,
|
|
||||||
width,
|
|
||||||
marginLeft,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CodeMirror
|
|
||||||
value={value}
|
|
||||||
options={{
|
|
||||||
lineNumbers: true,
|
|
||||||
lineWrapping: true,
|
|
||||||
styleActiveLine: true,
|
|
||||||
matchBrackets: true,
|
|
||||||
mode: 'shell',
|
|
||||||
}}
|
|
||||||
onBeforeChange={(editor, data, value) => {
|
|
||||||
setValue(value);
|
|
||||||
}}
|
|
||||||
onChange={(editor, data, value) => {}}
|
|
||||||
/>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Crontab;
|
|
77
src/pages/env/editNameModal.tsx
vendored
Normal file
77
src/pages/env/editNameModal.tsx
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Modal, message, Input, Form } from 'antd';
|
||||||
|
import { request } from '@/utils/http';
|
||||||
|
import config from '@/utils/config';
|
||||||
|
|
||||||
|
const EditNameModal = ({
|
||||||
|
ids,
|
||||||
|
handleCancel,
|
||||||
|
visible,
|
||||||
|
}: {
|
||||||
|
ids?: string[];
|
||||||
|
visible: boolean;
|
||||||
|
handleCancel: () => void;
|
||||||
|
}) => {
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const handleOk = async (values: any) => {
|
||||||
|
console.log(values);
|
||||||
|
console.log(ids);
|
||||||
|
setLoading(true);
|
||||||
|
const { code, data } = await request.put(`${config.apiPrefix}envs/name`, {
|
||||||
|
data: {
|
||||||
|
ids,
|
||||||
|
name: values.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (code === 200) {
|
||||||
|
message.success('更新环境变量名称成功');
|
||||||
|
} else {
|
||||||
|
message.error(data);
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
handleCancel();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
form.resetFields();
|
||||||
|
}, [ids]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="修改环境变量名称"
|
||||||
|
visible={visible}
|
||||||
|
forceRender
|
||||||
|
onOk={() => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then((values) => {
|
||||||
|
handleOk(values);
|
||||||
|
})
|
||||||
|
.catch((info) => {
|
||||||
|
console.log('Validate Failed:', info);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onCancel={() => handleCancel()}
|
||||||
|
confirmLoading={loading}
|
||||||
|
destroyOnClose
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
name="edit_name_modal"
|
||||||
|
preserve={false}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
name="name"
|
||||||
|
rules={[{ required: true, message: '请输入新的环境变量名称' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入新的环境变量名称" />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditNameModal;
|
182
src/pages/cookie/index.tsx → src/pages/env/index.tsx
vendored
182
src/pages/cookie/index.tsx → src/pages/env/index.tsx
vendored
|
@ -19,8 +19,8 @@ import {
|
||||||
import config from '@/utils/config';
|
import config from '@/utils/config';
|
||||||
import { PageContainer } from '@ant-design/pro-layout';
|
import { PageContainer } from '@ant-design/pro-layout';
|
||||||
import { request } from '@/utils/http';
|
import { request } from '@/utils/http';
|
||||||
import QRCode from 'qrcode.react';
|
import EnvModal from './modal';
|
||||||
import CookieModal from './modal';
|
import EditNameModal from './editNameModal';
|
||||||
import { DndProvider, useDrag, useDrop } from 'react-dnd';
|
import { DndProvider, useDrag, useDrop } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
@ -28,17 +28,12 @@ import './index.less';
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
'未获取',
|
'已启用',
|
||||||
'正常',
|
|
||||||
'已禁用',
|
'已禁用',
|
||||||
'已失效',
|
|
||||||
'状态异常',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum StatusColor {
|
enum StatusColor {
|
||||||
'default',
|
|
||||||
'success',
|
'success',
|
||||||
'warning',
|
|
||||||
'error',
|
'error',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +101,7 @@ const DragableBodyRow = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Config = () => {
|
const Env = () => {
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '序号',
|
title: '序号',
|
||||||
|
@ -116,25 +111,17 @@ const Config = () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '昵称',
|
title: '名称',
|
||||||
dataIndex: 'nickname',
|
dataIndex: 'name',
|
||||||
key: 'nickname',
|
key: 'name',
|
||||||
align: 'center' as const,
|
align: 'center' as const,
|
||||||
width: '15%',
|
|
||||||
render: (text: string, record: any, index: number) => {
|
|
||||||
const match = record.value.match(/pt_pin=([^; ]+)(?=;?)/);
|
|
||||||
const val = (match && match[1]) || '未匹配用户名';
|
|
||||||
return (
|
|
||||||
<span style={{ cursor: 'text' }}>{record.nickname || val} </span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '值',
|
title: '值',
|
||||||
dataIndex: 'value',
|
dataIndex: 'value',
|
||||||
key: 'value',
|
key: 'value',
|
||||||
align: 'center' as const,
|
align: 'center' as const,
|
||||||
width: '50%',
|
width: '45%',
|
||||||
render: (text: string, record: any) => {
|
render: (text: string, record: any) => {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
|
@ -143,6 +130,7 @@ const Config = () => {
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
wordBreak: 'break-all',
|
wordBreak: 'break-all',
|
||||||
cursor: 'text',
|
cursor: 'text',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
|
@ -150,28 +138,24 @@ const Config = () => {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '备注',
|
||||||
|
dataIndex: 'remarks',
|
||||||
|
key: 'remarks',
|
||||||
|
align: 'center' as const,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
key: 'status',
|
key: 'status',
|
||||||
dataIndex: 'status',
|
dataIndex: 'status',
|
||||||
align: 'center' as const,
|
align: 'center' as const,
|
||||||
width: '15%',
|
width: 60,
|
||||||
render: (text: string, record: any, index: number) => {
|
render: (text: string, record: any, index: number) => {
|
||||||
return (
|
return (
|
||||||
<Space size="middle" style={{ cursor: 'text' }}>
|
<Space size="middle" style={{ cursor: 'text' }}>
|
||||||
<Tag
|
<Tag color={StatusColor[record.status]} style={{ marginRight: 0 }}>
|
||||||
color={StatusColor[record.status] || StatusColor[3]}
|
|
||||||
style={{ marginRight: 0 }}
|
|
||||||
>
|
|
||||||
{Status[record.status]}
|
{Status[record.status]}
|
||||||
</Tag>
|
</Tag>
|
||||||
{record.status !== Status.已禁用 && (
|
|
||||||
<Tooltip title="刷新">
|
|
||||||
<a onClick={() => refreshStatus(record, index)}>
|
|
||||||
<SyncOutlined />
|
|
||||||
</a>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -183,12 +167,12 @@ const Config = () => {
|
||||||
render: (text: string, record: any, index: number) => (
|
render: (text: string, record: any, index: number) => (
|
||||||
<Space size="middle">
|
<Space size="middle">
|
||||||
<Tooltip title="编辑">
|
<Tooltip title="编辑">
|
||||||
<a onClick={() => editCookie(record, index)}>
|
<a onClick={() => editEnv(record, index)}>
|
||||||
<EditOutlined />
|
<EditOutlined />
|
||||||
</a>
|
</a>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={record.status === Status.已禁用 ? '启用' : '禁用'}>
|
<Tooltip title={record.status === Status.已禁用 ? '启用' : '禁用'}>
|
||||||
<a onClick={() => enabledOrDisabledCookie(record, index)}>
|
<a onClick={() => enabledOrDisabledEnv(record, index)}>
|
||||||
{record.status === Status.已禁用 ? (
|
{record.status === Status.已禁用 ? (
|
||||||
<CheckCircleOutlined />
|
<CheckCircleOutlined />
|
||||||
) : (
|
) : (
|
||||||
|
@ -197,7 +181,7 @@ const Config = () => {
|
||||||
</a>
|
</a>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="删除">
|
<Tooltip title="删除">
|
||||||
<a onClick={() => deleteCookie(record, index)}>
|
<a onClick={() => deleteEnv(record, index)}>
|
||||||
<DeleteOutlined />
|
<DeleteOutlined />
|
||||||
</a>
|
</a>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -211,39 +195,27 @@ const Config = () => {
|
||||||
const [value, setValue] = useState<any[]>([]);
|
const [value, setValue] = useState<any[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||||
const [editedCookie, setEditedCookie] = useState();
|
const [isEditNameModalVisible, setIsEditNameModalVisible] = useState(false);
|
||||||
|
const [editedEnv, setEditedEnv] = useState();
|
||||||
const [selectedRowIds, setSelectedRowIds] = useState<string[]>([]);
|
const [selectedRowIds, setSelectedRowIds] = useState<string[]>([]);
|
||||||
|
|
||||||
const getCookies = () => {
|
const getEnvs = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request
|
request
|
||||||
.get(`${config.apiPrefix}cookies`)
|
.get(`${config.apiPrefix}envs`)
|
||||||
.then((data: any) => {
|
.then((data: any) => {
|
||||||
setValue(data.data);
|
setValue(data.data);
|
||||||
})
|
})
|
||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshStatus = (record: any, index: number) => {
|
const enabledOrDisabledEnv = (record: any, index: number) => {
|
||||||
request
|
|
||||||
.get(`${config.apiPrefix}cookies/${record._id}/refresh`)
|
|
||||||
.then(async (data: any) => {
|
|
||||||
if (data.data && data.data.value) {
|
|
||||||
(value as any).splice(index, 1, data.data);
|
|
||||||
setValue([...(value as any)] as any);
|
|
||||||
} else {
|
|
||||||
message.error('更新状态失败');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const enabledOrDisabledCookie = (record: any, index: number) => {
|
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: `确认${record.status === Status.已禁用 ? '启用' : '禁用'}`,
|
title: `确认${record.status === Status.已禁用 ? '启用' : '禁用'}`,
|
||||||
content: (
|
content: (
|
||||||
<>
|
<>
|
||||||
确认{record.status === Status.已禁用 ? '启用' : '禁用'}
|
确认{record.status === Status.已禁用 ? '启用' : '禁用'}
|
||||||
Cookie{' '}
|
Env{' '}
|
||||||
<Text style={{ wordBreak: 'break-all' }} type="warning">
|
<Text style={{ wordBreak: 'break-all' }} type="warning">
|
||||||
{record.value}
|
{record.value}
|
||||||
</Text>{' '}
|
</Text>{' '}
|
||||||
|
@ -253,7 +225,7 @@ const Config = () => {
|
||||||
onOk() {
|
onOk() {
|
||||||
request
|
request
|
||||||
.put(
|
.put(
|
||||||
`${config.apiPrefix}cookies/${
|
`${config.apiPrefix}envs/${
|
||||||
record.status === Status.已禁用 ? 'enable' : 'disable'
|
record.status === Status.已禁用 ? 'enable' : 'disable'
|
||||||
}`,
|
}`,
|
||||||
{
|
{
|
||||||
|
@ -284,22 +256,22 @@ const Config = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const addCookie = () => {
|
const addEnv = () => {
|
||||||
setEditedCookie(null as any);
|
setEditedEnv(null as any);
|
||||||
setIsModalVisible(true);
|
setIsModalVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const editCookie = (record: any, index: number) => {
|
const editEnv = (record: any, index: number) => {
|
||||||
setEditedCookie(record);
|
setEditedEnv(record);
|
||||||
setIsModalVisible(true);
|
setIsModalVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteCookie = (record: any, index: number) => {
|
const deleteEnv = (record: any, index: number) => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '确认删除',
|
title: '确认删除',
|
||||||
content: (
|
content: (
|
||||||
<>
|
<>
|
||||||
确认删除Cookie{' '}
|
确认删除Env{' '}
|
||||||
<Text style={{ wordBreak: 'break-all' }} type="warning">
|
<Text style={{ wordBreak: 'break-all' }} type="warning">
|
||||||
{record.value}
|
{record.value}
|
||||||
</Text>{' '}
|
</Text>{' '}
|
||||||
|
@ -308,7 +280,7 @@ const Config = () => {
|
||||||
),
|
),
|
||||||
onOk() {
|
onOk() {
|
||||||
request
|
request
|
||||||
.delete(`${config.apiPrefix}cookies`, { data: [record._id] })
|
.delete(`${config.apiPrefix}envs`, { data: [record._id] })
|
||||||
.then((data: any) => {
|
.then((data: any) => {
|
||||||
if (data.code === 200) {
|
if (data.code === 200) {
|
||||||
message.success('删除成功');
|
message.success('删除成功');
|
||||||
|
@ -326,25 +298,25 @@ const Config = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = (cookies?: any[]) => {
|
const handleCancel = (env?: any[]) => {
|
||||||
setIsModalVisible(false);
|
setIsModalVisible(false);
|
||||||
if (cookies && cookies.length > 0) {
|
handleEnv(env);
|
||||||
handleCookies(cookies);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCookies = (cookies: any[]) => {
|
const handleEditNameCancel = (env?: any[]) => {
|
||||||
|
setIsEditNameModalVisible(false);
|
||||||
|
getEnvs();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEnv = (env: any) => {
|
||||||
const result = [...value];
|
const result = [...value];
|
||||||
for (let i = 0; i < cookies.length; i++) {
|
const index = value.findIndex((x) => x._id === env._id);
|
||||||
const cookie = cookies[i];
|
if (index === -1) {
|
||||||
const index = value.findIndex((x) => x._id === cookie._id);
|
result.push(env);
|
||||||
if (index === -1) {
|
} else {
|
||||||
result.push(cookie);
|
result.splice(index, 1, {
|
||||||
} else {
|
...env,
|
||||||
result.splice(index, 1, {
|
});
|
||||||
...cookie,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
setValue(result);
|
setValue(result);
|
||||||
};
|
};
|
||||||
|
@ -366,7 +338,7 @@ const Config = () => {
|
||||||
newData.splice(hoverIndex, 0, dragRow);
|
newData.splice(hoverIndex, 0, dragRow);
|
||||||
setValue([...newData]);
|
setValue([...newData]);
|
||||||
request
|
request
|
||||||
.put(`${config.apiPrefix}cookies/${dragRow._id}/move`, {
|
.put(`${config.apiPrefix}envs/${dragRow._id}/move`, {
|
||||||
data: { fromIndex: dragIndex, toIndex: hoverIndex },
|
data: { fromIndex: dragIndex, toIndex: hoverIndex },
|
||||||
})
|
})
|
||||||
.then((data: any) => {
|
.then((data: any) => {
|
||||||
|
@ -387,18 +359,18 @@ const Config = () => {
|
||||||
onChange: onSelectChange,
|
onChange: onSelectChange,
|
||||||
};
|
};
|
||||||
|
|
||||||
const delCookies = () => {
|
const delEnvs = () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '确认删除',
|
title: '确认删除',
|
||||||
content: <>确认删除选中的Cookie吗</>,
|
content: <>确认删除选中的Env吗</>,
|
||||||
onOk() {
|
onOk() {
|
||||||
request
|
request
|
||||||
.delete(`${config.apiPrefix}cookies`, { data: selectedRowIds })
|
.delete(`${config.apiPrefix}envs`, { data: selectedRowIds })
|
||||||
.then((data: any) => {
|
.then((data: any) => {
|
||||||
if (data.code === 200) {
|
if (data.code === 200) {
|
||||||
message.success('批量删除成功');
|
message.success('批量删除成功');
|
||||||
setSelectedRowIds([]);
|
setSelectedRowIds([]);
|
||||||
getCookies();
|
getEnvs();
|
||||||
} else {
|
} else {
|
||||||
message.error(data);
|
message.error(data);
|
||||||
}
|
}
|
||||||
|
@ -410,18 +382,18 @@ const Config = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const operateCookies = (operationStatus: number) => {
|
const operateEnvs = (operationStatus: number) => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: `确认${OperationName[operationStatus]}`,
|
title: `确认${OperationName[operationStatus]}`,
|
||||||
content: <>确认{OperationName[operationStatus]}选中的Cookie吗</>,
|
content: <>确认{OperationName[operationStatus]}选中的Env吗</>,
|
||||||
onOk() {
|
onOk() {
|
||||||
request
|
request
|
||||||
.put(`${config.apiPrefix}cookies/${OperationPath[operationStatus]}`, {
|
.put(`${config.apiPrefix}envs/${OperationPath[operationStatus]}`, {
|
||||||
data: selectedRowIds,
|
data: selectedRowIds,
|
||||||
})
|
})
|
||||||
.then((data: any) => {
|
.then((data: any) => {
|
||||||
if (data.code === 200) {
|
if (data.code === 200) {
|
||||||
getCookies();
|
getEnvs();
|
||||||
} else {
|
} else {
|
||||||
message.error(data);
|
message.error(data);
|
||||||
}
|
}
|
||||||
|
@ -433,6 +405,10 @@ const Config = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const modifyName = () => {
|
||||||
|
setIsEditNameModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (document.body.clientWidth < 768) {
|
if (document.body.clientWidth < 768) {
|
||||||
setWidth('auto');
|
setWidth('auto');
|
||||||
|
@ -443,16 +419,16 @@ const Config = () => {
|
||||||
setMarginLeft(0);
|
setMarginLeft(0);
|
||||||
setMarginTop(-72);
|
setMarginTop(-72);
|
||||||
}
|
}
|
||||||
getCookies();
|
getEnvs();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer
|
<PageContainer
|
||||||
className="session-wrapper"
|
className="env-wrapper"
|
||||||
title="Session管理"
|
title="环境变量"
|
||||||
extra={[
|
extra={[
|
||||||
<Button key="2" type="primary" onClick={() => addCookie()}>
|
<Button key="2" type="primary" onClick={() => addEnv()}>
|
||||||
添加Cookie
|
添加Env
|
||||||
</Button>,
|
</Button>,
|
||||||
]}
|
]}
|
||||||
header={{
|
header={{
|
||||||
|
@ -473,20 +449,27 @@ const Config = () => {
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
style={{ marginBottom: 5 }}
|
style={{ marginBottom: 5 }}
|
||||||
onClick={delCookies}
|
onClick={modifyName}
|
||||||
|
>
|
||||||
|
批量修改变量名称
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
style={{ marginBottom: 5, marginLeft: 8 }}
|
||||||
|
onClick={delEnvs}
|
||||||
>
|
>
|
||||||
批量删除
|
批量删除
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => operateCookies(0)}
|
onClick={() => operateEnvs(0)}
|
||||||
style={{ marginLeft: 8, marginBottom: 5 }}
|
style={{ marginLeft: 8, marginBottom: 5 }}
|
||||||
>
|
>
|
||||||
批量启用
|
批量启用
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => operateCookies(1)}
|
onClick={() => operateEnvs(1)}
|
||||||
style={{ marginLeft: 8, marginRight: 8 }}
|
style={{ marginLeft: 8, marginRight: 8 }}
|
||||||
>
|
>
|
||||||
批量禁用
|
批量禁用
|
||||||
|
@ -516,13 +499,18 @@ const Config = () => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
<CookieModal
|
<EnvModal
|
||||||
visible={isModalVisible}
|
visible={isModalVisible}
|
||||||
handleCancel={handleCancel}
|
handleCancel={handleCancel}
|
||||||
cookie={editedCookie}
|
env={editedEnv}
|
||||||
|
/>
|
||||||
|
<EditNameModal
|
||||||
|
visible={isEditNameModalVisible}
|
||||||
|
handleCancel={handleEditNameCancel}
|
||||||
|
ids={selectedRowIds}
|
||||||
/>
|
/>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Config;
|
export default Env;
|
|
@ -3,12 +3,12 @@ import { Modal, message, Input, Form } from 'antd';
|
||||||
import { request } from '@/utils/http';
|
import { request } from '@/utils/http';
|
||||||
import config from '@/utils/config';
|
import config from '@/utils/config';
|
||||||
|
|
||||||
const CookieModal = ({
|
const EnvModal = ({
|
||||||
cookie,
|
env,
|
||||||
handleCancel,
|
handleCancel,
|
||||||
visible,
|
visible,
|
||||||
}: {
|
}: {
|
||||||
cookie?: any;
|
env?: any;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
handleCancel: (cks?: any[]) => void;
|
handleCancel: (cks?: any[]) => void;
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -16,42 +16,28 @@ const CookieModal = ({
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const handleOk = async (values: any) => {
|
const handleOk = async (values: any) => {
|
||||||
const cookies = values.value
|
|
||||||
.split('\n')
|
|
||||||
.map((x: any) => x.trim().replace(/\s/g, ''));
|
|
||||||
let flag = false;
|
|
||||||
for (const coo of cookies) {
|
|
||||||
if (!/pt_key=\S*;\s*pt_pin=\S*;\s*/.test(coo)) {
|
|
||||||
message.error(`${coo}格式有误`);
|
|
||||||
flag = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flag) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const method = cookie ? 'put' : 'post';
|
const method = env ? 'put' : 'post';
|
||||||
const payload = cookie ? { value: cookies[0], _id: cookie._id } : cookies;
|
const payload = env ? { ...values, _id: env._id } : values;
|
||||||
const { code, data } = await request[method](`${config.apiPrefix}cookies`, {
|
const { code, data } = await request[method](`${config.apiPrefix}envs`, {
|
||||||
data: payload,
|
data: payload,
|
||||||
});
|
});
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
message.success(cookie ? '更新Cookie成功' : '添加Cookie成功');
|
message.success(env ? '更新Env成功' : '添加Env成功');
|
||||||
} else {
|
} else {
|
||||||
message.error(data);
|
message.error(data);
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
handleCancel(cookie ? [data] : data);
|
handleCancel(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
}, [cookie]);
|
}, [env]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={cookie ? '编辑Cookie' : '新建Cookie'}
|
title={env ? '编辑Env' : '新建Env'}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
forceRender
|
forceRender
|
||||||
onOk={() => {
|
onOk={() => {
|
||||||
|
@ -71,29 +57,34 @@ const CookieModal = ({
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
name="form_in_modal"
|
name="env_modal"
|
||||||
preserve={false}
|
preserve={false}
|
||||||
initialValues={cookie}
|
initialValues={env}
|
||||||
>
|
>
|
||||||
|
<Form.Item
|
||||||
|
name="name"
|
||||||
|
label="名称"
|
||||||
|
rules={[{ required: true, message: '请输入环境变量名称' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入环境变量名称" />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="value"
|
name="value"
|
||||||
rules={[
|
label="值"
|
||||||
{ required: true, message: '请输入Cookie' },
|
rules={[{ required: true, message: '请输入环境变量值' }]}
|
||||||
{
|
|
||||||
pattern: /pt_key=\S*;\s*pt_pin=\S*;\s*/,
|
|
||||||
message: 'Cookie格式错误,注意分号(pt_key=***;pt_pin=***;)',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
rows={4}
|
rows={4}
|
||||||
autoSize={true}
|
autoSize={true}
|
||||||
placeholder="请输入cookie,可直接换行输入多个cookie"
|
placeholder="请输入环境变量值"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item name="remarks" label="备注">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CookieModal;
|
export default EnvModal;
|
37
src/pages/script/index.module.less
Normal file
37
src/pages/script/index.module.less
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
@import '~@/styles/variable.less';
|
||||||
|
|
||||||
|
.left-tree {
|
||||||
|
&-container {
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
height: calc(100vh - 128px);
|
||||||
|
height: calc(100vh - var(--vh-offset, 0px) - 128px);
|
||||||
|
width: @tree-width;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
&-scroller {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
&-search {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.log-wrapper {
|
||||||
|
.ant-pro-grid-content.wide .ant-pro-page-container-children-content {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror {
|
||||||
|
width: calc(100% - 32px - @tree-width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
170
src/pages/script/index.tsx
Normal file
170
src/pages/script/index.tsx
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
import { useState, useEffect, useCallback, Key } from 'react';
|
||||||
|
import { TreeSelect, Tree, Input } from 'antd';
|
||||||
|
import config from '@/utils/config';
|
||||||
|
import { PageContainer } from '@ant-design/pro-layout';
|
||||||
|
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||||
|
import { request } from '@/utils/http';
|
||||||
|
import styles from './index.module.less';
|
||||||
|
|
||||||
|
function getFilterData(keyword: string, data: any) {
|
||||||
|
const expandedKeys: string[] = [];
|
||||||
|
if (keyword) {
|
||||||
|
const tree: any = [];
|
||||||
|
data.forEach((item: any) => {
|
||||||
|
if (item.title.toLocaleLowerCase().includes(keyword)) {
|
||||||
|
tree.push(item);
|
||||||
|
expandedKeys.push(...item.children.map((x: any) => x.key));
|
||||||
|
} else {
|
||||||
|
const children: any[] = [];
|
||||||
|
(item.children || []).forEach((subItem: any) => {
|
||||||
|
if (subItem.title.toLocaleLowerCase().includes(keyword)) {
|
||||||
|
children.push(subItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (children.length > 0) {
|
||||||
|
tree.push({
|
||||||
|
...item,
|
||||||
|
children,
|
||||||
|
});
|
||||||
|
expandedKeys.push(...children.map((x) => x.key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { tree, expandedKeys };
|
||||||
|
}
|
||||||
|
return { tree: data, expandedKeys };
|
||||||
|
}
|
||||||
|
|
||||||
|
const Script = () => {
|
||||||
|
const [width, setWidth] = useState('100%');
|
||||||
|
const [marginLeft, setMarginLeft] = useState(0);
|
||||||
|
const [marginTop, setMarginTop] = useState(-72);
|
||||||
|
const [title, setTitle] = useState('请选择脚本文件');
|
||||||
|
const [value, setValue] = useState('请选择脚本文件');
|
||||||
|
const [select, setSelect] = useState();
|
||||||
|
const [data, setData] = useState<any[]>([]);
|
||||||
|
const [filterData, setFilterData] = useState<any[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [isPhone, setIsPhone] = useState(false);
|
||||||
|
|
||||||
|
const getScripts = () => {
|
||||||
|
request.get(`${config.apiPrefix}scripts/files`).then((data) => {
|
||||||
|
setData(data.data);
|
||||||
|
setFilterData(data.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDetail = (node: any) => {
|
||||||
|
setLoading(true);
|
||||||
|
request
|
||||||
|
.get(`${config.apiPrefix}scripts/${node.value}`)
|
||||||
|
.then((data) => {
|
||||||
|
setValue(data.data);
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSelect = (value: any, node: any) => {
|
||||||
|
console.log(value);
|
||||||
|
console.log(node);
|
||||||
|
setSelect(value);
|
||||||
|
setTitle(node.parent || node.value);
|
||||||
|
getDetail(node);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTreeSelect = useCallback((keys: Key[], e: any) => {
|
||||||
|
onSelect(keys[0], e.node);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onSearch = useCallback(
|
||||||
|
(e) => {
|
||||||
|
const keyword = e.target.value;
|
||||||
|
const { tree } = getFilterData(keyword.toLocaleLowerCase(), data);
|
||||||
|
setFilterData(tree);
|
||||||
|
},
|
||||||
|
[data, setFilterData],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (document.body.clientWidth < 768) {
|
||||||
|
setWidth('auto');
|
||||||
|
setMarginLeft(0);
|
||||||
|
setMarginTop(0);
|
||||||
|
setIsPhone(true);
|
||||||
|
} else {
|
||||||
|
setWidth('100%');
|
||||||
|
setMarginLeft(0);
|
||||||
|
setMarginTop(-72);
|
||||||
|
setIsPhone(false);
|
||||||
|
}
|
||||||
|
getScripts();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer
|
||||||
|
className="ql-container-wrapper log-wrapper"
|
||||||
|
title={title}
|
||||||
|
extra={
|
||||||
|
isPhone && [
|
||||||
|
<TreeSelect
|
||||||
|
className="log-select"
|
||||||
|
value={select}
|
||||||
|
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
||||||
|
treeData={data}
|
||||||
|
placeholder="请选择脚本文件"
|
||||||
|
showSearch
|
||||||
|
key="value"
|
||||||
|
onSelect={onSelect}
|
||||||
|
/>,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
header={{
|
||||||
|
style: {
|
||||||
|
padding: '4px 16px 4px 15px',
|
||||||
|
position: 'sticky',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
zIndex: 20,
|
||||||
|
marginTop,
|
||||||
|
width,
|
||||||
|
marginLeft,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={`${styles['log-container']}`}>
|
||||||
|
{!isPhone && (
|
||||||
|
<div className={styles['left-tree-container']}>
|
||||||
|
<Input.Search
|
||||||
|
className={styles['left-tree-search']}
|
||||||
|
onChange={onSearch}
|
||||||
|
></Input.Search>
|
||||||
|
<div className={styles['left-tree-scroller']}>
|
||||||
|
<Tree
|
||||||
|
className={styles['left-tree']}
|
||||||
|
treeData={filterData}
|
||||||
|
onSelect={onTreeSelect}
|
||||||
|
></Tree>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<CodeMirror
|
||||||
|
value={value}
|
||||||
|
options={{
|
||||||
|
lineNumbers: true,
|
||||||
|
lineWrapping: true,
|
||||||
|
styleActiveLine: true,
|
||||||
|
matchBrackets: true,
|
||||||
|
mode: 'shell',
|
||||||
|
readOnly: true,
|
||||||
|
}}
|
||||||
|
onBeforeChange={(editor, data, value) => {
|
||||||
|
setValue(value);
|
||||||
|
}}
|
||||||
|
onChange={(editor, data, value) => {}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Script;
|
|
@ -9,11 +9,11 @@ message.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) {
|
||||||
const message = error.data
|
const msg = error.data
|
||||||
? error.data.message || error.data
|
? error.data.message || error.data
|
||||||
: error.response.statusText;
|
: error.response.statusText;
|
||||||
if (error.response.status !== 401 && error.response.status !== 502) {
|
if (error.response.status !== 401 && error.response.status !== 502) {
|
||||||
message.error(message);
|
message.error(msg);
|
||||||
} else {
|
} else {
|
||||||
console.log(error.response);
|
console.log(error.response);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user