This commit is contained in:
fanxb 2022-02-11 16:36:51 +08:00
parent 41e40ab496
commit 8917a985b6
23 changed files with 83 additions and 603 deletions

View File

@ -1,29 +0,0 @@
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;

22
api/CaptchaApi.ts Normal file
View File

@ -0,0 +1,22 @@
import { Context } from "koa";
import { create } from "svg-captcha";
import { v4 as uuid } from 'uuid';
import { RedisHelper } from '../util/RedisHelper';
const router = {};
/**
*
*/
router["GET /captcha"] = async function (ctx: Context) {
let key: string = uuid().replaceAll("-", "");
let obj = create();
await RedisHelper.client.set(key, obj.text);
ctx.body = {
key,
data: obj.data
};
};
export default router;

View File

@ -1,28 +0,0 @@
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;

6
api/HostApi.ts Normal file
View File

@ -0,0 +1,6 @@
import { Context } from "koa";
const router = {};
export default router;

View File

@ -1,22 +0,0 @@
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;

View File

@ -6,9 +6,14 @@ const rootPath = path.resolve(__dirname, '..');
let config = { let config = {
rootPath, rootPath,
port: process.env.PORT ? parseInt(process.env.PORT) : 8089, port: process.env.PORT ? parseInt(process.env.PORT) : 8089,
urlPrefix: '/openRenamer/api', urlPrefix: '/qiezi/api',
//是否为windows平台 //是否为windows平台
isWindows: process.platform.toLocaleLowerCase().includes("win"), isWindows: process.platform.toLocaleLowerCase().includes("win"),
//redis相关配置
redis: {
enable: true,
url: "redis://localhost:6379"
},
//sqlite相关配置 //sqlite相关配置
sqlite: { sqlite: {
enable: false, //是否启用sqlite enable: false, //是否启用sqlite

View File

@ -1,5 +1,4 @@
import ErrorHelper from "../util/ErrorHelper"; import ErrorHelper from "../util/ErrorHelper";
import ApplicationRule from "../entity/dto/ApplicationRule";
import SqliteHelper from "../util/SqliteHelper"; import SqliteHelper from "../util/SqliteHelper";
export default class ApplicationRuleDao { export default class ApplicationRuleDao {
@ -8,45 +7,10 @@ export default class ApplicationRuleDao {
* @param obj * @param obj
* @returns * @returns
*/ */
static async getAll(): Promise<Array<ApplicationRule>> { static async getAll(): Promise<Array<any>> {
let res = await SqliteHelper.pool.all('select id,createdDate,updatedDate,name,comment,content from application_rule'); let res = await SqliteHelper.pool.all('select id,createdDate,updatedDate,name,comment,content from application_rule');
return res; 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("数据不存在");
}
}
} }

0
entity/dto/.gitkeep Normal file
View File

View File

@ -1,23 +0,0 @@
export default class ApplicationRule {
/**
*/
createdDate: number;
/**
*/
updatedDate: number;
id: number;
/**
*/
name: string;
/**
*/
comment: string;
/**
json序列化后
*/
content: string;
}

0
entity/vo/.gitkeep Normal file
View File

View File

@ -1,50 +0,0 @@
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;
}
}

View File

@ -1,27 +0,0 @@
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);
}
}
}

View File

@ -1,92 +0,0 @@
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;
}
}

View File

@ -1,66 +0,0 @@
import RuleInterface from "./RuleInterface";
import FileObj from "../FileObj";
import path from 'path';
export default class InsertRule implements RuleInterface {
/**
*
*/
insertContent: string;
/**
* frontbackendat:位置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;
}
}

View File

@ -1,6 +0,0 @@
import FileObj from "../FileObj";
export default interface RuleInterface {
deal(file: FileObj): void;
}

View File

@ -1,80 +0,0 @@
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:前缀backendat
*/
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;
}
}

View File

@ -10,6 +10,7 @@ import init from "./middleware/init";
import SqliteUtil from './util/SqliteHelper'; import SqliteUtil from './util/SqliteHelper';
import log from './util/LogUtil'; import log from './util/LogUtil';
import { MysqlUtil } from "./util/MysqlHelper"; import { MysqlUtil } from "./util/MysqlHelper";
import { RedisHelper } from "./util/RedisHelper";
log.info(config); log.info(config);
@ -38,6 +39,10 @@ app.use(RouterMW(router, path.join(config.rootPath, "dist/api")));
if (config.mysql.enable) { if (config.mysql.enable) {
await MysqlUtil.createPool(); await MysqlUtil.createPool();
} }
//初始化redis
if (config.redis.enable) {
await RedisHelper.create();
}
app.listen(config.port); app.listen(config.port);
log.info(`server listened `, config.port); log.info(`server listened `, config.port);
})(); })();

View File

@ -5,25 +5,42 @@ CREATE TABLE qiezi.host (
name varchar(100) NOT NULL COMMENT '网站名', name varchar(100) NOT NULL COMMENT '网站名',
host varchar(100) NOT NULL COMMENT '网站域名不含http前缀以及路径', host varchar(100) NOT NULL COMMENT '网站域名不含http前缀以及路径',
pv INT UNSIGNED DEFAULT 0 NOT NULL, pv INT UNSIGNED DEFAULT 0 NOT NULL,
uv varchar(100) DEFAULT 0 NOT NULL, uv INT UNSIGNED DEFAULT 0 NOT NULL,
CONSTRAINT host_pk PRIMARY KEY (id) CONSTRAINT host_pk PRIMARY KEY (id)
) )
ENGINE=InnoDB ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4 DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci COLLATE=utf8mb4_0900_ai_ci
COMMENT='host表记录某个站点总的pv,uv数据'; COMMENT='host表记录某个站点总的pv,uv数据';
CREATE UNIQUE INDEX host_key_IDX USING BTREE ON qiezi.host (`key`);
CREATE TABLE qiezi.path_date( CREATE TABLE qiezi.host_day(
id INT auto_increment NOT NULL, id INT auto_increment NOT NULL,
`key` CHAR(32) NOT NULL COMMENT 'key用于标识', hostId INT NOT NULL COMMENT 'hostId',
secret char(32) NOT NULL COMMENT '密钥', dateNum INT NOT NULL COMMENT '日期比如20200202',
name varchar(100) NOT NULL COMMENT '网站名',
host varchar(100) NOT NULL COMMENT '网站域名不含http前缀以及路径',
pv INT UNSIGNED DEFAULT 0 NOT NULL, pv INT UNSIGNED DEFAULT 0 NOT NULL,
uv varchar(100) DEFAULT 0 NOT NULL, uv INT UNSIGNED DEFAULT 0 NOT NULL,
CONSTRAINT host_pk PRIMARY KEY (id) CONSTRAINT detail_page_pk PRIMARY KEY (id)
) )
ENGINE=InnoDB ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4 DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci COLLATE=utf8mb4_0900_ai_ci
COMMENT='host表记录某个站点总的pv,uv数据'; COMMENT='记录域名日pv/uv';
CREATE INDEX detail_page_host_id_date_IDX USING BTREE ON qiezi.host_day(`hostId`,`dateNum`);
CREATE TABLE qiezi.detail_page(
id INT auto_increment NOT NULL,
hostId INT NOT NULL COMMENT 'hostId',
pv INT UNSIGNED DEFAULT 0 NOT NULL,
uv INT UNSIGNED DEFAULT 0 NOT NULL,
CONSTRAINT detail_page_pk PRIMARY KEY (id)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci
COMMENT='detail表记录细分页面pv/uv';
CREATE INDEX detail_page_host_id_IDX USING BTREE ON qiezi.detail_page(`hostId`);

View File

@ -22,9 +22,11 @@
"log4js": "^6.3.0", "log4js": "^6.3.0",
"moment": "^2.22.2", "moment": "^2.22.2",
"mysql2": "^2.3.3", "mysql2": "^2.3.3",
"redis": "^4.0.3",
"sqlite": "^4.0.23", "sqlite": "^4.0.23",
"sqlite3": "^5.0.2", "sqlite3": "^5.0.2",
"uuid": "^3.3.2", "svg-captcha": "^1.4.0",
"uuid": "^8.3.2",
"winston": "^3.1.0" "winston": "^3.1.0"
} }
} }

View File

@ -1,33 +0,0 @@
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;

View File

@ -1,58 +0,0 @@
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;

View File

@ -1,41 +0,0 @@
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;

14
util/RedisHelper.ts Normal file
View File

@ -0,0 +1,14 @@
import { createClient, RedisClientType } from "redis";
import config from "../config";
class RedisHelper {
public static client: RedisClientType<any>;
static async create() {
this.client = await createClient({ url: config.redis.url });
this.client.set("1","1")
}
}
export {
RedisHelper
}