Compare commits
5 Commits
a0e0186c63
...
20513d14da
Author | SHA1 | Date | |
---|---|---|---|
20513d14da | |||
698087c8bf | |||
c43f406a29 | |||
5b33be94ba | |||
ef92c13a4f |
5
openRenamerBackend/.gitignore
vendored
5
openRenamerBackend/.gitignore
vendored
@ -15,3 +15,8 @@ static/*
|
|||||||
!static/.gitkeep
|
!static/.gitkeep
|
||||||
database.db
|
database.db
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
|
ndist/index.js
|
||||||
|
app
|
||||||
|
app.exe
|
||||||
|
/ndist/lib/binding/napi-v6-darwin-unknown-arm64/node_sqlite3.node.bak
|
||||||
|
1
openRenamerBackend/.idea/openRenamerBackend.iml
generated
1
openRenamerBackend/.idea/openRenamerBackend.iml
generated
@ -5,6 +5,7 @@
|
|||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.vscode" />
|
<excludeFolder url="file://$MODULE_DIR$/.vscode" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/ndist" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
7
openRenamerBackend/build.sh
Normal file
7
openRenamerBackend/build.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# shellcheck disable=SC2164
|
||||||
|
cd ../openRenamerFront
|
||||||
|
npm run build
|
||||||
|
cp -r dist/* ../openRenamerBackend/static
|
||||||
|
cd ../openRenamerBackend
|
||||||
|
npm run ncc
|
||||||
|
npm run pkg
|
@ -3,15 +3,26 @@ import * as process from "process";
|
|||||||
|
|
||||||
//后台所在绝对路径
|
//后台所在绝对路径
|
||||||
const rootPath = path.resolve(__dirname, '..');
|
const rootPath = path.resolve(__dirname, '..');
|
||||||
|
let map = {};
|
||||||
|
console.log(process.argv);
|
||||||
|
//argv 传递 port,dataPath,env,token
|
||||||
|
for (let i = 2; i < process.argv.length; i++) {
|
||||||
|
if (process.argv[i] != null && process.argv[i] != '') {
|
||||||
|
let strings = process.argv[i].split(":");
|
||||||
|
map[strings[0]] = strings[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let config = {
|
let config = {
|
||||||
rootPath,
|
rootPath,
|
||||||
dataPath: process.env.DATA_PATH ? process.env.DATA_PATH : path.join(rootPath, 'data'),
|
dataPath: map['dataPath'] ? map['dataPath'] : process.env.DATA_PATH ? process.env.DATA_PATH : path.join(rootPath, 'data'),
|
||||||
port: process.env.PORT ? parseInt(process.env.PORT) : 8089,
|
port: map['port'] ? parseInt(map['port']) : process.env.PORT ? parseInt(process.env.PORT) : 8089,
|
||||||
token: process.env.TOKEN ? process.env.TOKEN : null,
|
token: map['token'] ? map['token'] : process.env.TOKEN ? process.env.TOKEN : null,
|
||||||
|
env: map['env'] ? map['env'] : process.env.ENV ? process.env.ENV : "dev",
|
||||||
urlPrefix: '/openRenamer/api',
|
urlPrefix: '/openRenamer/api',
|
||||||
//是否为windows平台
|
//是否为windows平台
|
||||||
isWindows: process.platform.toLocaleLowerCase().includes("win"),
|
isWindows: process.platform.toLocaleLowerCase().includes("win32"),
|
||||||
|
isMac: process.platform.toLocaleLowerCase().includes("darwin"),
|
||||||
bodyLimit: {
|
bodyLimit: {
|
||||||
formLimit: '200mb',
|
formLimit: '200mb',
|
||||||
jsonLimit: '200mb',
|
jsonLimit: '200mb',
|
||||||
|
10
openRenamerBackend/entity/dto/QbCommonDto.ts
Normal file
10
openRenamerBackend/entity/dto/QbCommonDto.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export default interface QbCommonDto {
|
||||||
|
method: string;
|
||||||
|
url: string;
|
||||||
|
query: any;
|
||||||
|
body: any;
|
||||||
|
/**
|
||||||
|
* 1:application/json 2:formdata 3:application/x-www-form-urlencoded
|
||||||
|
*/
|
||||||
|
contentType: number;
|
||||||
|
}
|
7
openRenamerBackend/i18n/global.yaml
Normal file
7
openRenamerBackend/i18n/global.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
key-error:
|
||||||
|
en: Secret error
|
||||||
|
zh: 秘钥错误
|
||||||
|
qb:
|
||||||
|
version-error:
|
||||||
|
en: qBittorrent version must be V4.xx
|
||||||
|
zh: qBittorrent 版本必须为V4.xx
|
34
openRenamerBackend/i18n/index.ts
Normal file
34
openRenamerBackend/i18n/index.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import YAML from 'yaml';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path'
|
||||||
|
import config from '../config'
|
||||||
|
import logger from '../util/LogUtil';
|
||||||
|
|
||||||
|
const map = {};
|
||||||
|
|
||||||
|
export function init() {
|
||||||
|
let i18nFolder = path.join(config.rootPath, 'i18n');
|
||||||
|
let files = fs.readdirSync(i18nFolder).filter(item => item.endsWith(".yaml"));
|
||||||
|
files.forEach(file => {
|
||||||
|
let res = YAML.parse(fs.readFileSync(path.join(i18nFolder, file), 'utf-8'));
|
||||||
|
dealYaml("", res);
|
||||||
|
})
|
||||||
|
logger.info("i18n加载完毕");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMessage(lang: string, key: string): string {
|
||||||
|
let val = map[key + "." + (lang ? lang : 'en')];
|
||||||
|
return val ? val : key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dealYaml(pre: string, res: any) {
|
||||||
|
Object.keys(res).forEach(key => {
|
||||||
|
let val = res[key];
|
||||||
|
let mapKey = pre == '' ? key : (pre + "." + key);
|
||||||
|
if (typeof val != "object") {
|
||||||
|
map[mapKey] = val;
|
||||||
|
} else {
|
||||||
|
dealYaml(mapKey, val);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -9,9 +9,10 @@ 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 QbService from './service/QbService';
|
|
||||||
import qbService from "./service/QbService";
|
import qbService from "./service/QbService";
|
||||||
|
import * as i18n from './i18n';
|
||||||
|
|
||||||
|
let start = Date.now();
|
||||||
console.log(config);
|
console.log(config);
|
||||||
|
|
||||||
const app = new koa();
|
const app = new koa();
|
||||||
@ -32,9 +33,10 @@ 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 qbService.init();
|
qbService.init();
|
||||||
|
i18n.init();
|
||||||
app.listen(config.port);
|
app.listen(config.port);
|
||||||
log.info(`server listened `, config.port);
|
log.info(`server listened ${config.port},cost:${Date.now() - start}ms`);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
app.on("error", (error) => {
|
app.on("error", (error) => {
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
import log from '../util/LogUtil';
|
import log from '../util/LogUtil';
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
|
import {getMessage} from "../i18n";
|
||||||
|
|
||||||
let f = async (ctx, next) => {
|
let f = async (ctx, next) => {
|
||||||
|
let lang = ctx.request.headers['lang'];
|
||||||
try {
|
try {
|
||||||
//检查是否有密码
|
//检查是否有密码
|
||||||
if (checkToken(ctx)) {
|
if (checkToken(ctx)) {
|
||||||
await next();
|
await next();
|
||||||
} else {
|
} else {
|
||||||
ctx.status = 401;
|
ctx.status = 401;
|
||||||
ctx.body = "密钥验证错误";
|
ctx.body = getMessage(lang, "key-error");
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error.status != undefined) {
|
if (error.status != undefined) {
|
||||||
@ -16,7 +18,7 @@ let f = async (ctx, next) => {
|
|||||||
} else {
|
} else {
|
||||||
ctx.status = 500;
|
ctx.status = 500;
|
||||||
}
|
}
|
||||||
ctx.body = error.message;
|
ctx.body = getMessage(lang, error.message);
|
||||||
log.error(error);
|
log.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ export default async (ctx, next) => {
|
|||||||
ctx.set("X-Powered-By", ' 3.2.1');
|
ctx.set("X-Powered-By", ' 3.2.1');
|
||||||
ctx.set("Content-Type", "application/json;charset=utf-8");
|
ctx.set("Content-Type", "application/json;charset=utf-8");
|
||||||
//合并请求参数到allParams
|
//合并请求参数到allParams
|
||||||
let objs = new Array();
|
let objs = [];
|
||||||
if (ctx.method == "POST" || ctx.method == "PUT") {
|
if (ctx.method == "POST" || ctx.method == "PUT") {
|
||||||
if (ctx.request.body) {
|
if (ctx.request.body) {
|
||||||
if (ctx.request.body.fields != undefined && ctx.request.body.files != undefined) {
|
if (ctx.request.body.fields != undefined && ctx.request.body.files != undefined) {
|
||||||
|
Binary file not shown.
@ -4,7 +4,16 @@
|
|||||||
"description": "文件备份用",
|
"description": "文件备份用",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"pkg": "tsc && pkg . -t macos -o app"
|
||||||
|
},
|
||||||
|
"bin": "dist/index.js",
|
||||||
|
"pkg": {
|
||||||
|
"assets": [
|
||||||
|
"dist/**/*",
|
||||||
|
"static/**/**",
|
||||||
|
"sqls/*",
|
||||||
|
"i18n/*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"author": "fxb",
|
"author": "fxb",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@ -12,17 +21,18 @@
|
|||||||
"@types/fs-extra": "5.0.4",
|
"@types/fs-extra": "5.0.4",
|
||||||
"@types/koa": "2.13.12",
|
"@types/koa": "2.13.12",
|
||||||
"@types/node": "11.13.4",
|
"@types/node": "11.13.4",
|
||||||
"axios": "0.21.4",
|
"axios": "0.29.0",
|
||||||
"fs-extra": "7.0.0",
|
"fs-extra": "7.0.0",
|
||||||
"koa": "2.5.3",
|
"koa": "3.0.0-alpha.3",
|
||||||
"koa-body": "4.0.4",
|
"koa-body": "4.0.4",
|
||||||
"koa-router": "7.4.0",
|
"koa-router": "7.4.0",
|
||||||
"koa-static": "5.0.0",
|
"koa-static": "5.0.0",
|
||||||
"koa2-cors": "2.0.6",
|
"koa2-cors": "2.0.6",
|
||||||
"log4js": "6.3.0",
|
"log4js": "6.4.0",
|
||||||
"moment": "2.22.2",
|
"moment": "2.29.4",
|
||||||
"sqlite": "4.0.23",
|
"sqlite": "5.1.1",
|
||||||
"sqlite3": "5.0.2",
|
"sqlite3": "5.1.5",
|
||||||
"uuid": "3.3.2"
|
"uuid": "3.3.2",
|
||||||
|
"yaml": "2.7.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1592
openRenamerBackend/pnpm-lock.yaml
generated
1592
openRenamerBackend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,10 @@
|
|||||||
import QbConfigDto from "../entity/dto/QbConfigDto";
|
import QbConfigDto from "../entity/dto/QbConfigDto";
|
||||||
import {tryLogin, get, post, updateQbInfo, getQbInfo} from '../util/QbApiUtil';
|
import {get, getQbInfo, post, tryLogin, updateQbInfo} from '../util/QbApiUtil';
|
||||||
import GlobalConfigService from "./GlobalConfigService";
|
import GlobalConfigService from "./GlobalConfigService";
|
||||||
import GlobalConfig from "../entity/po/GlobalConfig";
|
import GlobalConfig from "../entity/po/GlobalConfig";
|
||||||
import BtListItemDto from "../entity/dto/BtListItemDto";
|
import BtListItemDto from "../entity/dto/BtListItemDto";
|
||||||
|
import QbCommonDto from "../entity/dto/QbCommonDto";
|
||||||
|
import logger from "../util/LogUtil";
|
||||||
|
|
||||||
class QbService {
|
class QbService {
|
||||||
|
|
||||||
@ -14,13 +16,18 @@ class QbService {
|
|||||||
if (body.address.endsWith("/")) {
|
if (body.address.endsWith("/")) {
|
||||||
body.address = body.address.substring(0, body.address.length - 1);
|
body.address = body.address.substring(0, body.address.length - 1);
|
||||||
}
|
}
|
||||||
await GlobalConfigService.insertOrReplace(new GlobalConfig("qbConfig", JSON.stringify(body), "qb config"));
|
|
||||||
updateQbInfo(body);
|
updateQbInfo(body);
|
||||||
body.valid = await tryLogin();
|
body.valid = await tryLogin();
|
||||||
body.version = body ? (await get("/app/version", null)) : null;
|
body.version = body ? (await get("/app/version", null)) : null;
|
||||||
|
if (parseFloat(body.version.replace("v", "")) < 4.1) {
|
||||||
|
body.valid = false;
|
||||||
|
body.version = null;
|
||||||
|
throw new Error("qb.version-error");
|
||||||
|
}
|
||||||
|
await GlobalConfigService.insertOrReplace(new GlobalConfig("qbConfig", JSON.stringify(body), "qb config"));
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
a
|
|
||||||
/**
|
/**
|
||||||
* 获取当前配置
|
* 获取当前配置
|
||||||
*/
|
*/
|
||||||
@ -36,6 +43,16 @@ a
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async commonGet(body: QbCommonDto): Promise<any> {
|
||||||
|
return await get(body.url, body.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async commonPost(body: QbCommonDto): Promise<any> {
|
||||||
|
return await post(body.url, body.query, body.body, body.contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化
|
* 初始化
|
||||||
*/
|
*/
|
||||||
@ -45,7 +62,6 @@ a
|
|||||||
updateQbInfo(qbInfo);
|
updateQbInfo(qbInfo);
|
||||||
qbInfo.valid = await tryLogin();
|
qbInfo.valid = await tryLogin();
|
||||||
qbInfo.version = qbInfo.valid ? (await get("/app/version", null)) : null;
|
qbInfo.version = qbInfo.valid ? (await get("/app/version", null)) : null;
|
||||||
return qbInfo;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,24 +16,40 @@ export function getQbInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function get(url: string, data: object) {
|
export async function get(url: string, data: object) {
|
||||||
return await request("get", url, data, null, false);
|
return await request("get", url, data, null, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function post(url: string, data: object, isForm = false) {
|
/**
|
||||||
return await request("post", url, null, data, isForm);
|
*
|
||||||
|
* @param url
|
||||||
|
* @param data
|
||||||
|
* @param formType 1:application/json 2:formdata 3:application/x-www-form-urlencoded
|
||||||
|
*/
|
||||||
|
export async function post(url: string, query: any, data: object, formType = 1) {
|
||||||
|
return await request("post", url, query, data, formType);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function request(method: Method, url: string, query: any, body: any, isForm = false) {
|
/**
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @param data
|
||||||
|
* @param formType 1:application/json 2:formdata 3:application/x-www-form-urlencoded
|
||||||
|
*/
|
||||||
|
async function request(method: Method, url: string, query: any, body: any, formType = 1) {
|
||||||
if (!qbInfo.valid) {
|
if (!qbInfo.valid) {
|
||||||
throw new Error("qbittorrent无法连接,请检查配置");
|
throw new Error("qbittorrent无法连接,请检查配置");
|
||||||
}
|
}
|
||||||
let isTryLogin = false;
|
let isTryLogin = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
let headers = {"Cookie": cookie};
|
let headers = {"Cookie": cookie};
|
||||||
if (isForm) {
|
if (method == 'post') {
|
||||||
headers['content-type'] = "multipart/form-data";
|
if (formType == 1) {
|
||||||
} else if (method == "post") {
|
|
||||||
headers['content-type'] = "application/json";
|
headers['content-type'] = "application/json";
|
||||||
|
} else if (formType == 2) {
|
||||||
|
headers['content-type'] = "multipart/form-data";
|
||||||
|
} else {
|
||||||
|
headers['content-type'] = "application/x-www-form-urlencoded";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let res = await axios.request({
|
let res = await axios.request({
|
||||||
baseURL: qbInfo.address,
|
baseURL: qbInfo.address,
|
||||||
@ -75,8 +91,8 @@ export async function tryLogin(): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
qbInfo.valid = success;
|
qbInfo.valid = success;
|
||||||
return success;
|
return success;
|
||||||
} catch (error) {
|
} catch (error:any) {
|
||||||
console.error("登录报错:", error);
|
console.error("qb登录报错:" );
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,13 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "2.0.10",
|
"@element-plus/icons-vue": "^2.0.10",
|
||||||
"axios": "1.6.0",
|
"axios": "1.6.0",
|
||||||
"core-js": "3.35.0",
|
"core-js": "3.35.0",
|
||||||
"dayjs": "1.10.7",
|
"dayjs": "1.10.7",
|
||||||
"element-plus": "2.2.25",
|
"element-plus": "2.2.25",
|
||||||
"vue": "3.2.45",
|
"vue": "3.2.45",
|
||||||
|
"vue-i18n": "9.5.0",
|
||||||
"vue-router": "4.2.5"
|
"vue-router": "4.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,73 +1,90 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app">
|
<div class="app">
|
||||||
|
<div class="header">
|
||||||
<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="/">{{ $t("menu.rename") }}</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>{{ $t("menu.download") }}</template>
|
||||||
<el-menu-item index="/download/center">下载中心</el-menu-item>
|
<el-menu-item index="/download/center">{{ $t("menu.downloadHome") }}</el-menu-item>
|
||||||
<el-menu-item index="/download/config">配置</el-menu-item>
|
<el-menu-item index="/download/config">{{ $t("menu.downloadConfig") }}</el-menu-item>
|
||||||
</el-sub-menu> -->
|
</el-sub-menu>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
<div class="content">
|
<el-dropdown style="position: absolute;right:1em;top:1em;color: white;cursor: pointer" @command="langChange">
|
||||||
<router-view/>
|
{{ $t("langChange") }} : {{ data.curLangLabel }}
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item v-for="item in data.langList" :key="item.code" :command="item.code">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">版本:
|
<div class="content">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
<div class="footer">{{ $t("version") }}:
|
||||||
<el-tooltip effect="dark" content="点击查看更新记录" placement="top">
|
<el-tooltip effect="dark" content="点击查看更新记录" placement="top">
|
||||||
<a href="https://blog.fleyx.com/blog/detail/20221130/#%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95"
|
<a href="https://blog.fleyx.com/blog/detail/20221130/#%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95"
|
||||||
target="_blank">
|
target="_blank">
|
||||||
{{ version }}</a>
|
{{ data.version }}</a>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<template v-if="latestVersion && showNewVersion">
|
<template v-if="data.latestVersion && data.showNewVersion">
|
||||||
最新版本:
|
{{ $t("newestVersion") }}:
|
||||||
<el-tooltip effect="dark" content="点击查看更新文档" placement="top">
|
<el-tooltip effect="dark" content="点击查看更新文档" placement="top">
|
||||||
<a href="https://blog.fleyx.com/blog/detail/20221130/#%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95"
|
<a href="https://blog.fleyx.com/blog/detail/20221130/#%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95"
|
||||||
target="_blank">
|
target="_blank">
|
||||||
{{ latestVersion }}</a>
|
{{ data.latestVersion }}</a>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
开源地址:<a href="https://github.com/FleyX/open-renamer" target="_blank">open-renamer</a>
|
{{ $t("openSourceLocation") }}:<a href="https://github.com/FleyX/open-renamer">github open-renamer</a>
|
||||||
<a href="https://github.com/FleyX/open-renamer/issues" target="_blank">反馈</a>
|
<a href="https://github.com/FleyX/open-renamer/issues">{{ $t("feedback") }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
|
import { onBeforeMount, reactive } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { locale, t } = useI18n();
|
||||||
import httpUtil from "./utils/HttpUtil";
|
import httpUtil from "./utils/HttpUtil";
|
||||||
|
|
||||||
export default {
|
const data = reactive({
|
||||||
name: "Home",
|
version: "1.7.2",
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
version: "1.8.0",
|
|
||||||
latestVersion: null,
|
latestVersion: null,
|
||||||
activeIndex: location.pathname,
|
activeIndex: location.pathname,
|
||||||
showNewVersion: false
|
showNewVersion: false,
|
||||||
};
|
curLangLabel: "",
|
||||||
},
|
langList: [{ code: "en", label: "English" },
|
||||||
async beforeCreate() {
|
{ code: "zh", label: "中文" }]
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
window.token = localStorage.getItem("token");
|
window.token = localStorage.getItem("token");
|
||||||
window.isWindows = await httpUtil.get("/file/isWindows");
|
window.isWindows = await httpUtil.get("/file/isWindows");
|
||||||
},
|
|
||||||
async created() {
|
|
||||||
//获取最新版本
|
//获取最新版本
|
||||||
let config = await httpUtil.get("https://s3.fleyx.com/picbed/openRenamer/config.json");
|
let config = await httpUtil.get("https://s3.fleyx.com/picbed/openRenamer/config.json");
|
||||||
this.latestVersion = config.version;
|
data.latestVersion = config.version;
|
||||||
this.showNewVersion = checkVersion(this.version, this.latestVersion);
|
data.showNewVersion = checkVersion(data.version, data.latestVersion);
|
||||||
|
data.curLangLabel = data.langList.filter(item => item.code === locale.value)[0].label;
|
||||||
|
console.log(data.curLangLabel);
|
||||||
|
});
|
||||||
|
|
||||||
},
|
function langChange(command) {
|
||||||
async mounted() {
|
data.curLangLabel = data.langList.filter(item => command === item.code)[0].label;
|
||||||
console.log(this.$route);
|
locale.value = command;
|
||||||
console.log(location);
|
localStorage.setItem("lang", command);
|
||||||
},
|
console.log(command);
|
||||||
};
|
}
|
||||||
|
|
||||||
function checkVersion(version, latestVersion) {
|
function checkVersion(version, latestVersion) {
|
||||||
let versions = version.split(".");
|
let versions = version.split(".");
|
||||||
let latestVersions = latestVersion.split('.');
|
let latestVersions = latestVersion.split(".");
|
||||||
for (let i = 0; i < versions.length; i++) {
|
for (let i = 0; i < versions.length; i++) {
|
||||||
if (i >= latestVersions.length) {
|
if (i >= latestVersions.length) {
|
||||||
return false;
|
return false;
|
||||||
@ -109,6 +126,10 @@ body {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 0 10px 0 10px;
|
padding: 0 10px 0 10px;
|
||||||
|
35
openRenamerFront/src/i18n/en.js
Normal file
35
openRenamerFront/src/i18n/en.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
export default {
|
||||||
|
langChange: "change language",
|
||||||
|
version: "version",
|
||||||
|
newestVersion: "latest version",
|
||||||
|
openSourceLocation: "Open source address",
|
||||||
|
feedback: "Feedback",
|
||||||
|
menu: {
|
||||||
|
rename: "Rename",
|
||||||
|
download: "QBittorrent Download",
|
||||||
|
downloadConfig: "Config",
|
||||||
|
downloadHome: "Download center"
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
success: "action success",
|
||||||
|
fail: "action fail",
|
||||||
|
edit: "edit",
|
||||||
|
cancel: "cancel",
|
||||||
|
submit: "submit",
|
||||||
|
confirm: "confirm"
|
||||||
|
},
|
||||||
|
qbConfig: {
|
||||||
|
address: "Deploy address",
|
||||||
|
addressAlt: "Example: http://localhost:8080 (only v4.1 and above)",
|
||||||
|
error: "Error",
|
||||||
|
version: "Version",
|
||||||
|
username: "Username",
|
||||||
|
usernameAlt: "QBittorrent username",
|
||||||
|
password: "Password",
|
||||||
|
passwordAlt: "QBittorrent password",
|
||||||
|
downloadPath: "QB download path",
|
||||||
|
downloadPathAlt: "qBittorrent download path (this will need to be configured if qbittorrent and open-renamer are deployed in different docker containers)",
|
||||||
|
localPath: "Local path",
|
||||||
|
localPathAlt: "Corresponding to the path of the system (if qbittorrent and open-renamer are deployed in different docker containers, this parameter needs to be configured)"
|
||||||
|
}
|
||||||
|
};
|
35
openRenamerFront/src/i18n/zh.js
Normal file
35
openRenamerFront/src/i18n/zh.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
export default {
|
||||||
|
langChange: "选择语言",
|
||||||
|
version: "版本",
|
||||||
|
newestVersion: "最新版本",
|
||||||
|
openSourceLocation: "开源地址",
|
||||||
|
feedback: "反馈",
|
||||||
|
menu: {
|
||||||
|
rename: "重命名",
|
||||||
|
download: "qBittorrent下载",
|
||||||
|
downloadConfig: "配置",
|
||||||
|
downloadHome: "下载中心"
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
success: "操作成功",
|
||||||
|
fail: "操作失败",
|
||||||
|
edit: "编辑",
|
||||||
|
cancel: "取消",
|
||||||
|
submit: "提交",
|
||||||
|
confirm: "确认"
|
||||||
|
},
|
||||||
|
qbConfig: {
|
||||||
|
address: "部署地址",
|
||||||
|
addressAlt: "例如:http://localhost:8080(仅支持v4.1及以上)",
|
||||||
|
error: "配置错误",
|
||||||
|
version: "版本",
|
||||||
|
username: "用户名",
|
||||||
|
usernameAlt: "qBittorrent 用户名",
|
||||||
|
password: "密码",
|
||||||
|
passwordAlt: "qBittorrent 密码",
|
||||||
|
downloadPath: "qb下载路径",
|
||||||
|
downloadPathAlt: "qb下载路径(如果qbittorrent和open-renamer部署在不同的docker容器中,需要配置此项)",
|
||||||
|
localPath: "对应本系统路径",
|
||||||
|
localPathAlt: "对应本系统路径(如果qbittorrent和open-renamer部署在不同的docker容器中,需要配置此项)"
|
||||||
|
}
|
||||||
|
};
|
@ -2,9 +2,29 @@ import { createApp } from "vue";
|
|||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
import ElementPlus, { ElMessage } from "element-plus";
|
import ElementPlus, { ElMessage } from "element-plus";
|
||||||
|
import { createI18n } from "vue-i18n";
|
||||||
import "element-plus/dist/index.css";
|
import "element-plus/dist/index.css";
|
||||||
|
|
||||||
|
import en from "./i18n/en";
|
||||||
|
import zh from "./i18n/zh";
|
||||||
|
|
||||||
|
const messages = {
|
||||||
|
en,
|
||||||
|
zh
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const lang = (navigator.language || "en").toLocaleLowerCase();
|
||||||
|
const locale = localStorage.getItem("lang") || lang.split("-")[0] || "en";
|
||||||
|
console.log(messages, locale);
|
||||||
|
const i18n = createI18n({
|
||||||
|
legacy: false,
|
||||||
|
locale,
|
||||||
|
fallbackLocale: "en",
|
||||||
|
messages
|
||||||
|
});
|
||||||
|
|
||||||
const vueInstance = createApp(App);
|
const vueInstance = createApp(App);
|
||||||
vueInstance.use(router).use(ElementPlus).mount("#app");
|
vueInstance.use(router).use(ElementPlus).use(i18n).mount("#app");
|
||||||
vueInstance.config.globalProperties.$message = ElMessage;
|
vueInstance.config.globalProperties.$message = ElMessage;
|
||||||
window.vueInstance = vueInstance;
|
window.vueInstance = vueInstance;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as http from 'axios';
|
import * as http from "axios";
|
||||||
import router from '../router/index';
|
import router from "../router/index";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求
|
* 请求
|
||||||
@ -14,13 +14,13 @@ import router from '../router/index';
|
|||||||
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, lang: localStorage.getItem("lang") }
|
||||||
};
|
};
|
||||||
if (isForm) {
|
if (isForm) {
|
||||||
options.headers['Content-Type'] = 'multipart/form-data';
|
options.headers["Content-Type"] = "multipart/form-data";
|
||||||
}
|
}
|
||||||
if (body) {
|
if (body) {
|
||||||
options.data = body;
|
options.data = body;
|
||||||
@ -32,12 +32,12 @@ async function request(url, method, params, body, isForm) {
|
|||||||
console.log(Object.keys(err));
|
console.log(Object.keys(err));
|
||||||
console.log(err.response);
|
console.log(err.response);
|
||||||
if (err.response.status === 401) {
|
if (err.response.status === 401) {
|
||||||
window.vueInstance.config.globalProperties.$message.error('密钥验证错误');
|
window.vueInstance.config.globalProperties.$message.error("密钥验证错误");
|
||||||
router.push("/public/login");
|
router.push("/public/login");
|
||||||
} else if (err.response.status === 400) {
|
} else if (err.response.status === 400) {
|
||||||
window.vueInstance.config.globalProperties.$message.error(err.response.data);
|
window.vueInstance.config.globalProperties.$message.error(err.response.data);
|
||||||
} else {
|
} else {
|
||||||
window.vueInstance.config.globalProperties.$message.error('发生了某些异常问题');
|
window.vueInstance.config.globalProperties.$message.error("发生了某些异常问题");
|
||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ async function request(url, method, params, body, isForm) {
|
|||||||
* @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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +63,7 @@ async function get(url, params = null) {
|
|||||||
* @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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,7 +75,7 @@ async function post(url, params, body, isForm = false) {
|
|||||||
* @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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,12 +85,12 @@ async function put(url, params, body, isForm = false) {
|
|||||||
* @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,40 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>配置qb</div>
|
<el-form :model="data.qbConfig" label-width="10em">
|
||||||
<el-form :model="data.qbConfig" label-width="8em">
|
<el-form-item :label="t('qbConfig.version')">
|
||||||
<el-form-item label="qb版本">
|
{{ data.qbConfig.version ? data.qbConfig.version : $t("qbConfig.error") }}
|
||||||
{{ data.qbConfig.version ? data.qbConfig.version : "配置错误,无法访问" }}
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="访问地址">
|
<el-form-item :label="t('qbConfig.address')">
|
||||||
<el-input type="text" v-model="data.qbConfig.address" placeholder="例如:http://localhost:8080(仅支持v4.1及以上)"/>
|
<el-input :disabled="data.disabled" type="text" v-model="data.qbConfig.address"
|
||||||
|
:placeholder="t('qbConfig.addressAlt')" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="用户名">
|
<el-form-item :label="t('qbConfig.username')">
|
||||||
<el-input type="text" v-model="data.qbConfig.username" placeholder="qb访问用户名"/>
|
<el-input :disabled="data.disabled" type="text" v-model="data.qbConfig.username"
|
||||||
|
:placeholder="t('qbConfig.usernameAlt')" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="密码">
|
<el-form-item :label="t('qbConfig.password')">
|
||||||
<el-input type="password" v-model="data.qbConfig.password" placeholder="qb访问密码"/>
|
<el-input :disabled="data.disabled" type="password" v-model="data.qbConfig.password"
|
||||||
|
:placeholder="t('qbConfig.passwordAlt')" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="qb下载路径">
|
<el-form-item :label="t('qbConfig.downloadPath')">
|
||||||
<el-input type="text" v-model="data.qbConfig.qbDownloadPath" placeholder="qb下载路径(qb中选择的下载路径)"/>
|
<el-input :disabled="data.disabled" type="text" v-model="data.qbConfig.qbDownloadPath"
|
||||||
|
:placeholder="t('qbConfig.downloadPathAlt')" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="对应本系统路径">
|
<el-form-item :label="t('qbConfig.localPath')">
|
||||||
<el-input type="text" v-model="data.qbConfig.renameQbDownloadPath" placeholder="qb下载路径对应到本软件中的路径"/>
|
<el-input :disabled="data.disabled" type="text" v-model="data.qbConfig.renameQbDownloadPath"
|
||||||
|
:placeholder="t('qbConfig.localPathAlt')" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div style="text-align: center">
|
<div style="text-align: center">
|
||||||
<el-button type="" @click="editInfo = false">取消</el-button>
|
<template v-if="!data.disabled">
|
||||||
<el-button type="primary" @click="submitQb">提交</el-button>
|
<el-button type="warning" @click="data.disabled= true">{{ $t("action.cancel") }}</el-button>
|
||||||
|
<el-button type="primary" @click="submitQb">{{ $t("action.submit") }}</el-button>
|
||||||
|
</template>
|
||||||
|
<el-button type="primary" @click="data.disabled= false" v-else>{{ $t("action.edit") }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {ref, reactive, onMounted, computed} from "vue";
|
import { ref, reactive, onMounted, computed } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
import http from "@/utils/HttpUtil";
|
import http from "@/utils/HttpUtil";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
//表单
|
//表单
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
qbConfig: {},
|
qbConfig: {},
|
||||||
|
disabled: true
|
||||||
|
|
||||||
});
|
});
|
||||||
//qb是否可访问
|
|
||||||
let editInfo = ref(false);
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
data.qbConfig = await http.get("/qb/config");
|
data.qbConfig = await http.get("/qb/config");
|
||||||
@ -42,6 +54,8 @@ onMounted(async () => {
|
|||||||
|
|
||||||
async function submitQb() {
|
async function submitQb() {
|
||||||
data.qbConfig = await http.post("/qb/saveQbInfo", null, data.qbConfig);
|
data.qbConfig = await http.post("/qb/saveQbInfo", null, data.qbConfig);
|
||||||
|
ElMessage({ message: t("action.success"), type: "success" });
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user