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
|
||||
database.db
|
||||
.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$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.vscode" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/ndist" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<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, '..');
|
||||
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 = {
|
||||
rootPath,
|
||||
dataPath: process.env.DATA_PATH ? process.env.DATA_PATH : path.join(rootPath, 'data'),
|
||||
port: process.env.PORT ? parseInt(process.env.PORT) : 8089,
|
||||
token: process.env.TOKEN ? process.env.TOKEN : null,
|
||||
dataPath: map['dataPath'] ? map['dataPath'] : process.env.DATA_PATH ? process.env.DATA_PATH : path.join(rootPath, 'data'),
|
||||
port: map['port'] ? parseInt(map['port']) : process.env.PORT ? parseInt(process.env.PORT) : 8089,
|
||||
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',
|
||||
//是否为windows平台
|
||||
isWindows: process.platform.toLocaleLowerCase().includes("win"),
|
||||
isWindows: process.platform.toLocaleLowerCase().includes("win32"),
|
||||
isMac: process.platform.toLocaleLowerCase().includes("darwin"),
|
||||
bodyLimit: {
|
||||
formLimit: '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 SqliteUtil from './util/SqliteHelper';
|
||||
import log from './util/LogUtil';
|
||||
import QbService from './service/QbService';
|
||||
import qbService from "./service/QbService";
|
||||
import * as i18n from './i18n';
|
||||
|
||||
let start = Date.now();
|
||||
console.log(config);
|
||||
|
||||
const app = new koa();
|
||||
@ -32,9 +33,10 @@ app.use(handleError);
|
||||
app.use(RouterMW(router, path.join(config.rootPath, "dist/api")));
|
||||
(async () => {
|
||||
await SqliteUtil.createPool();
|
||||
await qbService.init();
|
||||
qbService.init();
|
||||
i18n.init();
|
||||
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) => {
|
||||
|
@ -1,14 +1,16 @@
|
||||
import log from '../util/LogUtil';
|
||||
import config from "../config";
|
||||
import {getMessage} from "../i18n";
|
||||
|
||||
let f = async (ctx, next) => {
|
||||
let lang = ctx.request.headers['lang'];
|
||||
try {
|
||||
//检查是否有密码
|
||||
if (checkToken(ctx)) {
|
||||
await next();
|
||||
} else {
|
||||
ctx.status = 401;
|
||||
ctx.body = "密钥验证错误";
|
||||
ctx.body = getMessage(lang, "key-error");
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.status != undefined) {
|
||||
@ -16,7 +18,7 @@ let f = async (ctx, next) => {
|
||||
} else {
|
||||
ctx.status = 500;
|
||||
}
|
||||
ctx.body = error.message;
|
||||
ctx.body = getMessage(lang, error.message);
|
||||
log.error(error);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Binary file not shown.
@ -4,7 +4,16 @@
|
||||
"description": "文件备份用",
|
||||
"main": "index.js",
|
||||
"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",
|
||||
"license": "ISC",
|
||||
@ -12,17 +21,18 @@
|
||||
"@types/fs-extra": "5.0.4",
|
||||
"@types/koa": "2.13.12",
|
||||
"@types/node": "11.13.4",
|
||||
"axios": "0.21.4",
|
||||
"axios": "0.29.0",
|
||||
"fs-extra": "7.0.0",
|
||||
"koa": "2.5.3",
|
||||
"koa": "3.0.0-alpha.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",
|
||||
"sqlite": "4.0.23",
|
||||
"sqlite3": "5.0.2",
|
||||
"uuid": "3.3.2"
|
||||
"log4js": "6.4.0",
|
||||
"moment": "2.29.4",
|
||||
"sqlite": "5.1.1",
|
||||
"sqlite3": "5.1.5",
|
||||
"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 {tryLogin, get, post, updateQbInfo, getQbInfo} from '../util/QbApiUtil';
|
||||
import {get, getQbInfo, post, tryLogin, updateQbInfo} 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 logger from "../util/LogUtil";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
@ -45,7 +62,6 @@ a
|
||||
updateQbInfo(qbInfo);
|
||||
qbInfo.valid = await tryLogin();
|
||||
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) {
|
||||
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") {
|
||||
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,
|
||||
@ -75,8 +91,8 @@ export async function tryLogin(): Promise<boolean> {
|
||||
}
|
||||
qbInfo.valid = success;
|
||||
return success;
|
||||
} catch (error) {
|
||||
console.error("登录报错:", error);
|
||||
} catch (error:any) {
|
||||
console.error("qb登录报错:" );
|
||||
return false;
|
||||
|
||||
}
|
||||
|
@ -8,12 +8,13 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "2.0.10",
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"axios": "1.6.0",
|
||||
"core-js": "3.35.0",
|
||||
"dayjs": "1.10.7",
|
||||
"element-plus": "2.2.25",
|
||||
"vue": "3.2.45",
|
||||
"vue-i18n": "9.5.0",
|
||||
"vue-router": "4.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,73 +1,90 @@
|
||||
<template>
|
||||
<div class="app">
|
||||
<div class="header">
|
||||
<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="/">{{ $t("menu.rename") }}</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-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>
|
||||
{{ 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>
|
||||
{{ data.latestVersion }}</a>
|
||||
</el-tooltip>
|
||||
|
||||
</template>
|
||||
开源地址:<a href="https://github.com/FleyX/open-renamer" target="_blank">open-renamer</a>
|
||||
<a href="https://github.com/FleyX/open-renamer/issues" target="_blank">反馈</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.8.0",
|
||||
const data = reactive({
|
||||
version: "1.7.2",
|
||||
latestVersion: null,
|
||||
activeIndex: location.pathname,
|
||||
showNewVersion: false
|
||||
};
|
||||
},
|
||||
async beforeCreate() {
|
||||
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");
|
||||
},
|
||||
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);
|
||||
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);
|
||||
});
|
||||
|
||||
},
|
||||
async mounted() {
|
||||
console.log(this.$route);
|
||||
console.log(location);
|
||||
},
|
||||
};
|
||||
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) {
|
||||
let versions = version.split(".");
|
||||
let latestVersions = latestVersion.split('.');
|
||||
let latestVersions = latestVersion.split(".");
|
||||
for (let i = 0; i < versions.length; i++) {
|
||||
if (i >= latestVersions.length) {
|
||||
return false;
|
||||
@ -109,6 +126,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";
|
||||
|
||||
/**
|
||||
* 请求
|
||||
@ -14,13 +14,13 @@ import router from '../router/index';
|
||||
async function request(url, method, params, body, isForm) {
|
||||
let options = {
|
||||
url,
|
||||
baseURL: '/openRenamer/api',
|
||||
baseURL: "/openRenamer/api",
|
||||
method,
|
||||
params,
|
||||
headers: {token: window.token}
|
||||
headers: { token: window.token, lang: localStorage.getItem("lang") }
|
||||
};
|
||||
if (isForm) {
|
||||
options.headers['Content-Type'] = 'multipart/form-data';
|
||||
options.headers["Content-Type"] = "multipart/form-data";
|
||||
}
|
||||
if (body) {
|
||||
options.data = body;
|
||||
@ -32,12 +32,12 @@ async function request(url, method, params, body, isForm) {
|
||||
console.log(Object.keys(err));
|
||||
console.log(err.response);
|
||||
if (err.response.status === 401) {
|
||||
window.vueInstance.config.globalProperties.$message.error('密钥验证错误');
|
||||
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('发生了某些异常问题');
|
||||
window.vueInstance.config.globalProperties.$message.error("发生了某些异常问题");
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
@ -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,
|
||||
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 { 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