temp
This commit is contained in:
parent
8d78127e4d
commit
2cf41a9c18
8
openRenamerBackend/.idea/.gitignore
generated
vendored
Normal file
8
openRenamerBackend/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
8
openRenamerBackend/.idea/modules.xml
generated
Normal file
8
openRenamerBackend/.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/openRenamerBackend.iml" filepath="$PROJECT_DIR$/.idea/openRenamerBackend.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
11
openRenamerBackend/.idea/openRenamerBackend.iml
generated
Normal file
11
openRenamerBackend/.idea/openRenamerBackend.iml
generated
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
openRenamerBackend/.idea/vcs.xml
generated
Normal file
6
openRenamerBackend/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -1,49 +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);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 收藏路径
|
|
||||||
*/
|
|
||||||
router["POST /file/path/save"] = async function (ctx: Context) {
|
|
||||||
ctx.body = await FileService.savePath(ctx.request.body);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取收藏路径
|
|
||||||
*/
|
|
||||||
router["GET /file/path"] = async function (ctx: Context) {
|
|
||||||
ctx.body = await FileService.getSaveList();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取收藏路径
|
|
||||||
*/
|
|
||||||
router["DELETE /file/path/delete"] = async function (ctx: Context) {
|
|
||||||
ctx.body = await FileService.deleteOne(ctx.query.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default router;
|
|
@ -1,25 +1,32 @@
|
|||||||
import { Context } from "koa";
|
import {Context} from "koa";
|
||||||
import FileService from "../service/FileService";
|
import FileService from "../service/FileService";
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
|
|
||||||
const router = {};
|
const router = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取目录下的文件列表
|
* 获取目录下的文件列表
|
||||||
*/
|
*/
|
||||||
router["GET /file/query"] = async function (ctx: Context) {
|
router["GET /file/query"] = async function (ctx: Context) {
|
||||||
ctx.body = await FileService.readPath(ctx.query.path as string, ctx.query.showHidden === '1');
|
ctx.body = await FileService.readPath(ctx.query.path as string, ctx.query.showHidden === '1');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*是否windows
|
* 递归读取文件夹下所有的文件
|
||||||
|
*/
|
||||||
|
router["POST /file/recursionQuery"] = async function (ctx: Context) {
|
||||||
|
ctx.body = await FileService.readRecursion(ctx.request.body);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*是否windows
|
||||||
*/
|
*/
|
||||||
router['GET /file/isWindows'] = async function (ctx: Context) {
|
router['GET /file/isWindows'] = async function (ctx: Context) {
|
||||||
ctx.body = config.isWindows;
|
ctx.body = config.isWindows;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查路径是否存在
|
* 检查路径是否存在
|
||||||
*/
|
*/
|
||||||
router["GET /file/path/exist"] = async function (ctx: Context) {
|
router["GET /file/path/exist"] = async function (ctx: Context) {
|
||||||
ctx.body = await FileService.checkExist(ctx.query.path as string);
|
ctx.body = await FileService.checkExist(ctx.query.path as string);
|
||||||
@ -46,4 +53,19 @@ router["DELETE /file/path/delete"] = async function (ctx: Context) {
|
|||||||
ctx.body = await FileService.deleteOne(ctx.query.id);
|
ctx.body = await FileService.deleteOne(ctx.query.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete file batch
|
||||||
|
*/
|
||||||
|
router["POST /file/deleteBatch"] = async function (ctx: Context) {
|
||||||
|
ctx.body = await FileService.deleteBatch(ctx.request.body);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rename file
|
||||||
|
*/
|
||||||
|
router["POST /file/rename"] = async function (ctx: Context) {
|
||||||
|
await FileService.rename(ctx.request.body.source, ctx.request.body.target);
|
||||||
|
ctx.body = "";
|
||||||
|
};
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
@ -4,86 +4,88 @@ import path from 'path';
|
|||||||
|
|
||||||
|
|
||||||
let pattern = new RegExp(/s(eason)?(\d+)/);
|
let pattern = new RegExp(/s(eason)?(\d+)/);
|
||||||
let eNumPatternArr = [new RegExp(/e[p]?(\d+)/), new RegExp(/[\(\[(](\d+)[\)\])]/), new RegExp(/[\.-](\d+)/), new RegExp(/(\d+)/)];
|
let eNumPatternArr = [new RegExp(/ep?(\d+)/), new RegExp(/[\(\[(](\d+)[\)\])]/), new RegExp(/[\.-](\d+)/), new RegExp(/(\d+)/)];
|
||||||
let resolutionPattern = new RegExp(/(\d{3,}[pP])/);
|
let resolutionPattern = new RegExp(/(\d{3,}[pP])/);
|
||||||
let resolutionArr = ['1k', '1K', '2k', '2K', '4k', '4K', '8k', '8K'];
|
let resolutionArr = ['1k', '1K', '2k', '2K', '4k', '4K', '8k', '8K'];
|
||||||
let charSet = new Set([' ', '[', '.', '(', '(']);
|
let charSet = new Set([' ', '[', '.', '(', '(']);
|
||||||
export default class InsertRule implements RuleInterface {
|
export default class InsertRule implements RuleInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 识别类型,season:季号,name:剧名/电影名识别
|
* 识别类型,season:季号,name:剧名/电影名识别
|
||||||
*/
|
*/
|
||||||
type: string;
|
type: string;
|
||||||
/**
|
/**
|
||||||
* 前面追加
|
* 前面追加
|
||||||
*/
|
*/
|
||||||
frontAdd: string;
|
frontAdd: string;
|
||||||
/**
|
/**
|
||||||
* 后面追加
|
* 后面追加
|
||||||
*/
|
*/
|
||||||
endAdd: string;
|
endAdd: string;
|
||||||
eNumWidth: number;
|
eNumWidth: number;
|
||||||
|
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
this.type = data.type;
|
this.type = data.type;
|
||||||
this.frontAdd = data.frontAdd;
|
this.frontAdd = data.frontAdd;
|
||||||
this.endAdd = data.endAdd;
|
this.endAdd = data.endAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
deal(file: FileObj): void {
|
deal(file: FileObj): void {
|
||||||
//识别到的内容
|
//识别到的内容
|
||||||
let getStr = null;
|
let getStr = null;
|
||||||
let patternRes = path.basename(file.path).replace(/[ ]+/, "").toLocaleLowerCase().match(pattern);
|
let patternRes = path.basename(file.path).replace(/[ ]+/, "").toLocaleLowerCase().match(pattern);
|
||||||
if (this.type === 'season') {
|
if (this.type === 'season') {
|
||||||
if (patternRes && patternRes[2]) {
|
if (patternRes && patternRes[2]) {
|
||||||
getStr = patternRes[2];
|
getStr = patternRes[2];
|
||||||
}
|
}
|
||||||
} else if (this.type === 'name') {
|
} else if (this.type === 'name') {
|
||||||
let originName = null;
|
let originName = null;
|
||||||
if (patternRes && patternRes[2]) {
|
if (patternRes && patternRes[2]) {
|
||||||
//说明是剧集,取父文件夹的父文件夹名称
|
//说明是剧集,取父文件夹的父文件夹名称
|
||||||
originName = path.basename(path.resolve(file.path, '..'));
|
originName = path.basename(path.resolve(file.path, '..'));
|
||||||
} else {
|
} else {
|
||||||
//说明是电影
|
//说明是电影
|
||||||
originName = path.basename(file.path);
|
originName = path.basename(file.path);
|
||||||
}
|
}
|
||||||
getStr = '';
|
getStr = '';
|
||||||
for (let i = 0; i < originName.length; i++) {
|
for (let i = 0; i < originName.length; i++) {
|
||||||
let char = originName.charAt(i);
|
let char = originName.charAt(i);
|
||||||
if (charSet.has(char)) {
|
if (charSet.has(char)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
getStr += char;
|
getStr += char;
|
||||||
}
|
}
|
||||||
} else if (this.type === 'eNum') {
|
} else if (this.type === 'eNum') {
|
||||||
let lowName = file.originName.toLocaleLowerCase().replace(/ /g, '');
|
let lowName = file.originName.toLocaleLowerCase().replace(/ /g, '')
|
||||||
for (let i in eNumPatternArr) {
|
.replace(/\d+[a-z]/g, '')//去除4k,1080p等
|
||||||
let patternRes = lowName.match(eNumPatternArr[i]);
|
.replace(/[xh]\d+/g, '')//去除x264,h264等 ;
|
||||||
if (patternRes && patternRes.length > 1) {
|
for (let i in eNumPatternArr) {
|
||||||
getStr = patternRes[1];
|
let patternRes = lowName.match(eNumPatternArr[i]);
|
||||||
for (let i = 0; i < this.eNumWidth - getStr.length; i++) {
|
if (patternRes && patternRes.length > 1) {
|
||||||
getStr = '0' + getStr;
|
getStr = patternRes[1];
|
||||||
}
|
for (let i = 0; i < this.eNumWidth - getStr.length; i++) {
|
||||||
break;
|
getStr = '0' + getStr;
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
} else if (this.type === 'resolution') {
|
}
|
||||||
let res = file.originName.match(resolutionPattern);
|
}
|
||||||
if (res && res.length > 1) {
|
} else if (this.type === 'resolution') {
|
||||||
getStr = res[1];
|
let res = file.originName.match(resolutionPattern);
|
||||||
} else {
|
if (res && res.length > 1) {
|
||||||
for (let i = 0; i < resolutionArr.length; i++) {
|
getStr = res[1];
|
||||||
if (file.originName.indexOf(resolutionArr[i]) > -1) {
|
} else {
|
||||||
getStr = resolutionArr[i];
|
for (let i = 0; i < resolutionArr.length; i++) {
|
||||||
break;
|
if (file.originName.indexOf(resolutionArr[i]) > -1) {
|
||||||
}
|
getStr = resolutionArr[i];
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (getStr && getStr.length > 0) {
|
}
|
||||||
file.realName = file.realName + this.frontAdd + getStr + this.endAdd;
|
}
|
||||||
file.name = file.realName + file.expandName;
|
if (getStr && getStr.length > 0) {
|
||||||
}
|
file.realName = file.realName + this.frontAdd + getStr + this.endAdd;
|
||||||
}
|
file.name = file.realName + file.expandName;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -9,14 +9,15 @@ import handleError from "./middleware/handleError";
|
|||||||
import init from "./middleware/init";
|
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 { updateQbInfo } from './util/QbApiUtil';
|
import {updateQbInfo} from './util/QbApiUtil';
|
||||||
|
|
||||||
|
|
||||||
console.log(config);
|
console.log(config);
|
||||||
|
|
||||||
const app = new koa();
|
const app = new koa();
|
||||||
|
|
||||||
let router = new Router({
|
let router = new Router({
|
||||||
prefix: config.urlPrefix
|
prefix: config.urlPrefix
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(require('koa-static')(path.join(config.rootPath, 'static')));
|
app.use(require('koa-static')(path.join(config.rootPath, 'static')));
|
||||||
@ -30,12 +31,12 @@ app.use(handleError);
|
|||||||
|
|
||||||
app.use(RouterMW(router, path.join(config.rootPath, "dist/api")));
|
app.use(RouterMW(router, path.join(config.rootPath, "dist/api")));
|
||||||
(async () => {
|
(async () => {
|
||||||
await SqliteUtil.createPool();
|
await SqliteUtil.createPool();
|
||||||
await updateQbInfo(null, null);
|
await updateQbInfo(null, null);
|
||||||
app.listen(config.port);
|
app.listen(config.port);
|
||||||
log.info(`server listened `, config.port);
|
log.info(`server listened `, config.port);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
app.on("error", (error) => {
|
app.on("error", (error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
})
|
})
|
||||||
|
@ -6,136 +6,190 @@ import ProcessHelper from '../util/ProcesHelper';
|
|||||||
import FileObj from '../entity/vo/FileObj';
|
import FileObj from '../entity/vo/FileObj';
|
||||||
import SavePathDao from '../dao/SavePathDao';
|
import SavePathDao from '../dao/SavePathDao';
|
||||||
import SavePath from '../entity/po/SavePath';
|
import SavePath from '../entity/po/SavePath';
|
||||||
|
import ErrorHelper from "../util/ErrorHelper";
|
||||||
|
|
||||||
let numberSet = new Set(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
|
let numberSet = new Set(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
|
||||||
|
|
||||||
class FileService {
|
class FileService {
|
||||||
static async readPath(pathStr: string, showHidden: boolean): Promise<Array<FileObj>> {
|
static async readPath(pathStr: string, showHidden: boolean): Promise<Array<FileObj>> {
|
||||||
pathStr = decodeURIComponent(pathStr);
|
pathStr = decodeURIComponent(pathStr);
|
||||||
let fileList = new Array();
|
let fileList = [];
|
||||||
if (pathStr.trim().length == 0) {
|
if (pathStr.trim().length == 0) {
|
||||||
//获取根目录路径
|
//获取根目录路径
|
||||||
if (config.isWindows) {
|
if (config.isWindows) {
|
||||||
//windows下
|
//windows下
|
||||||
let std: string = (await ProcessHelper.exec('wmic logicaldisk get caption')).replace('Caption', '');
|
let std: string = (await ProcessHelper.exec('wmic logicaldisk get caption')).replace('Caption', '');
|
||||||
fileList = std
|
fileList = std
|
||||||
.split('\r\n')
|
.split('\r\n')
|
||||||
.filter((item) => item.trim().length > 0)
|
.filter((item) => item.trim().length > 0)
|
||||||
.map((item) => item.trim());
|
.map((item) => item.trim());
|
||||||
} else {
|
} else {
|
||||||
//linux下
|
//linux下
|
||||||
pathStr = '/';
|
pathStr = '/';
|
||||||
fileList = await fs.readdir(pathStr);
|
fileList = await fs.readdir(pathStr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!(fs.pathExists(pathStr))) {
|
if (!(fs.pathExists(pathStr))) {
|
||||||
throw new Error("路径不存在");
|
throw new Error("路径不存在");
|
||||||
}
|
}
|
||||||
fileList = await fs.readdir(pathStr);
|
fileList = await fs.readdir(pathStr);
|
||||||
}
|
}
|
||||||
let folderList: Array<FileObj> = new Array();
|
let folderList: Array<FileObj> = [];
|
||||||
let files: Array<FileObj> = new Array();
|
let files: Array<FileObj> = [];
|
||||||
for (let index in fileList) {
|
for (let index in fileList) {
|
||||||
try {
|
try {
|
||||||
let stat = await fs.stat(path.join(pathStr, fileList[index]));
|
let stat = await fs.stat(path.join(pathStr, fileList[index]));
|
||||||
if (fileList[index].startsWith('.')) {
|
if (fileList[index].startsWith('.')) {
|
||||||
if (showHidden) {
|
if (showHidden) {
|
||||||
(stat.isDirectory() ? folderList : files).push(
|
(stat.isDirectory() ? folderList : files).push(
|
||||||
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
|
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(stat.isDirectory() ? folderList : files).push(
|
(stat.isDirectory() ? folderList : files).push(
|
||||||
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
|
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
folderList.sort((a, b) => FileService.compareStr(a.name, b.name)).push(...files.sort((a, b) => FileService.compareStr(a.name, b.name)));
|
folderList.sort((a, b) => FileService.compareStr(a.name, b.name)).push(...files.sort((a, b) => FileService.compareStr(a.name, b.name)));
|
||||||
return folderList;
|
return folderList;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async checkExist(pathStr: string) {
|
/**
|
||||||
return await fs.pathExists(pathStr);
|
* 递归读取文件夹下所有的文件
|
||||||
}
|
*/
|
||||||
|
static async readRecursion(folders: Array<FileObj>): Promise<Array<FileObj>> {
|
||||||
|
let res = [];
|
||||||
|
await this.readDirRecursion(res, folders, 1);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
private static async readDirRecursion(res: Array<FileObj>, folders: Array<FileObj>, depth: number): Promise<void> {
|
||||||
* 收藏路径
|
if (depth > 10) {
|
||||||
* @param saveObj
|
throw ErrorHelper.Error400("递归读取超过10层,强制结束");
|
||||||
* @returns
|
}
|
||||||
*/
|
if (folders == null || folders.length == 0) {
|
||||||
static async savePath(saveObj: SavePath) {
|
return;
|
||||||
await SavePathDao.addOne(saveObj);
|
}
|
||||||
return saveObj;
|
for (let i in folders) {
|
||||||
}
|
let file = folders[i];
|
||||||
|
if (!file.isFolder) {
|
||||||
|
res.push(file);
|
||||||
|
} else {
|
||||||
|
let filePath = path.join(file.path, file.name);
|
||||||
|
let temp = (await fs.readdir(filePath)).map(item => {
|
||||||
|
let stat = fs.statSync(path.join(filePath, item));
|
||||||
|
return new FileObj(item, filePath, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime());
|
||||||
|
});
|
||||||
|
await FileService.readDirRecursion(res, temp, depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
static async checkExist(pathStr: string) {
|
||||||
* 获取保存列表
|
return await fs.pathExists(pathStr);
|
||||||
* @returns
|
}
|
||||||
*/
|
|
||||||
static async getSaveList() {
|
|
||||||
return await SavePathDao.getAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除
|
* 收藏路径
|
||||||
* @param id
|
* @param saveObj
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
static async deleteOne(id) {
|
static async savePath(saveObj: SavePath) {
|
||||||
return await SavePathDao.delete(id);
|
await SavePathDao.addOne(saveObj);
|
||||||
}
|
return saveObj;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数字字母混合排序
|
* 获取保存列表
|
||||||
* @param a str
|
* @returns
|
||||||
* @param b str
|
*/
|
||||||
*/
|
static async getSaveList() {
|
||||||
static compareStr(a: string, b: string) {
|
return await SavePathDao.getAll();
|
||||||
let an = a.length;
|
}
|
||||||
let bn = b.length;
|
|
||||||
for (let i = 0; i < an;) {
|
|
||||||
let charA = FileService.readChar(a, i, an);
|
|
||||||
let charB = FileService.readChar(b, i, bn);
|
|
||||||
if (charB.length == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (charA !== charB) {
|
|
||||||
//读取字符串不相等说明可以得到排序结果
|
|
||||||
//如果都为数字,按照数字的比较方法,否则按照字符串比较
|
|
||||||
return numberSet.has(charA.charAt(0)) && numberSet.has(charB.charAt(0)) ? Number(charA) - Number(charB) : charA.localeCompare(charB);
|
|
||||||
}
|
|
||||||
i += charA.length;
|
|
||||||
}
|
|
||||||
//排到最后都没分结果说明相等
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取字符,如果字符为数字就读取整个数字
|
* 删除
|
||||||
* @param a a
|
* @param id
|
||||||
* @param n 数字长度
|
* @returns
|
||||||
*/
|
*/
|
||||||
static readChar(a: string, i: number, n: number) {
|
static async deleteOne(id) {
|
||||||
let res = "";
|
return await SavePathDao.delete(id);
|
||||||
for (; i < n; i++) {
|
}
|
||||||
let char = a.charAt(i);
|
|
||||||
if (numberSet.has(char)) {
|
/**
|
||||||
//如果当前字符是数字,添加到结果中
|
* 数字字母混合排序
|
||||||
res += char;
|
* @param a str
|
||||||
} else {
|
* @param b str
|
||||||
//如果不为数字,但是为第一个字符,直接返回,否则返回res
|
*/
|
||||||
if (res.length == 0) {
|
static compareStr(a: string, b: string) {
|
||||||
return char;
|
let an = a.length;
|
||||||
} else {
|
let bn = b.length;
|
||||||
return res;
|
for (let i = 0; i < an;) {
|
||||||
}
|
let charA = FileService.readChar(a, i, an);
|
||||||
}
|
let charB = FileService.readChar(b, i, bn);
|
||||||
}
|
if (charB.length == 0) {
|
||||||
return res;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (charA !== charB) {
|
||||||
|
//读取字符串不相等说明可以得到排序结果
|
||||||
|
//如果都为数字,按照数字的比较方法,否则按照字符串比较
|
||||||
|
return numberSet.has(charA.charAt(0)) && numberSet.has(charB.charAt(0)) ? Number(charA) - Number(charB) : charA.localeCompare(charB);
|
||||||
|
}
|
||||||
|
i += charA.length;
|
||||||
|
}
|
||||||
|
//排到最后都没分结果说明相等
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取字符,如果字符为数字就读取整个数字
|
||||||
|
* @param a a
|
||||||
|
* @param n 数字长度
|
||||||
|
*/
|
||||||
|
static readChar(a: string, i: number, n: number) {
|
||||||
|
let res = "";
|
||||||
|
for (; i < n; i++) {
|
||||||
|
let char = a.charAt(i);
|
||||||
|
if (numberSet.has(char)) {
|
||||||
|
//如果当前字符是数字,添加到结果中
|
||||||
|
res += char;
|
||||||
|
} else {
|
||||||
|
//如果不为数字,但是为第一个字符,直接返回,否则返回res
|
||||||
|
if (res.length == 0) {
|
||||||
|
return char;
|
||||||
|
} else {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete batch
|
||||||
|
* @param files files
|
||||||
|
*/
|
||||||
|
static async deleteBatch(files: Array<FileObj>): Promise<void> {
|
||||||
|
if (files == null || files.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i in files) {
|
||||||
|
await fs.remove(path.join(files[i].path, files[i].name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rename file from source to target
|
||||||
|
* @param source sourceFile
|
||||||
|
* @param target targetFile
|
||||||
|
*/
|
||||||
|
static async rename(source: FileObj, target: FileObj): Promise<void> {
|
||||||
|
await fs.rename(path.join(source.path, source.name), path.join(target.path, target.name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FileService;
|
export default FileService;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app">
|
<div class="app">
|
||||||
<el-menu :default-active="activeIndex" mode="horizontal" background-color="#545c64" text-color="#fff"
|
<el-menu :default-active="activeIndex" mode="horizontal" background-color="#545c64" text-color="#fff"
|
||||||
active-text-color="#ffd04b" router>
|
active-text-color="#ffd04b" router>
|
||||||
<el-menu-item index="/">重命名</el-menu-item>
|
<el-menu-item index="/">重命名</el-menu-item>
|
||||||
<el-menu-item index="/auto">自动化</el-menu-item>
|
<!-- <el-menu-item index="/auto">自动化</el-menu-item>-->
|
||||||
<!-- <el-sub-menu index="/download">
|
<!-- <el-sub-menu index="/download">
|
||||||
<template #title>bt下载</template>
|
<template #title>bt下载</template>
|
||||||
<el-menu-item index="/download/center">下载中心</el-menu-item>
|
<el-menu-item index="/download/center">下载中心</el-menu-item>
|
||||||
@ -11,7 +11,7 @@
|
|||||||
</el-sub-menu> -->
|
</el-sub-menu> -->
|
||||||
</el-menu>
|
</el-menu>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<router-view />
|
<router-view/>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">版本:{{ version }} 开源地址:<a
|
<div class="footer">版本:{{ version }} 开源地址:<a
|
||||||
href="https://github.com/FleyX/open-renamer">open-renamer</a></div>
|
href="https://github.com/FleyX/open-renamer">open-renamer</a></div>
|
||||||
@ -20,22 +20,23 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import httpUtil from "./utils/HttpUtil";
|
import httpUtil from "./utils/HttpUtil";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Home",
|
name: "Home",
|
||||||
data () {
|
data() {
|
||||||
return {
|
return {
|
||||||
version: "1.2",
|
version: "1.2",
|
||||||
activeIndex: location.pathname,
|
activeIndex: location.pathname,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async created () {
|
async created() {
|
||||||
let token = localStorage.getItem("token");
|
let token = localStorage.getItem("token");
|
||||||
window.token = token;
|
window.token = token;
|
||||||
window.isWindows = await httpUtil.get("/file/isWindows");
|
window.isWindows = await httpUtil.get("/file/isWindows");
|
||||||
console.log(this.$route);
|
console.log(this.$route);
|
||||||
console.log(this.activeIndex);
|
console.log(this.activeIndex);
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted() {
|
||||||
console.log(this.$route);
|
console.log(this.$route);
|
||||||
console.log(location);
|
console.log(location);
|
||||||
},
|
},
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
<div class="fileList">
|
<div class="fileList">
|
||||||
<div>
|
<div>
|
||||||
<el-input style="display: inline-block; width: 150px" type="text" size="small" placeholder="关键词过滤"
|
<el-input style="display: inline-block; width: 150px" type="text" size="small" placeholder="关键词过滤"
|
||||||
v-model="filterText" clearable />
|
v-model="filterText" clearable/>
|
||||||
<template v-if="type == 'file'">
|
<template v-if="type === 'file'">
|
||||||
<el-button type="primary" @click="selectAll(true)" size="small">全选</el-button>
|
<el-button type="primary" @click="selectAll(true)" size="small">全选</el-button>
|
||||||
<el-button type="primary" @click="selectAll(false)" size="small">全不选</el-button>
|
<el-button type="primary" @click="selectAll(false)" size="small">全不选</el-button>
|
||||||
<el-button type="primary" @click="refresh" size="small">刷新</el-button>
|
<el-button type="primary" @click="refresh" size="small">刷新</el-button>
|
||||||
@ -21,9 +21,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(item, index) in filterFileList" :key="index">
|
<div v-for="(item, index) in filterFileList" :key="index">
|
||||||
<span class="folder" v-if="item.isFolder" @click="fileClick(item)">{{ item.name }}</span>
|
<el-checkbox style="height: 1.4em" v-model="item.checked" :disabled="type==='folder' && !item.isFolder">
|
||||||
<el-checkbox style="height: 1.4em" v-model="item.checked" v-else-if="type == 'file'">{{ item.name
|
<a v-if="item.isFolder" @click="fileClick(item)" style="color: #289fff">{{ item.name }}</a>
|
||||||
}}</el-checkbox>
|
<span v-else>{{ item.name }}</span>
|
||||||
|
</el-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -32,7 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-dialog title="保存路径" v-model="showSave" width="40em">
|
<el-dialog title="保存路径" v-model="showSave" width="40em">
|
||||||
<el-input type="text" v-model="saveName" placeholder="输入名称" />
|
<el-input type="text" v-model="saveName" placeholder="输入名称"/>
|
||||||
<el-button type="primary" @click="savePath" style="padding-top: 1em">提交</el-button>
|
<el-button type="primary" @click="savePath" style="padding-top: 1em">提交</el-button>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@ -41,10 +42,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import HttpUtil from "../utils/HttpUtil";
|
import HttpUtil from "../utils/HttpUtil";
|
||||||
import Bus from "../utils/Bus";
|
import Bus from "../utils/Bus";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "FileChose",
|
name: "FileChose",
|
||||||
|
//type:folder:选择文件夹。file:选择文件
|
||||||
props: ["curChoosePath", "type"],
|
props: ["curChoosePath", "type"],
|
||||||
data () {
|
data() {
|
||||||
return {
|
return {
|
||||||
isWindows: false,
|
isWindows: false,
|
||||||
fileList: [], //路径下的文件节点
|
fileList: [], //路径下的文件节点
|
||||||
@ -57,24 +60,24 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
filterFileList () {
|
filterFileList() {
|
||||||
let text = this.filterText.trim();
|
let text = this.filterText.trim();
|
||||||
return text === "" ? this.fileList : this.fileList.filter((item) => item.name.indexOf(text) > -1);
|
return text === "" ? this.fileList : this.fileList.filter((item) => item.name.indexOf(text) > -1);
|
||||||
},
|
},
|
||||||
curSavePathId () {
|
curSavePathId() {
|
||||||
let curPath = JSON.stringify(this.pathList);
|
let curPath = JSON.stringify(this.pathList);
|
||||||
let targetList = this.savePathList.filter((item) => item.content == curPath);
|
let targetList = this.savePathList.filter((item) => item.content === curPath);
|
||||||
return targetList.length > 0 ? targetList[0].id : null;
|
return targetList.length > 0 ? targetList[0].id : null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
async curChoosePath (newVal) {
|
async curChoosePath(newVal) {
|
||||||
console.log("变更路径:", newVal);
|
console.log("变更路径:", newVal);
|
||||||
this.pathList = newVal;
|
this.pathList = newVal;
|
||||||
await this.breadcrumbClick(this.pathList.length - 1);
|
await this.breadcrumbClick(this.pathList.length - 1);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async created () {
|
async created() {
|
||||||
if (this.curChoosePath && this.curChoosePath.length > 0) {
|
if (this.curChoosePath && this.curChoosePath.length > 0) {
|
||||||
this.pathList = this.curChoosePath;
|
this.pathList = this.curChoosePath;
|
||||||
}
|
}
|
||||||
@ -84,15 +87,15 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async refresh () {
|
async refresh() {
|
||||||
await this.breadcrumbClick(this.pathList.length - 1);
|
await this.breadcrumbClick(this.pathList.length - 1);
|
||||||
},
|
},
|
||||||
//刷新保存的路径
|
//刷新保存的路径
|
||||||
async refreshSavePathList () {
|
async refreshSavePathList() {
|
||||||
this.savePathList = await HttpUtil.get("/file/path");
|
this.savePathList = await HttpUtil.get("/file/path");
|
||||||
},
|
},
|
||||||
//点击面包蟹
|
//点击面包蟹
|
||||||
async breadcrumbClick (index) {
|
async breadcrumbClick(index) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
let path = this.createPath(index);
|
let path = this.createPath(index);
|
||||||
@ -109,7 +112,7 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
//文件列表点击
|
//文件列表点击
|
||||||
fileClick (item) {
|
fileClick(item) {
|
||||||
if (item.isFolder) {
|
if (item.isFolder) {
|
||||||
this.pathList.push(item.name);
|
this.pathList.push(item.name);
|
||||||
this.breadcrumbClick(this.pathList.length);
|
this.breadcrumbClick(this.pathList.length);
|
||||||
@ -118,14 +121,14 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
//全选
|
//全选
|
||||||
selectAll (status) {
|
selectAll(status) {
|
||||||
this.filterFileList.filter((item) => !item.isFolder).forEach((item) => (item.checked = status));
|
this.filterFileList.filter((item) => !item.isFolder).forEach((item) => (item.checked = status));
|
||||||
},
|
},
|
||||||
//根据index构建路径
|
//根据index构建路径
|
||||||
createPath (index) {
|
createPath(index) {
|
||||||
console.log("当前路径为:", this.pathList);
|
console.log("当前路径为:", this.pathList);
|
||||||
let path;
|
let path;
|
||||||
if (index == -1) {
|
if (index === -1) {
|
||||||
path = "";
|
path = "";
|
||||||
this.pathList = [];
|
this.pathList = [];
|
||||||
} else {
|
} else {
|
||||||
@ -137,34 +140,35 @@ export default {
|
|||||||
return path;
|
return path;
|
||||||
},
|
},
|
||||||
//点击确定
|
//点击确定
|
||||||
submit () {
|
async submit() {
|
||||||
|
let chosenFiles = this.fileList.filter((item) => item.checked);
|
||||||
|
if (chosenFiles.length === 0) {
|
||||||
|
this.$message({message: "未选择文件", type: "warning"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.type === 'file') {
|
if (this.type === 'file') {
|
||||||
let chosedFiles = this.fileList.filter((item) => item.checked);
|
let body = await HttpUtil.post("/file/recursionQuery", null, chosenFiles);
|
||||||
if (chosedFiles.length == 0) {
|
this.$emit("addData", JSON.parse(JSON.stringify(body)));
|
||||||
this.$message({ message: "未选择文件", type: "warning" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.$emit("addData", JSON.parse(JSON.stringify(chosedFiles)));
|
|
||||||
this.fileList.forEach((item) => (item.checked = false));
|
this.fileList.forEach((item) => (item.checked = false));
|
||||||
this.fileList = [...this.fileList];
|
this.fileList = [...this.fileList];
|
||||||
} else if (this.type === 'folder') {
|
} else if (this.type === 'folder') {
|
||||||
//选择文件夹
|
//选择文件夹
|
||||||
this.$emit("folderChose", this.createPath(this.pathList.length - 1));
|
this.$emit("folderChose", JSON.parse(JSON.stringify(chosenFiles)));
|
||||||
}
|
}
|
||||||
this.filterText = "";
|
this.filterText = "";
|
||||||
|
|
||||||
},
|
},
|
||||||
//收藏路径
|
//收藏路径
|
||||||
async savePath () {
|
async savePath() {
|
||||||
await HttpUtil.post("/file/path/save", null, { name: this.saveName, content: JSON.stringify(this.pathList) });
|
await HttpUtil.post("/file/path/save", null, {name: this.saveName, content: JSON.stringify(this.pathList)});
|
||||||
Bus.$emit("refreshSavePathList");
|
Bus.$emit("refreshSavePathList");
|
||||||
this.saveName = "";
|
this.saveName = "";
|
||||||
this.showSave = false;
|
this.showSave = false;
|
||||||
this.$message.success("操作成功");
|
this.$message.success("操作成功");
|
||||||
},
|
},
|
||||||
//取消收藏路径
|
//取消收藏路径
|
||||||
async cancelSavePath () {
|
async cancelSavePath() {
|
||||||
await HttpUtil.delete("/file/path/delete", { id: this.curSavePathId });
|
await HttpUtil.delete("/file/path/delete", {id: this.curSavePathId});
|
||||||
Bus.$emit("refreshSavePathList");
|
Bus.$emit("refreshSavePathList");
|
||||||
this.$message.success("操作成功");
|
this.$message.success("操作成功");
|
||||||
},
|
},
|
||||||
|
@ -11,35 +11,37 @@ import router from '../router/index';
|
|||||||
* @param {*} redirect 接口返回未认证是否跳转到登陆
|
* @param {*} redirect 接口返回未认证是否跳转到登陆
|
||||||
* @returns 数据
|
* @returns 数据
|
||||||
*/
|
*/
|
||||||
async function request (url, method, params, body, isForm) {
|
async function request(url, method, params, body, isForm) {
|
||||||
let options = {
|
let options = {
|
||||||
url,
|
url,
|
||||||
baseURL: '/openRenamer/api',
|
baseURL: '/openRenamer/api',
|
||||||
method,
|
method,
|
||||||
params,
|
params,
|
||||||
headers: { token: window.token }
|
headers: {token: window.token}
|
||||||
};
|
};
|
||||||
if (isForm) {
|
if (isForm) {
|
||||||
options.headers['Content-Type'] = 'multipart/form-data';
|
options.headers['Content-Type'] = 'multipart/form-data';
|
||||||
}
|
|
||||||
if (body) {
|
|
||||||
options.data = body;
|
|
||||||
}
|
|
||||||
let res;
|
|
||||||
try {
|
|
||||||
res = await http.default.request(options);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(Object.keys(err));
|
|
||||||
console.log(err.response);
|
|
||||||
if (err.response.status == 401) {
|
|
||||||
window.vueInstance.config.globalProperties.$message.error('密钥验证错误');
|
|
||||||
router.push("/public/login");
|
|
||||||
} else {
|
|
||||||
window.vueInstance.config.globalProperties.$message.error('发生了某些异常问题');
|
|
||||||
}
|
}
|
||||||
throw err;
|
if (body) {
|
||||||
}
|
options.data = body;
|
||||||
return res.data;
|
}
|
||||||
|
let res;
|
||||||
|
try {
|
||||||
|
res = await http.default.request(options);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(Object.keys(err));
|
||||||
|
console.log(err.response);
|
||||||
|
if (err.response.status === 401) {
|
||||||
|
window.vueInstance.config.globalProperties.$message.error('密钥验证错误');
|
||||||
|
router.push("/public/login");
|
||||||
|
} else if (err.response.status === 400) {
|
||||||
|
window.vueInstance.config.globalProperties.$message.error(err.response.data);
|
||||||
|
} else {
|
||||||
|
window.vueInstance.config.globalProperties.$message.error('发生了某些异常问题');
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,8 +50,8 @@ async function request (url, method, params, body, isForm) {
|
|||||||
* @param {*} params url参数
|
* @param {*} params url参数
|
||||||
* @param {*} redirect 未登陆是否跳转到登陆页
|
* @param {*} redirect 未登陆是否跳转到登陆页
|
||||||
*/
|
*/
|
||||||
async function get (url, params = null) {
|
async function get(url, params = null) {
|
||||||
return request(url, 'get', params, null, false);
|
return request(url, 'get', params, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,8 +62,8 @@ async function get (url, params = null) {
|
|||||||
* @param {*} isForm 是否表单数据
|
* @param {*} isForm 是否表单数据
|
||||||
* @param {*} redirect 是否重定向
|
* @param {*} redirect 是否重定向
|
||||||
*/
|
*/
|
||||||
async function post (url, params, body, isForm = false) {
|
async function post(url, params, body, isForm = false) {
|
||||||
return request(url, 'post', params, body, isForm);
|
return request(url, 'post', params, body, isForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,8 +74,8 @@ async function post (url, params, body, isForm = false) {
|
|||||||
* @param {*} isForm 是否表单数据
|
* @param {*} isForm 是否表单数据
|
||||||
* @param {*} redirect 是否重定向
|
* @param {*} redirect 是否重定向
|
||||||
*/
|
*/
|
||||||
async function put (url, params, body, isForm = false) {
|
async function put(url, params, body, isForm = false) {
|
||||||
return request(url, 'put', params, body, isForm);
|
return request(url, 'put', params, body, isForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,13 +84,13 @@ async function put (url, params, body, isForm = false) {
|
|||||||
* @param {*} params url参数
|
* @param {*} params url参数
|
||||||
* @param {*} redirect 是否重定向
|
* @param {*} redirect 是否重定向
|
||||||
*/
|
*/
|
||||||
async function deletes (url, params = null) {
|
async function deletes(url, params = null) {
|
||||||
return request(url, 'delete', params, null);
|
return request(url, 'delete', params, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
get,
|
get,
|
||||||
post,
|
post,
|
||||||
put,
|
put,
|
||||||
delete: deletes,
|
delete: deletes,
|
||||||
};
|
};
|
||||||
|
@ -1,36 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-loading="loading" element-loading-text="后台处理中,请稍候">
|
<div v-loading="loading" element-loading-text="后台处理中,请稍候">
|
||||||
<br />
|
<br/>
|
||||||
<el-button type="success" @click="submit" size="default">开始重命名</el-button>
|
<el-button type="success" @click="submit" size="default">开始重命名</el-button>
|
||||||
<el-divider content-position="left">
|
<el-divider content-position="left">
|
||||||
<div class="head-text">规则设置</div>
|
<div class="head-text">规则设置</div>
|
||||||
</el-divider>
|
</el-divider>
|
||||||
<!-- 规则列表 -->
|
<!-- 规则列表 -->
|
||||||
<rule-block @ruleUpdate="ruleUpdate" />
|
<rule-block @ruleUpdate="ruleUpdate"/>
|
||||||
<el-divider content-position="left">
|
<el-divider content-position="left">
|
||||||
<div class="head-text">文件预览</div>
|
<div class="head-text">文件预览</div>
|
||||||
</el-divider>
|
</el-divider>
|
||||||
<!-- 文件预览列表 -->
|
<!-- 文件预览列表 -->
|
||||||
<div class="fileList">
|
<div class="fileList">
|
||||||
<div>
|
<div>
|
||||||
<el-button type="primary" @click="showFileAdd" size="small">新增</el-button>
|
<el-tooltip effect="dark" content="添加需要重命名的文件" placement="top">
|
||||||
收藏路径:<el-tag v-for="item in savePathList" :round="true" class="savePath" closable :key="item.id"
|
<el-button type="primary" @click="showFileAdd" size="small">添加</el-button>
|
||||||
@click="clickSavePath(item)" @close="deleteSavePath(item)" text>{{ item.name }}</el-tag>
|
</el-tooltip>
|
||||||
|
收藏路径:
|
||||||
|
<el-tag v-for="item in savePathList" :round="true" class="savePath" closable :key="item.id"
|
||||||
|
@click="clickSavePath(item)" @close="deleteSavePath(item)" text>{{ item.name }}
|
||||||
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div style="margin-top: 5px">
|
||||||
<el-button type="primary" size="small" @click="selectAllFiles">反选</el-button>
|
<el-button type="primary" size="small" @click="selectAllFiles">反选</el-button>
|
||||||
<el-button type="danger" size="small" @click="deleteCheckedFiles">删除</el-button>
|
<el-tooltip effect="dark" content="一键选中所有的非视频、字幕文件和小于5MB的视频文件" placement="bottom">
|
||||||
|
<el-button type="success" size="small" @click="">一键选择</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="dark" content="移除(非删除)需要重命名的文件" placement="bottom">
|
||||||
|
<el-button type="warning" size="small" @click="removeCheckedFiles">移除</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-popconfirm width="250" confirm-button-text="确认" cancel-button-text="取消"
|
||||||
|
title="确认删除勾选的文件(无法恢复)?" @confirm="deleteCheckedFiles">
|
||||||
|
<template #reference>
|
||||||
|
<el-button type="danger" size="small">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
<el-button type="primary" size="small" @click="moveIndex('top')">
|
<el-button type="primary" size="small" @click="moveIndex('top')">
|
||||||
<el-tooltip effect="dark" content="上移规则" placement="top">
|
<el-tooltip effect="dark" content="上移规则" placement="top">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<top />
|
<top/>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" size="small" @click="moveIndex('bottom')">
|
<el-button type="primary" size="small" @click="moveIndex('bottom')">
|
||||||
<el-tooltip effect="dark" content="下移规则" placement="top"><el-icon>
|
<el-tooltip effect="dark" content="下移规则" placement="top">
|
||||||
<bottom />
|
<el-icon>
|
||||||
</el-icon></el-tooltip>
|
<bottom/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" size="small" @click="editFile">
|
||||||
|
<el-tooltip effect="dark" content="修改文件名" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<Edit/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="fileBlock">
|
<div class="fileBlock">
|
||||||
@ -53,66 +77,72 @@
|
|||||||
|
|
||||||
<el-dialog title="新增文件" v-model="dialogVisible" width="70%">
|
<el-dialog title="新增文件" v-model="dialogVisible" width="70%">
|
||||||
<file-chose ref="fileChose" type="file" :curChoosePath="curChoosePath" @addData="addData"
|
<file-chose ref="fileChose" type="file" :curChoosePath="curChoosePath" @addData="addData"
|
||||||
@refreshSavePathList="refreshSavePathList" />
|
@refreshSavePathList="refreshSavePathList"/>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog title="编辑名称" v-model="showNameEditDialog" width="50%">
|
||||||
|
<el-input type="text" v-model="newName"/>
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" @click="doEditFile">确认</el-button>
|
||||||
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// @ is an alias to /src
|
// @ is an alias to /src
|
||||||
import { Top, Bottom } from "@element-plus/icons-vue";
|
import {Top, Bottom, Edit} from "@element-plus/icons-vue";
|
||||||
import HttpUtil from "../../utils/HttpUtil";
|
import HttpUtil from "../../utils/HttpUtil";
|
||||||
import FileChose from "@/components/FileChose";
|
import FileChose from "@/components/FileChose";
|
||||||
import RuleBlock from "@/components/rules/RuleBlock.vue";
|
import RuleBlock from "@/components/rules/RuleBlock.vue";
|
||||||
import Bus from "../../utils/Bus";
|
import Bus from "../../utils/Bus";
|
||||||
|
import Tips from '@/components/Tips';
|
||||||
|
|
||||||
let numberSet = new Set(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
|
let numberSet = new Set(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Home",
|
name: "Home",
|
||||||
components: {
|
components: {
|
||||||
FileChose,
|
FileChose, RuleBlock, Top, Bottom, Tips, Edit
|
||||||
RuleBlock,
|
|
||||||
Top,
|
|
||||||
Bottom,
|
|
||||||
},
|
},
|
||||||
data () {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false, //遮罩
|
loading: false, //遮罩
|
||||||
dialogVisible: false, //新增文件弹窗
|
dialogVisible: false, //新增文件弹窗
|
||||||
ruleList: [], //当前生效的规则
|
ruleList: [], //当前生效的规则
|
||||||
fileList: [], //选择的文件
|
fileList: [], //选择的文件
|
||||||
changedFileList: [], //执行修改后的文件
|
changedFileList: [], //执行修改后的文件
|
||||||
needPreview: false, //需要点击预览
|
|
||||||
applicationRule: null, //当前应用的应用规则模板
|
applicationRule: null, //当前应用的应用规则模板
|
||||||
savePathList: [], //收藏的路径列表
|
savePathList: [], //收藏的路径列表
|
||||||
curChoosePath: null, //当前选择的收藏路径
|
curChoosePath: null, //当前选择的收藏路径
|
||||||
timer: null, //修改顺序计时器
|
timer: null, //修改顺序计时器
|
||||||
|
newName: "", //新的文件名
|
||||||
|
currentEditFile: null,
|
||||||
|
showNameEditDialog: false //显示编辑文件弹窗
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
async created () {
|
async created() {
|
||||||
this.savePathList = await HttpUtil.get("/file/path");
|
this.savePathList = await HttpUtil.get("/file/path");
|
||||||
window.isWindows = await HttpUtil.get("/file/isWindows");
|
window.isWindows = await HttpUtil.get("/file/isWindows");
|
||||||
Bus.$on("refreshSavePathList", this.refreshSavePathList);
|
Bus.$on("refreshSavePathList", this.refreshSavePathList);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
//新增文件
|
//新增文件
|
||||||
async addData (data) {
|
async addData(data) {
|
||||||
|
let existSet = new Set();
|
||||||
data.forEach((item) => (item.checked = false));
|
data.forEach((item) => (item.checked = false));
|
||||||
this.fileList.push(...data);
|
this.fileList.forEach(item => existSet.add(item.path + item.name));
|
||||||
|
this.fileList.push(...data.filter(item => !existSet.has(item.path + item.name)));
|
||||||
this.fileList = [...this.fileList.sort((a, b) => compareStr(a.name, b.name))];
|
this.fileList = [...this.fileList.sort((a, b) => compareStr(a.name, b.name))];
|
||||||
this.dialogVisible = false;
|
this.dialogVisible = false;
|
||||||
this.needPreview = true;
|
|
||||||
await this.showResult();
|
await this.showResult();
|
||||||
},
|
},
|
||||||
async ruleUpdate (rules) {
|
async ruleUpdate(rules) {
|
||||||
this.ruleList = rules;
|
this.ruleList = rules;
|
||||||
this.needPreview = true;
|
|
||||||
await this.showResult();
|
await this.showResult();
|
||||||
},
|
},
|
||||||
//预览结果
|
//预览结果
|
||||||
async showResult () {
|
async showResult() {
|
||||||
this.changedFileList = [];
|
this.changedFileList = [];
|
||||||
if (!this.checkRuleAndFile()) {
|
if (!this.checkRuleAndFile()) {
|
||||||
return;
|
return;
|
||||||
@ -124,16 +154,15 @@ export default {
|
|||||||
};
|
};
|
||||||
this.changedFileList = await HttpUtil.post("/renamer/preview", null, body);
|
this.changedFileList = await HttpUtil.post("/renamer/preview", null, body);
|
||||||
this.fileList = [...this.fileList];
|
this.fileList = [...this.fileList];
|
||||||
this.needPreview = false;
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
},
|
},
|
||||||
//提交
|
//提交
|
||||||
async submit () {
|
async submit() {
|
||||||
if (!this.checkRuleAndFile()) {
|
if (!this.checkRuleAndFile()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.changedFileList.filter((item) => item.errorMessage).length > 0) {
|
if (this.changedFileList.filter((item) => item.errorMessage).length > 0) {
|
||||||
this.$message({ message: "存在错误,无法执行操作", type: "error" });
|
this.$message({message: "存在错误,无法执行操作", type: "error"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
@ -143,48 +172,80 @@ export default {
|
|||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await HttpUtil.post("/renamer/submit", null, body);
|
await HttpUtil.post("/renamer/submit", null, body);
|
||||||
this.$message({ message: "重命名成功", type: "success" });
|
this.$message({message: "重命名成功", type: "success"});
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
//删除选中的文件名
|
//移除选中的文件名
|
||||||
async deleteCheckedFiles () {
|
async removeCheckedFiles() {
|
||||||
this.fileList = this.fileList.filter((item) => !item.checked);
|
this.fileList = this.fileList.filter((item) => !item.checked);
|
||||||
this.needPreview = true;
|
await this.showResult();
|
||||||
|
},
|
||||||
|
//delete checked item
|
||||||
|
async deleteCheckedFiles() {
|
||||||
|
let body = this.fileList.filter((item) => item.checked);
|
||||||
|
await HttpUtil.post("/file/deleteBatch", null, body);
|
||||||
|
this.fileList = this.fileList.filter((item) => !item.checked);
|
||||||
|
await this.showResult();
|
||||||
|
},
|
||||||
|
//edit file
|
||||||
|
async editFile() {
|
||||||
|
let list = this.fileList.filter((item) => item.checked);
|
||||||
|
if (list.length === 0 || list.length > 1) {
|
||||||
|
this.$message({message: "只能选择一个进行编辑", type: "warning"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.newName = list[0].name;
|
||||||
|
this.currentEditFile = list[0];
|
||||||
|
this.showNameEditDialog = true;
|
||||||
|
await this.showResult();
|
||||||
|
},
|
||||||
|
async doEditFile() {
|
||||||
|
if (!this.newName) {
|
||||||
|
this.$message({message: "文件名不能为空", type: "warning"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let target = JSON.parse(JSON.stringify(this.currentEditFile));
|
||||||
|
target.name = this.newName;
|
||||||
|
await HttpUtil.post("/file/rename", null, {source: this.currentEditFile, target});
|
||||||
|
this.currentEditFile.name = this.newName;
|
||||||
|
this.fileList = [...this.fileList];
|
||||||
|
this.currentEditFile = null;
|
||||||
|
this.showNameEditDialog = false;
|
||||||
await this.showResult();
|
await this.showResult();
|
||||||
},
|
},
|
||||||
//反选
|
//反选
|
||||||
selectAllFiles () {
|
selectAllFiles() {
|
||||||
this.fileList.forEach((item) => (item.checked = !item.checked));
|
this.fileList.forEach((item) => (item.checked = !item.checked));
|
||||||
},
|
},
|
||||||
//检查规则和文件
|
//检查规则和文件
|
||||||
checkRuleAndFile () {
|
checkRuleAndFile() {
|
||||||
if (this.fileList.length == 0) {
|
if (this.fileList.length === 0) {
|
||||||
this.$message({ message: "请选择文件", type: "warning" });
|
this.$message({message: "请选择文件", type: "warning"});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.ruleList.filter((item) => !item.blocked).length == 0) {
|
if (this.ruleList.filter((item) => !item.blocked).length === 0) {
|
||||||
this.$message({ message: "无生效规则", type: "warning" });
|
this.$message({message: "无生效规则", type: "warning"});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
//移动文件顺序
|
//移动文件顺序
|
||||||
async moveIndex (type) {
|
async moveIndex(type) {
|
||||||
let temps = this.fileList.filter((item) => item.checked == true);
|
let temps = this.fileList.filter((item) => item.checked === true);
|
||||||
if (temps.length == 0) {
|
if (temps.length === 0) {
|
||||||
this.$message({ type: "warning", message: "未选中文件,无法移动" });
|
this.$message({type: "warning", message: "未选中文件,无法移动"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == "top") {
|
if (type == "top") {
|
||||||
if (this.fileList.indexOf(temps[0]) == 0) {
|
if (this.fileList.indexOf(temps[0]) == 0) {
|
||||||
this.$message({ type: "warning", message: "无法上移" });
|
this.$message({type: "warning", message: "无法上移"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.fileList.indexOf(temps[temps.length - 1]) == this.fileList.length - 1) {
|
if (this.fileList.indexOf(temps[temps.length - 1]) == this.fileList.length - 1) {
|
||||||
this.$message({ type: "warning", message: "无法下移" });
|
this.$message({type: "warning", message: "无法下移"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
temps = temps.reverse();
|
temps = temps.reverse();
|
||||||
@ -197,7 +258,6 @@ export default {
|
|||||||
this.fileList[newIndex] = temp;
|
this.fileList[newIndex] = temp;
|
||||||
}
|
}
|
||||||
this.fileList = [...this.fileList];
|
this.fileList = [...this.fileList];
|
||||||
this.needPreview = true;
|
|
||||||
if (this.timer != null) {
|
if (this.timer != null) {
|
||||||
clearTimeout(this.timer);
|
clearTimeout(this.timer);
|
||||||
}
|
}
|
||||||
@ -206,20 +266,20 @@ export default {
|
|||||||
this.timer = null;
|
this.timer = null;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
},
|
},
|
||||||
showFileAdd () {
|
showFileAdd() {
|
||||||
this.dialogVisible = true;
|
this.dialogVisible = true;
|
||||||
},
|
},
|
||||||
//点击收藏路径
|
//点击收藏路径
|
||||||
async clickSavePath (item) {
|
async clickSavePath(item) {
|
||||||
this.curChoosePath = JSON.parse(item.content);
|
this.curChoosePath = JSON.parse(item.content);
|
||||||
this.dialogVisible = true;
|
this.dialogVisible = true;
|
||||||
},
|
},
|
||||||
async deleteSavePath (item) {
|
async deleteSavePath(item) {
|
||||||
console.log(item);
|
console.log(item);
|
||||||
await HttpUtil.delete("/file/path/delete", { id: item.id });
|
await HttpUtil.delete("/file/path/delete", {id: item.id});
|
||||||
Bus.$emit("refreshSavePathList");
|
Bus.$emit("refreshSavePathList");
|
||||||
},
|
},
|
||||||
async refreshSavePathList () {
|
async refreshSavePathList() {
|
||||||
this.savePathList = await HttpUtil.get("/file/path");
|
this.savePathList = await HttpUtil.get("/file/path");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -230,13 +290,13 @@ export default {
|
|||||||
* @param a str
|
* @param a str
|
||||||
* @param b str
|
* @param b str
|
||||||
*/
|
*/
|
||||||
function compareStr (a, b) {
|
function compareStr(a, b) {
|
||||||
let an = a.length;
|
let an = a.length;
|
||||||
let bn = b.length;
|
let bn = b.length;
|
||||||
for (let i = 0; i < an;) {
|
for (let i = 0; i < an;) {
|
||||||
let charA = readChar(a, i, an);
|
let charA = readChar(a, i, an);
|
||||||
let charB = readChar(b, i, bn);
|
let charB = readChar(b, i, bn);
|
||||||
if (charB.length == 0) {
|
if (charB.length === 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (charA !== charB) {
|
if (charA !== charB) {
|
||||||
@ -255,7 +315,7 @@ function compareStr (a, b) {
|
|||||||
* @param a a
|
* @param a a
|
||||||
* @param n 数字长度
|
* @param n 数字长度
|
||||||
*/
|
*/
|
||||||
function readChar (a, i, n) {
|
function readChar(a, i, n) {
|
||||||
let res = "";
|
let res = "";
|
||||||
for (; i < n; i++) {
|
for (; i < n; i++) {
|
||||||
let char = a.charAt(i);
|
let char = a.charAt(i);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user