feat:init初始化
This commit is contained in:
parent
0026bced89
commit
41e40ab496
5
.gitignore
vendored
5
.gitignore
vendored
@ -102,3 +102,8 @@ dist
|
|||||||
|
|
||||||
# TernJS port file
|
# TernJS port file
|
||||||
.tern-port
|
.tern-port
|
||||||
|
|
||||||
|
|
||||||
|
sqliteHistory.json
|
||||||
|
mysqlHistory.json
|
||||||
|
database.db
|
20
.vscode/launch.json
vendored
Normal file
20
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
// 使用 IntelliSense 了解相关属性。
|
||||||
|
// 悬停以查看现有属性的描述。
|
||||||
|
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "pwa-node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Program",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}/dist/index.js",
|
||||||
|
"outFiles": [
|
||||||
|
"${workspaceFolder}/dist/**/*.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
29
api/ApplicationRuleApi.ts
Normal file
29
api/ApplicationRuleApi.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Context } from "koa";
|
||||||
|
import ApplicationRuleService from "../service/ApplicationRuleService";
|
||||||
|
import config from "../config";
|
||||||
|
|
||||||
|
const router = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取目录下的文件列表
|
||||||
|
*/
|
||||||
|
router["GET /applicationRule"] = async function (ctx: Context) {
|
||||||
|
ctx.body = await ApplicationRuleService.getAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新或者插入
|
||||||
|
*/
|
||||||
|
router['POST /applicationRule'] = async function (ctx: Context) {
|
||||||
|
ctx.body = await ApplicationRuleService.saveOrAdd(ctx.request.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
router["DELETE /applicationRule/:id"] = async function (ctx: Context) {
|
||||||
|
await ApplicationRuleService.deleteById(ctx.params.id);
|
||||||
|
ctx.body = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
export default router;
|
28
api/FileApi.ts
Normal file
28
api/FileApi.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Context } from "koa";
|
||||||
|
import FileService from "../service/FileService";
|
||||||
|
import config from "../config";
|
||||||
|
|
||||||
|
const router = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取目录下的文件列表
|
||||||
|
*/
|
||||||
|
router["GET /file/query"] = async function (ctx: Context) {
|
||||||
|
ctx.body = await FileService.readPath(ctx.query.path as string, ctx.query.showHidden === '1');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*是否windows
|
||||||
|
*/
|
||||||
|
router['GET /file/isWindows'] = async function (ctx:Context) {
|
||||||
|
ctx.body=config.isWindows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查路径是否存在
|
||||||
|
*/
|
||||||
|
router["GET /file/path/exist"] = async function (ctx: Context) {
|
||||||
|
ctx.body = await FileService.checkExist(ctx.query.path as string);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default router;
|
22
api/RenamerApi.ts
Normal file
22
api/RenamerApi.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Context } from "koa";
|
||||||
|
import RenamerService from "../service/RenamerService";
|
||||||
|
|
||||||
|
const router = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览文件修改后的状态
|
||||||
|
*/
|
||||||
|
router["POST /renamer/preview"] = async function (ctx: Context) {
|
||||||
|
ctx.body = await RenamerService.preview(ctx.request.body.fileList, ctx.request.body.ruleList);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交修改
|
||||||
|
*/
|
||||||
|
router["POST /renamer/submit"] = async function (ctx: Context) {
|
||||||
|
ctx.body = await RenamerService.rename(ctx.request.body.fileList, ctx.request.body.changedFileList);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default router;
|
45
config.ts
Normal file
45
config.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
//后台所在绝对路径
|
||||||
|
const rootPath = path.resolve(__dirname, '..');
|
||||||
|
|
||||||
|
let config = {
|
||||||
|
rootPath,
|
||||||
|
port: process.env.PORT ? parseInt(process.env.PORT) : 8089,
|
||||||
|
urlPrefix: '/openRenamer/api',
|
||||||
|
//是否为windows平台
|
||||||
|
isWindows: process.platform.toLocaleLowerCase().includes("win"),
|
||||||
|
//sqlite相关配置
|
||||||
|
sqlite: {
|
||||||
|
enable: false, //是否启用sqlite
|
||||||
|
//相对于项目根目录
|
||||||
|
filePath: "database.db",
|
||||||
|
//sql存放地址,用于执行sql
|
||||||
|
sqlFolder: "sqliteSqls"
|
||||||
|
},
|
||||||
|
//mysql相关配置
|
||||||
|
mysql: {
|
||||||
|
enable: true, //是否启用mysql
|
||||||
|
sqlFolder: "mysqlSqls",
|
||||||
|
connection: {
|
||||||
|
host: "localhost",
|
||||||
|
port: 3306,
|
||||||
|
user: "root",
|
||||||
|
password: "123456",
|
||||||
|
database: "qiezi",
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
bodyLimit: {
|
||||||
|
formLimit: '2mb',
|
||||||
|
urlencoded: true,
|
||||||
|
multipart: true,
|
||||||
|
formidable: {
|
||||||
|
uploadDir: path.join(rootPath, 'files', 'temp', 'uploads'),
|
||||||
|
keepExtenstions: true,
|
||||||
|
maxFieldsSize: 1024 * 1024
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
52
dao/ApplicationRuleDao.ts
Normal file
52
dao/ApplicationRuleDao.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import ErrorHelper from "../util/ErrorHelper";
|
||||||
|
import ApplicationRule from "../entity/dto/ApplicationRule";
|
||||||
|
import SqliteHelper from "../util/SqliteHelper";
|
||||||
|
|
||||||
|
export default class ApplicationRuleDao {
|
||||||
|
/**
|
||||||
|
* 查询所有
|
||||||
|
* @param obj
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
static async getAll(): Promise<Array<ApplicationRule>> {
|
||||||
|
let res = await SqliteHelper.pool.all('select id,createdDate,updatedDate,name,comment,content from application_rule');
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增
|
||||||
|
* @param obj
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
static async addOne(obj: ApplicationRule): Promise<number> {
|
||||||
|
let res = await SqliteHelper.pool.run('insert into application_rule(createdDate,updatedDate,name,comment,content) values(?,?,?,?,?)'
|
||||||
|
, obj.createdDate, obj.updatedDate, obj.name, obj.comment, obj.content);
|
||||||
|
return res.lastID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新
|
||||||
|
* @param obj
|
||||||
|
*/
|
||||||
|
static async updateOne(obj: ApplicationRule): Promise<void> {
|
||||||
|
let res = await SqliteHelper.pool.run('update application_rule set updatedDate=?,name=?,comment=?,content=? where id=?'
|
||||||
|
, obj.updatedDate, obj.name, obj.comment, obj.content, obj.id);
|
||||||
|
if (res.changes == 0) {
|
||||||
|
throw ErrorHelper.Error404("数据不存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
static async delete(id: number): Promise<void> {
|
||||||
|
let res = await SqliteHelper.pool.run('delete from application_rule where id=?', id);
|
||||||
|
if (res.changes == 0) {
|
||||||
|
throw ErrorHelper.Error404("数据不存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
23
entity/dto/ApplicationRule.ts
Normal file
23
entity/dto/ApplicationRule.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
export default class ApplicationRule {
|
||||||
|
/**
|
||||||
|
创建时间
|
||||||
|
*/
|
||||||
|
createdDate: number;
|
||||||
|
/**
|
||||||
|
更新时间
|
||||||
|
*/
|
||||||
|
updatedDate: number;
|
||||||
|
id: number;
|
||||||
|
/**
|
||||||
|
名称
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
说明
|
||||||
|
*/
|
||||||
|
comment: string;
|
||||||
|
/**
|
||||||
|
规则内容,json序列化后
|
||||||
|
*/
|
||||||
|
content: string;
|
||||||
|
}
|
30
entity/po/HostPo.ts
Normal file
30
entity/po/HostPo.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
export default class HostPo {
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
id: number;
|
||||||
|
/**
|
||||||
|
* 标识key,用于表明身份
|
||||||
|
*/
|
||||||
|
key: string;
|
||||||
|
/**
|
||||||
|
* 密钥
|
||||||
|
*/
|
||||||
|
secret: string;
|
||||||
|
/**
|
||||||
|
* 网站名称
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* 网站域名
|
||||||
|
*/
|
||||||
|
host: string;
|
||||||
|
/**
|
||||||
|
* pv
|
||||||
|
*/
|
||||||
|
pv: number;
|
||||||
|
/**
|
||||||
|
* uv
|
||||||
|
*/
|
||||||
|
uv: number;
|
||||||
|
}
|
50
entity/vo/FileObj.ts
Normal file
50
entity/vo/FileObj.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import * as pathUtil from "path";
|
||||||
|
export default class FileObj {
|
||||||
|
/**
|
||||||
|
* 文件名
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* 拓展名
|
||||||
|
*/
|
||||||
|
expandName: string;
|
||||||
|
/**
|
||||||
|
* 去掉拓展名后的名字
|
||||||
|
*/
|
||||||
|
realName: string;
|
||||||
|
/**
|
||||||
|
* 所属路径
|
||||||
|
*/
|
||||||
|
path: string;
|
||||||
|
/**
|
||||||
|
* 是否文件夹
|
||||||
|
*/
|
||||||
|
isFolder: boolean;
|
||||||
|
/**
|
||||||
|
* 重命名错误原因
|
||||||
|
*/
|
||||||
|
errorMessage: string;
|
||||||
|
/**
|
||||||
|
* 创建时间ms
|
||||||
|
*/
|
||||||
|
createdTime: number;
|
||||||
|
/**
|
||||||
|
* 更新时间ms
|
||||||
|
*/
|
||||||
|
updatedTime: number;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(name: string, path, isFolder, createdTime, updatedTime) {
|
||||||
|
this.name = name;
|
||||||
|
this.expandName = pathUtil.extname(name);
|
||||||
|
if (this.expandName.length > 0) {
|
||||||
|
this.realName = name.substring(0, name.lastIndexOf("."));
|
||||||
|
} else {
|
||||||
|
this.realName = name;
|
||||||
|
}
|
||||||
|
this.path = path;
|
||||||
|
this.isFolder = isFolder;
|
||||||
|
this.createdTime = createdTime;
|
||||||
|
this.updatedTime = updatedTime;
|
||||||
|
}
|
||||||
|
}
|
27
entity/vo/RuleObj.ts
Normal file
27
entity/vo/RuleObj.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import DeleteRule from "./rules/DeleteRule";
|
||||||
|
import InsertRule from "./rules/InsertRule";
|
||||||
|
import SerializationRule from "./rules/SerializationRule";
|
||||||
|
|
||||||
|
export default class RuleObj {
|
||||||
|
type: string;
|
||||||
|
message: string;
|
||||||
|
/**
|
||||||
|
* 具体参数
|
||||||
|
*/
|
||||||
|
data: any;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.type = data.type;
|
||||||
|
this.message = data.message;
|
||||||
|
switch (this.type) {
|
||||||
|
case "delete":
|
||||||
|
this.data = new DeleteRule(data.data);
|
||||||
|
break;
|
||||||
|
case "insert":
|
||||||
|
this.data = new InsertRule(data.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.data = new SerializationRule(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
entity/vo/rules/DeleteRule.ts
Normal file
92
entity/vo/rules/DeleteRule.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import RuleInterface from "./RuleInterface";
|
||||||
|
import FileObj from "../FileObj";
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export default class DeleteRule implements RuleInterface {
|
||||||
|
/**
|
||||||
|
* 类别:deletePart:部分删除,deleteAll:全部删除
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
/**
|
||||||
|
* 部分删除时的开始信息
|
||||||
|
*/
|
||||||
|
start: DeleteRuleItem;
|
||||||
|
/**
|
||||||
|
* 部分删除时的结束信息
|
||||||
|
|
||||||
|
*/
|
||||||
|
end: DeleteRuleItem;
|
||||||
|
/**
|
||||||
|
* 忽略拓展名,true:忽略,false:不忽略
|
||||||
|
*/
|
||||||
|
ignorePostfix: boolean;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.type = data.type;
|
||||||
|
this.start = new DeleteRuleItem(data.start);
|
||||||
|
this.end = new DeleteRuleItem(data.end);
|
||||||
|
this.ignorePostfix = data.ignorePostfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
deal(file: FileObj): void {
|
||||||
|
if (this.type === 'deleteAll') {
|
||||||
|
file.realName = "";
|
||||||
|
if (!this.ignorePostfix) {
|
||||||
|
file.expandName = "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let str = file.realName + (this.ignorePostfix ? "" : file.expandName);
|
||||||
|
let startIndex = this.start.calIndex(str);
|
||||||
|
let endIndex = this.end.calIndex(str);
|
||||||
|
if (startIndex < 0 || endIndex < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
str = str.substring(0, startIndex) + str.substring(endIndex + 1);
|
||||||
|
if (this.ignorePostfix) {
|
||||||
|
file.realName = str;
|
||||||
|
} else {
|
||||||
|
file.expandName = path.extname(str);
|
||||||
|
if (file.expandName.length > 0) {
|
||||||
|
file.realName = str.substring(0, str.lastIndexOf("."));
|
||||||
|
} else {
|
||||||
|
file.realName = str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.name = file.realName + file.expandName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeleteRuleItem {
|
||||||
|
/**
|
||||||
|
* location:位置,text:文本,end:直到末尾
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
/**
|
||||||
|
* 对应的值
|
||||||
|
*/
|
||||||
|
value: string;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.type = data.type;
|
||||||
|
this.value = data.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算位置
|
||||||
|
*/
|
||||||
|
calIndex(str: string): number {
|
||||||
|
if (this.type === 'location') {
|
||||||
|
return parseInt(this.value) - 1;
|
||||||
|
} else if (this.type === 'text') {
|
||||||
|
return str.indexOf(this.value);
|
||||||
|
} else if (this.type === 'end') {
|
||||||
|
return str.length - 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
66
entity/vo/rules/InsertRule.ts
Normal file
66
entity/vo/rules/InsertRule.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import RuleInterface from "./RuleInterface";
|
||||||
|
import FileObj from "../FileObj";
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export default class InsertRule implements RuleInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入内容
|
||||||
|
*/
|
||||||
|
insertContent: string;
|
||||||
|
/**
|
||||||
|
* 操作类别,front:前缀,backend:后缀,at:位置,replace:替换当前文件名
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
/**
|
||||||
|
* 当type为at,时的位置,从1开始
|
||||||
|
*/
|
||||||
|
atInput: number;
|
||||||
|
/**
|
||||||
|
* 当type为at,时的方向,true:从右到左,false:从左到右
|
||||||
|
*/
|
||||||
|
atIsRightToleft: boolean;
|
||||||
|
/**
|
||||||
|
* 忽略拓展名,true:忽略,false:不忽略
|
||||||
|
*/
|
||||||
|
ignorePostfix: boolean;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.insertContent = data.insertContent;
|
||||||
|
this.type = data.type;
|
||||||
|
this.atInput = data.atInput;
|
||||||
|
this.atIsRightToleft = data.atIsRightToleft;
|
||||||
|
this.ignorePostfix = data.ignorePostfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
deal(file: FileObj): void {
|
||||||
|
let str = this.ignorePostfix ? file.realName : file.name;
|
||||||
|
switch (this.type) {
|
||||||
|
case "front":
|
||||||
|
str = this.insertContent + str;
|
||||||
|
break;
|
||||||
|
case "backend":
|
||||||
|
str = str + this.insertContent;
|
||||||
|
break;
|
||||||
|
case "at":
|
||||||
|
let index = this.atIsRightToleft ? str.length - this.atInput + 1 : this.atInput - 1;
|
||||||
|
str = str.substring(0, index) + this.insertContent + str.substring(index);
|
||||||
|
break;
|
||||||
|
case "replace":
|
||||||
|
str = this.insertContent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (this.ignorePostfix) {
|
||||||
|
file.realName = str;
|
||||||
|
} else {
|
||||||
|
file.expandName = path.extname(str);
|
||||||
|
if (file.expandName.length > 0) {
|
||||||
|
file.realName = str.substring(0, str.lastIndexOf("."));
|
||||||
|
} else {
|
||||||
|
file.realName = str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.name = file.realName + file.expandName;
|
||||||
|
}
|
||||||
|
}
|
6
entity/vo/rules/RuleInterface.ts
Normal file
6
entity/vo/rules/RuleInterface.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import FileObj from "../FileObj";
|
||||||
|
|
||||||
|
export default interface RuleInterface {
|
||||||
|
|
||||||
|
deal(file: FileObj): void;
|
||||||
|
}
|
80
entity/vo/rules/SerializationRule.ts
Normal file
80
entity/vo/rules/SerializationRule.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import RuleInterface from "./RuleInterface";
|
||||||
|
import FileObj from "../FileObj";
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export default class InsertRule implements RuleInterface {
|
||||||
|
/**
|
||||||
|
* 开始位置
|
||||||
|
*/
|
||||||
|
start: number;
|
||||||
|
/**
|
||||||
|
* 记录当前的值是多少
|
||||||
|
*/
|
||||||
|
currentIndex: number;
|
||||||
|
/**
|
||||||
|
* 增量
|
||||||
|
*/
|
||||||
|
increment: number;
|
||||||
|
/**
|
||||||
|
* 是否填充0
|
||||||
|
*/
|
||||||
|
addZero: boolean;
|
||||||
|
/**
|
||||||
|
* 填充后长度
|
||||||
|
*/
|
||||||
|
numLength: number;
|
||||||
|
/**
|
||||||
|
* 插入位置,front:前缀,backend:后缀,at:位置
|
||||||
|
*/
|
||||||
|
insertType: string;
|
||||||
|
/**
|
||||||
|
* 插入的位置
|
||||||
|
*/
|
||||||
|
insertValue: number;
|
||||||
|
/**
|
||||||
|
* 忽略拓展名
|
||||||
|
*/
|
||||||
|
ignorePostfix: boolean;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.start = data.start;
|
||||||
|
this.currentIndex = data.start;
|
||||||
|
this.increment = data.increment;
|
||||||
|
this.addZero = data.addZero;
|
||||||
|
this.numLength = data.numLength;
|
||||||
|
this.insertType = data.insertType;
|
||||||
|
this.insertValue = data.insertValue;
|
||||||
|
this.ignorePostfix = data.ignorePostfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
deal(file: FileObj): void {
|
||||||
|
let length = this.currentIndex.toString().length;
|
||||||
|
let numStr = (this.addZero && this.numLength > length ? "0".repeat(this.numLength - length) : "") + this.currentIndex;
|
||||||
|
let str = this.ignorePostfix ? file.realName : file.name;
|
||||||
|
switch (this.insertType) {
|
||||||
|
case "front":
|
||||||
|
str = numStr + str;
|
||||||
|
break;
|
||||||
|
case "backend":
|
||||||
|
str = str + numStr;
|
||||||
|
break;
|
||||||
|
case "at":
|
||||||
|
str = str.substring(0, this.insertValue - 1) + numStr + str.substring(this.insertValue - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.currentIndex += this.increment;
|
||||||
|
|
||||||
|
if (this.ignorePostfix) {
|
||||||
|
file.realName = str;
|
||||||
|
} else {
|
||||||
|
file.expandName = path.extname(str);
|
||||||
|
if (file.expandName.length > 0) {
|
||||||
|
file.realName = str.substring(0, str.lastIndexOf("."));
|
||||||
|
} else {
|
||||||
|
file.realName = str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.name = file.realName + file.expandName;
|
||||||
|
}
|
||||||
|
}
|
47
index.ts
Normal file
47
index.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import koa from "koa";
|
||||||
|
import Router from "koa-router";
|
||||||
|
import koaBody from "koa-body";
|
||||||
|
import * as path from "path";
|
||||||
|
import RouterMW from "./middleware/controllerEngine";
|
||||||
|
|
||||||
|
import config from "./config";
|
||||||
|
import handleError from "./middleware/handleError";
|
||||||
|
import init from "./middleware/init";
|
||||||
|
import SqliteUtil from './util/SqliteHelper';
|
||||||
|
import log from './util/LogUtil';
|
||||||
|
import { MysqlUtil } from "./util/MysqlHelper";
|
||||||
|
|
||||||
|
|
||||||
|
log.info(config);
|
||||||
|
const app = new koa();
|
||||||
|
|
||||||
|
let router = new Router({
|
||||||
|
prefix: config.urlPrefix
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(require('koa-static')(path.join(config.rootPath, 'static')));
|
||||||
|
|
||||||
|
//表单解析
|
||||||
|
app.use(koaBody(config.bodyLimit));
|
||||||
|
//请求预处理
|
||||||
|
app.use(init);
|
||||||
|
//错误处理
|
||||||
|
app.use(handleError);
|
||||||
|
|
||||||
|
app.use(RouterMW(router, path.join(config.rootPath, "dist/api")));
|
||||||
|
(async () => {
|
||||||
|
//初始化sqlite
|
||||||
|
if (config.sqlite.enable) {
|
||||||
|
await SqliteUtil.createPool();
|
||||||
|
}
|
||||||
|
//初始化mysql
|
||||||
|
if (config.mysql.enable) {
|
||||||
|
await MysqlUtil.createPool();
|
||||||
|
}
|
||||||
|
app.listen(config.port);
|
||||||
|
log.info(`server listened `, config.port);
|
||||||
|
})();
|
||||||
|
|
||||||
|
app.on("error", (error) => {
|
||||||
|
console.error(error);
|
||||||
|
})
|
50
middleware/controllerEngine.ts
Normal file
50
middleware/controllerEngine.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import * as fs from 'fs-extra';
|
||||||
|
import * as path from 'path';
|
||||||
|
import log from '../util/LogUtil';
|
||||||
|
|
||||||
|
async function addMapping(router, filePath: string) {
|
||||||
|
let mapping = require(filePath).default;
|
||||||
|
for (let url in mapping) {
|
||||||
|
if (url.startsWith('GET ')) {
|
||||||
|
let temp = url.substring(4);
|
||||||
|
router.get(temp, mapping[url]);
|
||||||
|
log.info(`----GET:${temp}`);
|
||||||
|
} else if (url.startsWith('POST ')) {
|
||||||
|
let temp = url.substring(5);
|
||||||
|
router.post(temp, mapping[url]);
|
||||||
|
log.info(`----POST:${temp}`);
|
||||||
|
} else if (url.startsWith('PUT ')) {
|
||||||
|
let temp = url.substring(4);
|
||||||
|
router.put(temp, mapping[url]);
|
||||||
|
log.info(`----PUT:${temp}`);
|
||||||
|
} else if (url.startsWith('DELETE ')) {
|
||||||
|
let temp = url.substring(7);
|
||||||
|
router.delete(temp, mapping[url]);
|
||||||
|
log.info(`----DELETE: ${temp}`);
|
||||||
|
} else {
|
||||||
|
log.info(`xxxxx无效路径:${url}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addControllers(router, filePath) {
|
||||||
|
let files = fs.readdirSync(filePath).filter(item => item.endsWith('.js'));
|
||||||
|
for (let index in files) {
|
||||||
|
let element = files[index];
|
||||||
|
let temp = path.join(filePath, element);
|
||||||
|
let state = fs.statSync(temp);
|
||||||
|
if (state.isDirectory()) {
|
||||||
|
addControllers(router, temp);
|
||||||
|
} else {
|
||||||
|
if (!temp.endsWith('Helper.js')) {
|
||||||
|
log.info('\n--开始处理: ' + element + '路由');
|
||||||
|
addMapping(router, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function engine(router, folder) {
|
||||||
|
addControllers(router, folder);
|
||||||
|
return router.routes();
|
||||||
|
}
|
17
middleware/handleError.ts
Normal file
17
middleware/handleError.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import log from '../util/LogUtil';
|
||||||
|
|
||||||
|
let f = async (ctx, next) => {
|
||||||
|
try {
|
||||||
|
await next();
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.status != undefined) {
|
||||||
|
ctx.status = error.status;
|
||||||
|
} else {
|
||||||
|
ctx.status = 500;
|
||||||
|
}
|
||||||
|
ctx.body = error.message;
|
||||||
|
log.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default f;
|
51
middleware/init.ts
Normal file
51
middleware/init.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import config from '../config';
|
||||||
|
import ObjectHelper from '../util/ObjectOperate';
|
||||||
|
|
||||||
|
let doSuccess = (ctx, body) => {
|
||||||
|
switch (ctx.method) {
|
||||||
|
case 'GET':
|
||||||
|
ctx.status = body !== null ? 200 : 204;
|
||||||
|
ctx.body = body;
|
||||||
|
break;
|
||||||
|
case 'POST':
|
||||||
|
ctx.status = body !== null ? 201 : 204;
|
||||||
|
ctx.body = body;
|
||||||
|
break;
|
||||||
|
case 'PUT':
|
||||||
|
ctx.status = body !== null ? 200 : 204;
|
||||||
|
ctx.body = body;
|
||||||
|
break;
|
||||||
|
case 'DELETE':
|
||||||
|
ctx.status = body !== null ? 200 : 204;
|
||||||
|
ctx.body = body;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Object.assign(ctx.allParams, ctx.params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async (ctx, next) => {
|
||||||
|
//跨域
|
||||||
|
ctx.set("Access-Control-Allow-Origin", "*");
|
||||||
|
ctx.set("Access-Control-Allow-Headers", "X-Requested-With");
|
||||||
|
ctx.set("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
|
||||||
|
ctx.set("X-Powered-By", ' 3.2.1');
|
||||||
|
ctx.set("Content-Type", "application/json;charset=utf-8");
|
||||||
|
//合并请求参数到allParams
|
||||||
|
let objs = new Array();
|
||||||
|
if (ctx.method == "POST" || ctx.method == "PUT") {
|
||||||
|
if (ctx.request.body) {
|
||||||
|
if (ctx.request.body.fields != undefined && ctx.request.body.files != undefined) {
|
||||||
|
objs.push(ctx.request.body.fields, ctx.request.body.files);
|
||||||
|
} else {
|
||||||
|
objs.push(ctx.request.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objs.push(ctx.query);
|
||||||
|
ctx.allParams = ObjectHelper.combineObject(objs);
|
||||||
|
|
||||||
|
ctx.onSuccess = function (body = null) {
|
||||||
|
doSuccess(ctx, body);
|
||||||
|
};
|
||||||
|
await next();
|
||||||
|
}
|
29
mysqlSqls/V001_init.sql
Normal file
29
mysqlSqls/V001_init.sql
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
CREATE TABLE qiezi.host (
|
||||||
|
id INT auto_increment NOT NULL,
|
||||||
|
`key` CHAR(32) NOT NULL COMMENT 'key,用于标识',
|
||||||
|
secret char(32) NOT NULL COMMENT '密钥',
|
||||||
|
name varchar(100) NOT NULL COMMENT '网站名',
|
||||||
|
host varchar(100) NOT NULL COMMENT '网站域名(不含http前缀以及路径)',
|
||||||
|
pv INT UNSIGNED DEFAULT 0 NOT NULL,
|
||||||
|
uv varchar(100) DEFAULT 0 NOT NULL,
|
||||||
|
CONSTRAINT host_pk PRIMARY KEY (id)
|
||||||
|
)
|
||||||
|
ENGINE=InnoDB
|
||||||
|
DEFAULT CHARSET=utf8mb4
|
||||||
|
COLLATE=utf8mb4_0900_ai_ci
|
||||||
|
COMMENT='host表,记录某个站点总的pv,uv数据';
|
||||||
|
|
||||||
|
CREATE TABLE qiezi.path_date(
|
||||||
|
id INT auto_increment NOT NULL,
|
||||||
|
`key` CHAR(32) NOT NULL COMMENT 'key,用于标识',
|
||||||
|
secret char(32) NOT NULL COMMENT '密钥',
|
||||||
|
name varchar(100) NOT NULL COMMENT '网站名',
|
||||||
|
host varchar(100) NOT NULL COMMENT '网站域名(不含http前缀以及路径)',
|
||||||
|
pv INT UNSIGNED DEFAULT 0 NOT NULL,
|
||||||
|
uv varchar(100) DEFAULT 0 NOT NULL,
|
||||||
|
CONSTRAINT host_pk PRIMARY KEY (id)
|
||||||
|
)
|
||||||
|
ENGINE=InnoDB
|
||||||
|
DEFAULT CHARSET=utf8mb4
|
||||||
|
COLLATE=utf8mb4_0900_ai_ci
|
||||||
|
COMMENT='host表,记录某个站点总的pv,uv数据';
|
30
package.json
Normal file
30
package.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "nas_backup",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "文件备份用",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "fxb",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/fs-extra": "^5.0.4",
|
||||||
|
"@types/koa": "^2.0.47",
|
||||||
|
"@types/node": "^11.13.4",
|
||||||
|
"axios": "^0.21.1",
|
||||||
|
"fs-extra": "^7.0.0",
|
||||||
|
"koa": "^2.13.4",
|
||||||
|
"koa-body": "^4.2.0",
|
||||||
|
"koa-router": "^10.1.1",
|
||||||
|
"koa-static": "^5.0.0",
|
||||||
|
"koa2-cors": "^2.0.6",
|
||||||
|
"log4js": "^6.3.0",
|
||||||
|
"moment": "^2.22.2",
|
||||||
|
"mysql2": "^2.3.3",
|
||||||
|
"sqlite": "^4.0.23",
|
||||||
|
"sqlite3": "^5.0.2",
|
||||||
|
"uuid": "^3.3.2",
|
||||||
|
"winston": "^3.1.0"
|
||||||
|
}
|
||||||
|
}
|
33
service/ApplicationRuleService.ts
Normal file
33
service/ApplicationRuleService.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import config from '../config';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs-extra';
|
||||||
|
import ApplicationRule from '../entity/dto/ApplicationRule';
|
||||||
|
import ApplicationRuleDao from '../dao/ApplicationRuleDao';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationRuleService {
|
||||||
|
static async saveOrAdd(ruleObj: ApplicationRule): Promise<ApplicationRule> {
|
||||||
|
ruleObj.updatedDate = Date.now();
|
||||||
|
if (!ruleObj.id) {
|
||||||
|
//说明是新增
|
||||||
|
ruleObj.createdDate = Date.now();
|
||||||
|
ruleObj.id = await ApplicationRuleDao.addOne(ruleObj);
|
||||||
|
} else {
|
||||||
|
//说明是修改
|
||||||
|
await ApplicationRuleDao.updateOne(ruleObj);
|
||||||
|
}
|
||||||
|
return ruleObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getAll(): Promise<Array<ApplicationRule>> {
|
||||||
|
return await ApplicationRuleDao.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async deleteById(id: number): Promise<void> {
|
||||||
|
await ApplicationRuleDao.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ApplicationRuleService;
|
58
service/FileService.ts
Normal file
58
service/FileService.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import config from '../config';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs-extra';
|
||||||
|
|
||||||
|
import ProcessHelper from '../util/ProcesHelper';
|
||||||
|
import FileObj from '../vo/FileObj';
|
||||||
|
|
||||||
|
class FileService {
|
||||||
|
static async readPath(pathStr: string, showHidden: boolean): Promise<Array<FileObj>> {
|
||||||
|
pathStr = decodeURIComponent(pathStr);
|
||||||
|
let fileList = new Array();
|
||||||
|
if (pathStr.trim().length == 0) {
|
||||||
|
//获取根目录路径
|
||||||
|
if (config.isWindows) {
|
||||||
|
//windows下
|
||||||
|
let std: string = (await ProcessHelper.exec('wmic logicaldisk get caption')).replace('Caption', '');
|
||||||
|
fileList = std
|
||||||
|
.split('\r\n')
|
||||||
|
.filter((item) => item.trim().length > 0)
|
||||||
|
.map((item) => item.trim());
|
||||||
|
} else {
|
||||||
|
//linux下
|
||||||
|
pathStr = '/';
|
||||||
|
fileList = await fs.readdir(pathStr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileList = await fs.readdir(pathStr);
|
||||||
|
}
|
||||||
|
let folderList: Array<FileObj> = new Array();
|
||||||
|
let files: Array<FileObj> = new Array();
|
||||||
|
for (let index in fileList) {
|
||||||
|
try {
|
||||||
|
let stat = await fs.stat(path.join(pathStr, fileList[index]));
|
||||||
|
if (fileList[index].startsWith('.')) {
|
||||||
|
if (showHidden) {
|
||||||
|
(stat.isDirectory() ? folderList : files).push(
|
||||||
|
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(stat.isDirectory() ? folderList : files).push(
|
||||||
|
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
folderList.sort((a, b) => a.name.localeCompare(b.name)).push(...files.sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
return folderList;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async checkExist(pathStr: string) {
|
||||||
|
return await fs.pathExists(pathStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FileService;
|
41
service/RenamerService.ts
Normal file
41
service/RenamerService.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import config from '../config';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs-extra';
|
||||||
|
|
||||||
|
import FileObj from '../vo/FileObj';
|
||||||
|
import RuleObj from '../vo/RuleObj';
|
||||||
|
import DeleteRule from '../vo/rules/DeleteRule';
|
||||||
|
import RuleInterface from '../vo/rules/RuleInterface';
|
||||||
|
|
||||||
|
|
||||||
|
class RenamerService {
|
||||||
|
static async preview(fileList: Array<FileObj>, ruleList: Array<any>): Promise<Array<FileObj>> {
|
||||||
|
let ruleObjs = ruleList.map(item => new RuleObj(item));
|
||||||
|
let newNameSet: Set<string> = new Set<string>();
|
||||||
|
for (let i in fileList) {
|
||||||
|
let obj = fileList[i];
|
||||||
|
ruleObjs.forEach(item => (item.data as RuleInterface).deal(obj));
|
||||||
|
if (newNameSet.has(obj.name)) {
|
||||||
|
obj.errorMessage = "重名";
|
||||||
|
}
|
||||||
|
newNameSet.add(obj.name);
|
||||||
|
}
|
||||||
|
return fileList;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async rename(fileList: Array<FileObj>, changedFileList: Array<FileObj>) {
|
||||||
|
for (let i in fileList) {
|
||||||
|
let old = fileList[i];
|
||||||
|
let oldPath = path.join(fileList[i].path, fileList[i].name);
|
||||||
|
let newPath = path.join(changedFileList[i].path, changedFileList[i].name);
|
||||||
|
if ((await fs.pathExists(newPath))) {
|
||||||
|
throw new Error("此路径已存在:" + newPath);
|
||||||
|
}
|
||||||
|
await fs.rename(oldPath, newPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RenamerService;
|
0
static/.gitkeep
Normal file
0
static/.gitkeep
Normal file
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2017",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"module": "commonjs",
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"baseUrl":".",
|
||||||
|
"rootDir": "./",
|
||||||
|
"watch": false,
|
||||||
|
"strict": true,
|
||||||
|
"strictNullChecks": false,
|
||||||
|
"esModuleInterop": true
|
||||||
|
}
|
||||||
|
}
|
32
util/ErrorHelper.ts
Normal file
32
util/ErrorHelper.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
class ErrorHelper {
|
||||||
|
/**
|
||||||
|
* 返回一个自定义错误
|
||||||
|
* @param {String} message
|
||||||
|
* @param {Number} status
|
||||||
|
*/
|
||||||
|
static newError(message, status) {
|
||||||
|
return getError(message, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Error403(message){
|
||||||
|
return getError(message,403);
|
||||||
|
}
|
||||||
|
static Error404(message){
|
||||||
|
return getError(message,404);
|
||||||
|
}
|
||||||
|
static Error406(message){
|
||||||
|
return getError(message,406);
|
||||||
|
}
|
||||||
|
static Error400(message){
|
||||||
|
return getError(message,400);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let getError = (message, status) => {
|
||||||
|
let error = new Error(message);
|
||||||
|
error['status'] = status;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ErrorHelper;
|
9
util/LogUtil.ts
Normal file
9
util/LogUtil.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { getLogger, configure } from "log4js";
|
||||||
|
configure({
|
||||||
|
appenders: { cheese: { type: "console" } },
|
||||||
|
categories: { default: { appenders: ["cheese"], level: "info" } }
|
||||||
|
});
|
||||||
|
const logger = getLogger();
|
||||||
|
logger.level = "debug";
|
||||||
|
|
||||||
|
export default logger;
|
108
util/MysqlHelper.ts
Normal file
108
util/MysqlHelper.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import mysql from "mysql2/promise";
|
||||||
|
import config from '../config';
|
||||||
|
import * as fs from "fs-extra";
|
||||||
|
import * as path from 'path';
|
||||||
|
import log from '../util/LogUtil';
|
||||||
|
|
||||||
|
const HISTORY_NAME = "mysqlHistory.json";
|
||||||
|
|
||||||
|
interface Res {
|
||||||
|
rows: any;
|
||||||
|
fields: mysql.FieldPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MysqlUtil {
|
||||||
|
public static pool: mysql.Pool = null;
|
||||||
|
|
||||||
|
static async createPool() {
|
||||||
|
MysqlUtil.pool = await mysql.createPool(config.mysql.connection);
|
||||||
|
let basePath = path.join(config.rootPath, config.mysql.sqlFolder);
|
||||||
|
let hisPath = path.join(config.rootPath, HISTORY_NAME);
|
||||||
|
let history: Array<string>;
|
||||||
|
if (fs.existsSync(hisPath)) {
|
||||||
|
history = JSON.parse(await fs.readFile(hisPath, "utf-8"));
|
||||||
|
} else {
|
||||||
|
history = new Array();
|
||||||
|
}
|
||||||
|
//执行数据库
|
||||||
|
let files = (await fs.readdir(basePath)).sort((a, b) => a.localeCompare(b)).filter(item => !(item === HISTORY_NAME));
|
||||||
|
let error = null;
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
if (history.indexOf(files[i]) > -1) {
|
||||||
|
log.info("sql无需重复执行:", files[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let sqlLines = (await fs.readFile(path.join(basePath, files[i]), 'utf-8')).split(/[\r\n]/g);
|
||||||
|
try {
|
||||||
|
let sql = "";
|
||||||
|
for (let j = 0; j < sqlLines.length; j++) {
|
||||||
|
sql = sql + " " + sqlLines[j];
|
||||||
|
if (sqlLines[j].endsWith(";")) {
|
||||||
|
await MysqlUtil.pool.execute(sql);
|
||||||
|
sql = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("sql执行成功:", files[i]);
|
||||||
|
history.push(files[i]);
|
||||||
|
} catch (err) {
|
||||||
|
error = err;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await fs.writeFile(hisPath, JSON.stringify(history));
|
||||||
|
if (error != null) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getRows(sql: string, params: Array<any>, connection: mysql.PoolConnection = null): Promise<Array<any>> {
|
||||||
|
return (await MysqlUtil.execute(sql, params, connection)).rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async getRow(sql: string, params: Array<any>, connection: mysql.PoolConnection = null): Promise<any> {
|
||||||
|
let rows = (await MysqlUtil.execute(sql, params, connection)).rows;
|
||||||
|
return rows.length > 0 ? rows[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getSingle(sql: string, params: Array<any>, connection: mysql.PoolConnection = null): Promise<any> {
|
||||||
|
let rows = (await MysqlUtil.execute(sql, params, connection)).rows;
|
||||||
|
if (rows.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let row = rows[0];
|
||||||
|
return row[Object.keys(row)[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static async execute(sql: string, params: Array<any>, connection: mysql.PoolConnection = null): Promise<Res> {
|
||||||
|
let res: any = {};
|
||||||
|
if (connection == null) {
|
||||||
|
let [rows, fields] = await MysqlUtil.pool.query(sql, params);
|
||||||
|
res['rows'] = fields === undefined ? null : rows;
|
||||||
|
res['fields'] = fields === undefined ? rows : fields;
|
||||||
|
} else {
|
||||||
|
let [rows, fields] = await connection.query(sql, params);
|
||||||
|
res['rows'] = rows;
|
||||||
|
res['fields'] = fields;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async test() {
|
||||||
|
let connection = await MysqlUtil.pool.getConnection();
|
||||||
|
connection.beginTransaction();
|
||||||
|
connection.query(`insert into url value(6,"GET","asd","public")`);
|
||||||
|
connection.query(`insert into url value(7,"GET","asd","public")`);
|
||||||
|
await connection.commit();
|
||||||
|
connection.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
MysqlUtil,
|
||||||
|
Res,
|
||||||
|
mysql
|
||||||
|
}
|
8
util/NumberUtil.ts
Normal file
8
util/NumberUtil.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
class NumberUtil {
|
||||||
|
static getRandom(min: number, max: number): number {
|
||||||
|
return Math.floor((Math.random() * (max - min + 1) + min));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NumberUtil;
|
18
util/ObjectOperate.ts
Normal file
18
util/ObjectOperate.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
合并node对象,对于相同的属性后面覆盖前面
|
||||||
|
*/
|
||||||
|
class ObjectOperation {
|
||||||
|
static combineObject(...objs) {
|
||||||
|
if (objs.length == 1 && objs[0] instanceof Array) {
|
||||||
|
objs = objs[0];
|
||||||
|
}
|
||||||
|
let sum = {};
|
||||||
|
let length = objs.length;
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
sum = Object.assign(sum,objs[i]);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ObjectOperation
|
24
util/ProcesHelper.ts
Normal file
24
util/ProcesHelper.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import * as childPrecess from 'child_process';
|
||||||
|
|
||||||
|
class ProcessHelper {
|
||||||
|
static exec(cmd): Promise<string> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
childPrecess.exec(cmd, (error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} if (stderr) {
|
||||||
|
reject(stderr);
|
||||||
|
} else {
|
||||||
|
resolve(stdout)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (async()=>{
|
||||||
|
// let res= await ProcessHelper.exec('cd /d e://workspace&&dir');
|
||||||
|
// console.log(res);
|
||||||
|
// })()
|
||||||
|
|
||||||
|
export default ProcessHelper
|
64
util/SqliteHelper.ts
Normal file
64
util/SqliteHelper.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import sqlite3 from 'sqlite3';
|
||||||
|
import { open, Database } from 'sqlite';
|
||||||
|
import config from '../config';
|
||||||
|
import * as fs from "fs-extra";
|
||||||
|
import * as path from 'path';
|
||||||
|
import log from './LogUtil';
|
||||||
|
|
||||||
|
const HISTORY_NAME = "sqliteHistory.json";
|
||||||
|
|
||||||
|
|
||||||
|
class SqliteHelper {
|
||||||
|
public static pool: Database = null;
|
||||||
|
|
||||||
|
static async createPool() {
|
||||||
|
let fullPath = path.join(config.rootPath, config.sqlite.filePath);
|
||||||
|
let dataFolder = path.dirname(fullPath);
|
||||||
|
if (!fs.existsSync(dataFolder)) {
|
||||||
|
fs.mkdir(dataFolder);
|
||||||
|
}
|
||||||
|
SqliteHelper.pool = await open({
|
||||||
|
filename: fullPath,
|
||||||
|
driver: sqlite3.Database
|
||||||
|
});
|
||||||
|
let sqlFolder = path.join(config.rootPath, config.sqlite.sqlFolder);
|
||||||
|
let hisPath = path.join(config.rootPath, HISTORY_NAME);
|
||||||
|
let history: Array<string>;
|
||||||
|
if (fs.existsSync(hisPath)) {
|
||||||
|
history = JSON.parse(await fs.readFile(hisPath, "utf-8"));
|
||||||
|
} else {
|
||||||
|
history = new Array();
|
||||||
|
}
|
||||||
|
//执行数据库
|
||||||
|
let files = (await fs.readdir(sqlFolder)).sort((a, b) => a.localeCompare(b)).filter(item => !(item === HISTORY_NAME));
|
||||||
|
let error = null;
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
if (history.indexOf(files[i]) > -1) {
|
||||||
|
log.info("sql无需重复执行:", files[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let sqlLines = (await fs.readFile(path.join(sqlFolder, files[i]), 'utf-8')).split(/[\r\n]/g).map(item => item.trim()).filter(item => !item.startsWith("--"));
|
||||||
|
try {
|
||||||
|
let sql = "";
|
||||||
|
for (let j = 0; j < sqlLines.length; j++) {
|
||||||
|
sql = sql + sqlLines[j];
|
||||||
|
if (sqlLines[j].endsWith(";")) {
|
||||||
|
await SqliteHelper.pool.run(sql);
|
||||||
|
sql = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("sql执行成功:", files[i]);
|
||||||
|
history.push(files[i]);
|
||||||
|
} catch (err) {
|
||||||
|
error = err;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await fs.writeFile(hisPath, JSON.stringify(history));
|
||||||
|
if (error != null) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SqliteHelper;
|
22
util/TimeUtil.ts
Normal file
22
util/TimeUtil.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import moment from 'moment';
|
||||||
|
class TimeUtil {
|
||||||
|
/**
|
||||||
|
* 获取今天的零点
|
||||||
|
*/
|
||||||
|
static getZeroTime(): Date {
|
||||||
|
return moment()
|
||||||
|
.millisecond(0)
|
||||||
|
.second(0)
|
||||||
|
.minute(0)
|
||||||
|
.hour(0)
|
||||||
|
.toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async sleep(duration: number): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setTimeout(() => resolve(), duration);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TimeUtil;
|
14
util/pathUtil.ts
Normal file
14
util/pathUtil.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import path, { dirname } from 'path'
|
||||||
|
|
||||||
|
class pathUtil {
|
||||||
|
static getPath(pathStr) {
|
||||||
|
return path.resolve(pathUtil.getRootPath(), pathStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getRootPath() {
|
||||||
|
return path.resolve(__dirname, '..');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default pathUtil
|
Loading…
x
Reference in New Issue
Block a user