temp
This commit is contained in:
parent
4b8a7829d9
commit
ef92c13a4f
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,8 +9,8 @@ import handleError from "./middleware/handleError";
|
||||
import init from "./middleware/init";
|
||||
import SqliteUtil from './util/SqliteHelper';
|
||||
import log from './util/LogUtil';
|
||||
import QbService from './service/QbService';
|
||||
import qbService from "./service/QbService";
|
||||
import * as i18n from './i18n';
|
||||
|
||||
console.log(config);
|
||||
|
||||
@ -33,6 +33,7 @@ app.use(RouterMW(router, path.join(config.rootPath, "dist/api")));
|
||||
(async () => {
|
||||
await SqliteUtil.createPool();
|
||||
await qbService.init();
|
||||
await i18n.init();
|
||||
app.listen(config.port);
|
||||
log.info(`server listened `, config.port);
|
||||
})();
|
||||
|
@ -1,35 +1,37 @@
|
||||
import log from '../util/LogUtil';
|
||||
import config from "../config";
|
||||
import {getMessage} from "../i18n";
|
||||
|
||||
let f = async (ctx, next) => {
|
||||
try {
|
||||
//检查是否有密码
|
||||
if (checkToken(ctx)) {
|
||||
await next();
|
||||
} else {
|
||||
ctx.status = 401;
|
||||
ctx.body = "密钥验证错误";
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.status != undefined) {
|
||||
ctx.status = error.status;
|
||||
} else {
|
||||
ctx.status = 500;
|
||||
}
|
||||
ctx.body = error.message;
|
||||
log.error(error);
|
||||
}
|
||||
let lang = ctx.request.headers['lang'];
|
||||
try {
|
||||
//检查是否有密码
|
||||
if (checkToken(ctx)) {
|
||||
await next();
|
||||
} else {
|
||||
ctx.status = 401;
|
||||
ctx.body = getMessage(lang, "key-error");
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.status != undefined) {
|
||||
ctx.status = error.status;
|
||||
} else {
|
||||
ctx.status = 500;
|
||||
}
|
||||
ctx.body = getMessage(lang, error.message);
|
||||
log.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function checkToken(ctx) {
|
||||
if (!config.token) {
|
||||
return true;
|
||||
}
|
||||
let requestPath = ctx.method + ctx.path.replace(config.urlPrefix, "");
|
||||
if (config.publicPath.has(requestPath)) {
|
||||
return true;
|
||||
}
|
||||
return config.token == ctx.headers.token;
|
||||
if (!config.token) {
|
||||
return true;
|
||||
}
|
||||
let requestPath = ctx.method + ctx.path.replace(config.urlPrefix, "");
|
||||
if (config.publicPath.has(requestPath)) {
|
||||
return true;
|
||||
}
|
||||
return config.token == ctx.headers.token;
|
||||
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ export default async (ctx, next) => {
|
||||
ctx.set("X-Powered-By", ' 3.2.1');
|
||||
ctx.set("Content-Type", "application/json;charset=utf-8");
|
||||
//合并请求参数到allParams
|
||||
let objs = new Array();
|
||||
let objs = [];
|
||||
if (ctx.method == "POST" || ctx.method == "PUT") {
|
||||
if (ctx.request.body) {
|
||||
if (ctx.request.body.fields != undefined && ctx.request.body.files != undefined) {
|
||||
|
@ -1,31 +1,32 @@
|
||||
{
|
||||
"name": "nas_backup",
|
||||
"version": "1.0.0",
|
||||
"description": "文件备份用",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "fxb",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/fs-extra": "^5.0.4",
|
||||
"@types/koa": "^2.0.47",
|
||||
"@types/node": "^11.13.4",
|
||||
"axios": "^0.21.4",
|
||||
"fs-extra": "^7.0.0",
|
||||
"koa": "^2.5.3",
|
||||
"koa-body": "^4.0.4",
|
||||
"koa-router": "^7.4.0",
|
||||
"koa-static": "^5.0.0",
|
||||
"koa2-cors": "^2.0.6",
|
||||
"log4js": "^6.3.0",
|
||||
"moment": "^2.22.2",
|
||||
"mysql2": "^2.2.5",
|
||||
"querystring": "^0.2.1",
|
||||
"sqlite": "^4.0.23",
|
||||
"sqlite3": "^5.0.2",
|
||||
"uuid": "^3.3.2",
|
||||
"winston": "^3.1.0"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "nas_backup",
|
||||
"version": "1.0.0",
|
||||
"description": "文件备份用",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "fxb",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/fs-extra": "^5.0.4",
|
||||
"@types/koa": "^2.0.47",
|
||||
"@types/node": "^11.13.4",
|
||||
"axios": "^0.21.4",
|
||||
"fs-extra": "^7.0.0",
|
||||
"koa": "^2.5.3",
|
||||
"koa-body": "^4.0.4",
|
||||
"koa-router": "^7.4.0",
|
||||
"koa-static": "^5.0.0",
|
||||
"koa2-cors": "^2.0.6",
|
||||
"log4js": "^6.3.0",
|
||||
"moment": "^2.22.2",
|
||||
"mysql2": "^2.2.5",
|
||||
"querystring": "^0.2.1",
|
||||
"sqlite": "^4.0.23",
|
||||
"sqlite3": "^5.0.2",
|
||||
"uuid": "^3.3.2",
|
||||
"winston": "^3.1.0",
|
||||
"yaml": "^2.3.3"
|
||||
}
|
||||
}
|
||||
|
17
openRenamerBackend/pnpm-lock.yaml
generated
17
openRenamerBackend/pnpm-lock.yaml
generated
@ -44,6 +44,9 @@ dependencies:
|
||||
mysql2:
|
||||
specifier: ^2.2.5
|
||||
version: 2.3.3
|
||||
querystring:
|
||||
specifier: ^0.2.1
|
||||
version: 0.2.1
|
||||
sqlite:
|
||||
specifier: ^4.0.23
|
||||
version: 4.1.2
|
||||
@ -56,6 +59,9 @@ dependencies:
|
||||
winston:
|
||||
specifier: ^3.1.0
|
||||
version: 3.8.2
|
||||
yaml:
|
||||
specifier: ^2.3.3
|
||||
version: 2.3.3
|
||||
|
||||
packages:
|
||||
|
||||
@ -1404,6 +1410,12 @@ packages:
|
||||
side-channel: 1.0.4
|
||||
dev: false
|
||||
|
||||
/querystring@0.2.1:
|
||||
resolution: {integrity: sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==}
|
||||
engines: {node: '>=0.4.x'}
|
||||
deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
|
||||
dev: false
|
||||
|
||||
/raw-body@2.5.2:
|
||||
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@ -1771,6 +1783,11 @@ packages:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
dev: false
|
||||
|
||||
/yaml@2.3.3:
|
||||
resolution: {integrity: sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==}
|
||||
engines: {node: '>= 14'}
|
||||
dev: false
|
||||
|
||||
/ylru@1.3.2:
|
||||
resolution: {integrity: sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==}
|
||||
engines: {node: '>= 4.0.0'}
|
||||
|
@ -3,6 +3,8 @@ import {tryLogin, get, post, updateQbInfo, getQbInfo} from '../util/QbApiUtil';
|
||||
import GlobalConfigService from "./GlobalConfigService";
|
||||
import GlobalConfig from "../entity/po/GlobalConfig";
|
||||
import BtListItemDto from "../entity/dto/BtListItemDto";
|
||||
import QbCommonDto from "../entity/dto/QbCommonDto";
|
||||
import {boolTag} from "yaml/dist/schema/core/bool";
|
||||
|
||||
class QbService {
|
||||
|
||||
@ -14,13 +16,18 @@ class QbService {
|
||||
if (body.address.endsWith("/")) {
|
||||
body.address = body.address.substring(0, body.address.length - 1);
|
||||
}
|
||||
await GlobalConfigService.insertOrReplace(new GlobalConfig("qbConfig", JSON.stringify(body), "qb config"));
|
||||
updateQbInfo(body);
|
||||
body.valid = await tryLogin();
|
||||
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;
|
||||
}
|
||||
a
|
||||
|
||||
/**
|
||||
* 获取当前配置
|
||||
*/
|
||||
@ -36,6 +43,16 @@ a
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
|
@ -16,24 +16,40 @@ export function getQbInfo() {
|
||||
}
|
||||
|
||||
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) {
|
||||
throw new Error("qbittorrent无法连接,请检查配置");
|
||||
}
|
||||
let isTryLogin = false;
|
||||
while (true) {
|
||||
let headers = {"Cookie": cookie};
|
||||
if (isForm) {
|
||||
headers['content-type'] = "multipart/form-data";
|
||||
} else if (method == "post") {
|
||||
headers['content-type'] = "application/json";
|
||||
if (method == 'post') {
|
||||
if (formType == 1) {
|
||||
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({
|
||||
baseURL: qbInfo.address,
|
||||
|
@ -1,28 +1,29 @@
|
||||
{
|
||||
"name": "open-renamer",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"dayjs": "^1.10.7",
|
||||
"element-plus": "^2.2.25",
|
||||
"vue": "^3.2.45",
|
||||
"vue-router": "^4.0.0-0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~5.0.8",
|
||||
"@vue/cli-plugin-router": "~5.0.8",
|
||||
"@vue/cli-service": "~5.0.8",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"less": "^3.0.4",
|
||||
"less-loader": "^5.0.0",
|
||||
"prettier": "^2.2.1"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "open-renamer",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"dayjs": "^1.10.7",
|
||||
"element-plus": "^2.2.25",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.5.0",
|
||||
"vue-router": "^4.0.0-0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~5.0.8",
|
||||
"@vue/cli-plugin-router": "~5.0.8",
|
||||
"@vue/cli-service": "~5.0.8",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"less": "^3.0.4",
|
||||
"less-loader": "^5.0.0",
|
||||
"prettier": "^2.2.1"
|
||||
}
|
||||
}
|
||||
|
36
openRenamerFront/pnpm-lock.yaml
generated
36
openRenamerFront/pnpm-lock.yaml
generated
@ -23,6 +23,9 @@ dependencies:
|
||||
vue:
|
||||
specifier: ^3.2.45
|
||||
version: 3.2.47
|
||||
vue-i18n:
|
||||
specifier: ^9.5.0
|
||||
version: 9.5.0(vue@3.2.47)
|
||||
vue-router:
|
||||
specifier: ^4.0.0-0
|
||||
version: 4.1.6(vue@3.2.47)
|
||||
@ -1302,6 +1305,27 @@ packages:
|
||||
'@hapi/hoek': 9.3.0
|
||||
dev: true
|
||||
|
||||
/@intlify/core-base@9.5.0:
|
||||
resolution: {integrity: sha512-y3ufM1RJbI/DSmJf3lYs9ACq3S/iRvaSsE3rPIk0MGH7fp+JxU6rdryv/EYcwfcr3Y1aHFlCBir6S391hRZ57w==}
|
||||
engines: {node: '>= 16'}
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 9.5.0
|
||||
'@intlify/shared': 9.5.0
|
||||
dev: false
|
||||
|
||||
/@intlify/message-compiler@9.5.0:
|
||||
resolution: {integrity: sha512-CAhVNfEZcOVFg0/5MNyt+OFjvs4J/ARjCj2b+54/FvFP0EDJI5lIqMTSDBE7k0atMROSP0SvWCkwu/AZ5xkK1g==}
|
||||
engines: {node: '>= 16'}
|
||||
dependencies:
|
||||
'@intlify/shared': 9.5.0
|
||||
source-map-js: 1.0.2
|
||||
dev: false
|
||||
|
||||
/@intlify/shared@9.5.0:
|
||||
resolution: {integrity: sha512-tAxV14LMXZDZbu32XzLMTsowNlgJNmLwWHYzvMUl6L8gvQeoYiZONjY7AUsqZW8TOZDX9lfvF6adPkk9FSRdDA==}
|
||||
engines: {node: '>= 16'}
|
||||
dev: false
|
||||
|
||||
/@jridgewell/gen-mapping@0.1.1:
|
||||
resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
@ -7869,6 +7893,18 @@ packages:
|
||||
resolution: {integrity: sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==}
|
||||
dev: true
|
||||
|
||||
/vue-i18n@9.5.0(vue@3.2.47):
|
||||
resolution: {integrity: sha512-NiI3Ph1qMstNf7uhYh8trQBOBFLxeJgcOxBq51pCcZ28Vs18Y7BDS58r8HGDKCYgXdLUYqPDXdKatIF4bvBVZg==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
dependencies:
|
||||
'@intlify/core-base': 9.5.0
|
||||
'@intlify/shared': 9.5.0
|
||||
'@vue/devtools-api': 6.5.0
|
||||
vue: 3.2.47
|
||||
dev: false
|
||||
|
||||
/vue-loader@15.10.1(@vue/compiler-sfc@3.2.47)(css-loader@6.7.3)(lodash@4.17.21)(webpack@5.75.0):
|
||||
resolution: {integrity: sha512-SaPHK1A01VrNthlix6h1hq4uJu7S/z0kdLUb6klubo738NeQoLbS6V9/d8Pv19tU0XdQKju3D1HSKuI8wJ5wMA==}
|
||||
peerDependencies:
|
||||
|
@ -1,69 +1,87 @@
|
||||
<template>
|
||||
<div class="app">
|
||||
<el-menu :default-active="activeIndex" mode="horizontal" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" router>
|
||||
<el-menu-item index="/">重命名</el-menu-item>
|
||||
<!-- <el-menu-item index="/auto">自动化</el-menu-item>-->
|
||||
<el-sub-menu index="/download">
|
||||
<template #title>bt下载</template>
|
||||
<el-menu-item index="/download/center">下载中心</el-menu-item>
|
||||
<el-menu-item index="/download/config">配置</el-menu-item>
|
||||
</el-sub-menu>
|
||||
</el-menu>
|
||||
<div class="header">
|
||||
<el-menu :default-active="data.activeIndex" mode="horizontal" background-color="#545c64" text-color="#fff"
|
||||
active-text-color="#ffd04b" router>
|
||||
<el-menu-item index="/">{{ $t("menu.rename") }}</el-menu-item>
|
||||
<!-- <el-menu-item index="/auto">自动化</el-menu-item>-->
|
||||
<el-sub-menu index="/download">
|
||||
<template #title>{{ $t("menu.download") }}</template>
|
||||
<el-menu-item index="/download/center">{{ $t("menu.downloadHome") }}</el-menu-item>
|
||||
<el-menu-item index="/download/config">{{ $t("menu.downloadConfig") }}</el-menu-item>
|
||||
</el-sub-menu>
|
||||
</el-menu>
|
||||
<el-dropdown style="position: absolute;right:1em;top:1em;color: white;cursor: pointer" @command="langChange">
|
||||
{{ $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 class="content">
|
||||
<router-view />
|
||||
</div>
|
||||
<div class="footer">
|
||||
版本:
|
||||
<div class="footer">{{ $t("version") }}:
|
||||
<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" target="_blank">
|
||||
{{ version }}</a
|
||||
>
|
||||
<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">
|
||||
{{ data.version }}</a>
|
||||
</el-tooltip>
|
||||
|
||||
<template v-if="latestVersion && showNewVersion">
|
||||
最新版本:
|
||||
<template v-if="data.latestVersion && data.showNewVersion">
|
||||
{{ $t("newestVersion") }}:
|
||||
<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" target="_blank">
|
||||
{{ latestVersion }}</a
|
||||
>
|
||||
<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">
|
||||
{{ data.latestVersion }}</a>
|
||||
</el-tooltip>
|
||||
|
||||
</template>
|
||||
开源地址:<a href="https://github.com/FleyX/open-renamer">open-renamer</a> <a href="https://github.com/FleyX/open-renamer/issues"
|
||||
>反馈</a
|
||||
>
|
||||
{{ $t("openSourceLocation") }}:<a href="https://github.com/FleyX/open-renamer">github open-renamer</a>
|
||||
<a href="https://github.com/FleyX/open-renamer/issues">{{ $t("feedback") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { onBeforeMount, reactive } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { locale, t } = useI18n();
|
||||
import httpUtil from "./utils/HttpUtil";
|
||||
|
||||
export default {
|
||||
name: "Home",
|
||||
data() {
|
||||
return {
|
||||
version: "1.6.2",
|
||||
latestVersion: null,
|
||||
activeIndex: location.pathname,
|
||||
showNewVersion: false,
|
||||
};
|
||||
},
|
||||
async beforeCreate() {
|
||||
window.token = localStorage.getItem("token");
|
||||
const data = reactive({
|
||||
version: "1.6.2",
|
||||
latestVersion: null,
|
||||
activeIndex: location.pathname,
|
||||
showNewVersion: false,
|
||||
curLangLabel: "",
|
||||
langList: [{ code: "en", label: "English" },
|
||||
{ code: "zh", label: "中文" }]
|
||||
});
|
||||
|
||||
onBeforeMount(async () => {
|
||||
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");
|
||||
this.latestVersion = config.version;
|
||||
this.showNewVersion = checkVersion(this.version, this.latestVersion);
|
||||
},
|
||||
async mounted() {
|
||||
console.log(this.$route);
|
||||
console.log(location);
|
||||
},
|
||||
};
|
||||
//获取最新版本
|
||||
let config = await httpUtil.get("https://s3.fleyx.com/picbed/openRenamer/config.json");
|
||||
data.latestVersion = config.version;
|
||||
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) {
|
||||
data.curLangLabel = data.langList.filter(item => command === item.code)[0].label;
|
||||
locale.value = command;
|
||||
localStorage.setItem("lang", command);
|
||||
console.log(command);
|
||||
}
|
||||
|
||||
function checkVersion(version, latestVersion) {
|
||||
if (version === latestVersion) {
|
||||
@ -112,6 +130,10 @@ body {
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
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 router from "./router";
|
||||
import ElementPlus, { ElMessage } from "element-plus";
|
||||
import { createI18n } from "vue-i18n";
|
||||
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);
|
||||
vueInstance.use(router).use(ElementPlus).mount("#app");
|
||||
vueInstance.use(router).use(ElementPlus).use(i18n).mount("#app");
|
||||
vueInstance.config.globalProperties.$message = ElMessage;
|
||||
window.vueInstance = vueInstance;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as http from 'axios';
|
||||
import router from '../router/index';
|
||||
import * as http from "axios";
|
||||
import router from "../router/index";
|
||||
|
||||
/**
|
||||
* 请求
|
||||
@ -12,36 +12,36 @@ import router from '../router/index';
|
||||
* @returns 数据
|
||||
*/
|
||||
async function request(url, method, params, body, isForm) {
|
||||
let options = {
|
||||
url,
|
||||
baseURL: '/openRenamer/api',
|
||||
method,
|
||||
params,
|
||||
headers: {token: window.token}
|
||||
};
|
||||
if (isForm) {
|
||||
options.headers['Content-Type'] = 'multipart/form-data';
|
||||
let options = {
|
||||
url,
|
||||
baseURL: "/openRenamer/api",
|
||||
method,
|
||||
params,
|
||||
headers: { token: window.token, lang: localStorage.getItem("lang") }
|
||||
};
|
||||
if (isForm) {
|
||||
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 if (err.response.status === 400) {
|
||||
window.vueInstance.config.globalProperties.$message.error(err.response.data);
|
||||
} else {
|
||||
window.vueInstance.config.globalProperties.$message.error("发生了某些异常问题");
|
||||
}
|
||||
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 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;
|
||||
throw err;
|
||||
}
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,7 +51,7 @@ async function request(url, method, params, body, isForm) {
|
||||
* @param {*} redirect 未登陆是否跳转到登陆页
|
||||
*/
|
||||
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 是否重定向
|
||||
*/
|
||||
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 是否重定向
|
||||
*/
|
||||
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 是否重定向
|
||||
*/
|
||||
async function deletes(url, params = null) {
|
||||
return request(url, 'delete', params, null);
|
||||
return request(url, "delete", params, null);
|
||||
}
|
||||
|
||||
export default {
|
||||
get,
|
||||
post,
|
||||
put,
|
||||
delete: deletes,
|
||||
get,
|
||||
post,
|
||||
put,
|
||||
delete: deletes
|
||||
};
|
||||
|
@ -1,40 +1,52 @@
|
||||
<template>
|
||||
<div>配置qb</div>
|
||||
<el-form :model="data.qbConfig" label-width="8em">
|
||||
<el-form-item label="qb版本">
|
||||
{{ data.qbConfig.version ? data.qbConfig.version : "配置错误,无法访问" }}
|
||||
<el-form :model="data.qbConfig" label-width="10em">
|
||||
<el-form-item :label="t('qbConfig.version')">
|
||||
{{ data.qbConfig.version ? data.qbConfig.version : $t("qbConfig.error") }}
|
||||
</el-form-item>
|
||||
<el-form-item label="访问地址">
|
||||
<el-input type="text" v-model="data.qbConfig.address" placeholder="例如:http://localhost:8080(仅支持v4.1及以上)"/>
|
||||
<el-form-item :label="t('qbConfig.address')">
|
||||
<el-input :disabled="data.disabled" type="text" v-model="data.qbConfig.address"
|
||||
:placeholder="t('qbConfig.addressAlt')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名">
|
||||
<el-input type="text" v-model="data.qbConfig.username" placeholder="qb访问用户名"/>
|
||||
<el-form-item :label="t('qbConfig.username')">
|
||||
<el-input :disabled="data.disabled" type="text" v-model="data.qbConfig.username"
|
||||
:placeholder="t('qbConfig.usernameAlt')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码">
|
||||
<el-input type="password" v-model="data.qbConfig.password" placeholder="qb访问密码"/>
|
||||
<el-form-item :label="t('qbConfig.password')">
|
||||
<el-input :disabled="data.disabled" type="password" v-model="data.qbConfig.password"
|
||||
:placeholder="t('qbConfig.passwordAlt')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="qb下载路径">
|
||||
<el-input type="text" v-model="data.qbConfig.qbDownloadPath" placeholder="qb下载路径(qb中选择的下载路径)"/>
|
||||
<el-form-item :label="t('qbConfig.downloadPath')">
|
||||
<el-input :disabled="data.disabled" type="text" v-model="data.qbConfig.qbDownloadPath"
|
||||
:placeholder="t('qbConfig.downloadPathAlt')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="对应本系统路径">
|
||||
<el-input type="text" v-model="data.qbConfig.renameQbDownloadPath" placeholder="qb下载路径对应到本软件中的路径"/>
|
||||
<el-form-item :label="t('qbConfig.localPath')">
|
||||
<el-input :disabled="data.disabled" type="text" v-model="data.qbConfig.renameQbDownloadPath"
|
||||
:placeholder="t('qbConfig.localPathAlt')" />
|
||||
</el-form-item>
|
||||
<div style="text-align: center">
|
||||
<el-button type="" @click="editInfo = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitQb">提交</el-button>
|
||||
<template v-if="!data.disabled">
|
||||
<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>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<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 { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
//表单
|
||||
const data = reactive({
|
||||
qbConfig: {},
|
||||
disabled: true
|
||||
|
||||
});
|
||||
//qb是否可访问
|
||||
let editInfo = ref(false);
|
||||
|
||||
onMounted(async () => {
|
||||
data.qbConfig = await http.get("/qb/config");
|
||||
@ -42,6 +54,8 @@ onMounted(async () => {
|
||||
|
||||
async function submitQb() {
|
||||
data.qbConfig = await http.post("/qb/saveQbInfo", null, data.qbConfig);
|
||||
ElMessage({ message: t("action.success"), type: "success" });
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user