diff --git a/apps/frontend/package.json b/apps/frontend/package.json
index 87cf581..4acab8e 100644
--- a/apps/frontend/package.json
+++ b/apps/frontend/package.json
@@ -12,20 +12,22 @@
"lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint \"**/*.{css,scss,vue}\" --fix"
},
- "dependencies": {
- "@element-plus/icons-vue": "^1.0.0",
- "@vueuse/core": "^9.1.1",
- "axios": "^1.3.4",
- "copy-to-clipboard": "^3.3.3",
- "element-plus": "^2.3.1",
- "nprogress": "^0.2.0",
- "path-browserify": "^1.0.1",
- "pinia": "^2.0.33",
- "vue": "^3.2.45",
- "vue-i18n": "9",
- "vue-router": "^4.1.6",
- "vuedraggable": "^4.1.0"
- },
+ "dependencies": {
+ "@element-plus/icons-vue": "^1.0.0",
+ "@vueuse/core": "^9.1.1",
+ "axios": "^1.3.4",
+ "copy-to-clipboard": "^3.3.3",
+ "echarts": "^5.5.1",
+ "element-plus": "^2.3.1",
+ "nprogress": "^0.2.0",
+ "path-browserify": "^1.0.1",
+ "pinia": "^2.0.33",
+ "vue": "^3.2.45",
+ "vue-echarts": "^7.0.3",
+ "vue-i18n": "9",
+ "vue-router": "^4.1.6",
+ "vuedraggable": "^4.1.0"
+ },
"devDependencies": {
"@iconify-json/ep": "^1.1.8",
"@types/nprogress": "^0.2.0",
diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml
index 25a7e02..34a8690 100644
--- a/apps/frontend/pnpm-lock.yaml
+++ b/apps/frontend/pnpm-lock.yaml
@@ -20,6 +20,9 @@ importers:
copy-to-clipboard:
specifier: ^3.3.3
version: 3.3.3
+ echarts:
+ specifier: ^5.5.1
+ version: 5.6.0
element-plus:
specifier: ^2.3.1
version: 2.3.1(vue@3.2.45)
@@ -35,6 +38,9 @@ importers:
vue:
specifier: ^3.2.45
version: 3.2.45
+ vue-echarts:
+ specifier: ^7.0.3
+ version: 7.0.3(@vue/runtime-core@3.2.45)(echarts@5.6.0)(vue@3.2.45)
vue-i18n:
specifier: '9'
version: 9.0.0(vue@3.2.45)
@@ -1183,6 +1189,9 @@ packages:
duplexer@0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
+ echarts@5.6.0:
+ resolution: {integrity: sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==}
+
electron-to-chromium@1.4.529:
resolution: {integrity: sha512-6uyPyXTo8lkv8SWAmjKFbG42U073TXlzD4R8rW3EzuznhFS2olCIAfjjQtV2dV2ar/vRF55KUd3zQYnCB0dd3A==}
@@ -2698,6 +2707,9 @@ packages:
tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+ tslib@2.3.0:
+ resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
+
tsutils@3.21.0:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
@@ -2868,6 +2880,17 @@ packages:
terser:
optional: true
+ vue-demi@0.13.11:
+ resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
+ engines: {node: '>=12'}
+ hasBin: true
+ peerDependencies:
+ '@vue/composition-api': ^1.0.0-rc.1
+ vue: ^3.0.0-0 || ^2.6.0
+ peerDependenciesMeta:
+ '@vue/composition-api':
+ optional: true
+
vue-demi@0.14.6:
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
engines: {node: '>=12'}
@@ -2879,6 +2902,16 @@ packages:
'@vue/composition-api':
optional: true
+ vue-echarts@7.0.3:
+ resolution: {integrity: sha512-/jSxNwOsw5+dYAUcwSfkLwKPuzTQ0Cepz1LxCOpj2QcHrrmUa/Ql0eQqMmc1rTPQVrh2JQ29n2dhq75ZcHvRDw==}
+ peerDependencies:
+ '@vue/runtime-core': ^3.0.0
+ echarts: ^5.5.1
+ vue: ^2.7.0 || ^3.1.1
+ peerDependenciesMeta:
+ '@vue/runtime-core':
+ optional: true
+
vue-eslint-parser@9.3.1:
resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==}
engines: {node: ^14.17.0 || >=16.0.0}
@@ -2952,6 +2985,9 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
+ zrender@5.6.1:
+ resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==}
+
snapshots:
'@aashutoshrathi/word-wrap@1.2.6': {}
@@ -4155,6 +4191,11 @@ snapshots:
duplexer@0.1.2: {}
+ echarts@5.6.0:
+ dependencies:
+ tslib: 2.3.0
+ zrender: 5.6.1
+
electron-to-chromium@1.4.529: {}
element-plus@2.3.1(vue@3.2.45):
@@ -5742,6 +5783,8 @@ snapshots:
tslib@1.14.1: {}
+ tslib@2.3.0: {}
+
tsutils@3.21.0(typescript@4.9.3):
dependencies:
tslib: 1.14.1
@@ -5962,10 +6005,24 @@ snapshots:
fsevents: 2.3.3
sass: 1.58.3
+ vue-demi@0.13.11(vue@3.2.45):
+ dependencies:
+ vue: 3.2.45
+
vue-demi@0.14.6(vue@3.2.45):
dependencies:
vue: 3.2.45
+ vue-echarts@7.0.3(@vue/runtime-core@3.2.45)(echarts@5.6.0)(vue@3.2.45):
+ dependencies:
+ echarts: 5.6.0
+ vue: 3.2.45
+ vue-demi: 0.13.11(vue@3.2.45)
+ optionalDependencies:
+ '@vue/runtime-core': 3.2.45
+ transitivePeerDependencies:
+ - '@vue/composition-api'
+
vue-eslint-parser@9.3.1(eslint@8.34.0):
dependencies:
debug: 4.3.4
@@ -6037,3 +6094,7 @@ snapshots:
yargs-parser@20.2.9: {}
yocto-queue@0.1.0: {}
+
+ zrender@5.6.1:
+ dependencies:
+ tslib: 2.3.0
diff --git a/apps/frontend/src/api/peer/index.ts b/apps/frontend/src/api/peer/index.ts
index c69d81a..8aaf67c 100644
--- a/apps/frontend/src/api/peer/index.ts
+++ b/apps/frontend/src/api/peer/index.ts
@@ -50,21 +50,21 @@ export function updatePeerApi(data: PeerUpdateDto): AxiosPromise {
export function resetPeerTrafficApi(data: IdDto): AxiosPromise {
return request({
url: `/peers/${data.id}/reset-traffic`,
- method: "post",
+ method: "patch",
});
}
export function releaseKickPeerApi(data: IdDto): AxiosPromise {
return request({
url: `/peers/${data.id}/release-kick`,
- method: "post",
+ method: "patch",
});
}
export function kickPeerApi(id: number, data: KickPeerDto): AxiosPromise {
return request({
url: `/peers/${id}/kick`,
- method: "post",
+ method: "patch",
data,
});
}
@@ -80,7 +80,7 @@ export function getPeerClientConfigApi(
export function importPeerApi(data: FormData): AxiosPromise {
return request({
- url: "/peers/import",
+ url: "/peer-import",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
@@ -91,7 +91,7 @@ export function importPeerApi(data: FormData): AxiosPromise {
export function exportPeerApi(): AxiosPromise {
return request({
- url: "/peers/export",
+ url: "/peer-export",
method: "post",
responseType: "blob",
});
diff --git a/apps/frontend/src/lang/package/en.ts b/apps/frontend/src/lang/package/en.ts
index d832df1..3ffa0fb 100644
--- a/apps/frontend/src/lang/package/en.ts
+++ b/apps/frontend/src/lang/package/en.ts
@@ -20,6 +20,9 @@ export default {
username: "Username",
password: "Password",
login: "Login",
+ capsLockOn: "Caps lock is On",
+ usernameFormatIncorrect: "Username format is incorrect",
+ passwordFormatIncorrect: "Password format is incorrect",
},
dashboard: {
stale: "Dashboard data is stale. Retrying automatically...",
@@ -34,9 +37,19 @@ export default {
todayDownload: "Today download",
todayUpload: "Today upload",
trafficChart: "Traffic & System Timeseries",
+ trafficSeriesChart: "Traffic: download/upload",
+ systemSeriesChart: "System: CPU/RAM",
download: "Download",
upload: "Upload",
total: "Total",
+ security: {
+ hysteriaStopped: "Hysteria2 is stopped",
+ trafficApiUnavailable: "Traffic API is unavailable",
+ },
+ error: {
+ trafficApiUnavailable: "Traffic API is unavailable",
+ collectorStale: "Collector data is stale",
+ },
},
admin: {
changePasswordTitle: "Change password",
@@ -93,8 +106,8 @@ export default {
yearLater: "A year later",
hourLater: "A hour later",
dayLater: "A day later",
- deleteConfirm: "Are you sure to delete the user \u300c{username}\u300d?",
- resetTrafficConfirm: "Are you sure to reset traffic?",
+ deleteConfirm: "Are you sure to delete peer \u300c{username}\u300d?",
+ resetTrafficConfirm: "Are you sure to reset peer traffic?",
invalid: "Invalid value",
switchLanguageSuccess: "Language switched successfully",
sizeChanged: "Interface size changed",
@@ -116,7 +129,6 @@ export default {
peer: {
name: "Peer",
remark: "Remark",
- username: "Username",
secret: "Secret",
maxDevices: "Max devices",
disabled: "Disabled",
@@ -130,8 +142,6 @@ export default {
clientQr: "Client QR",
unlimited: "Unlimited",
secretRotateConfirm: "Rotate peer secret? Existing client configurations will stop working until updated.",
- pass: "Pass",
- conPass: "ConPass",
quota: "Quota",
download: "Download",
upload: "Upload",
@@ -143,7 +153,6 @@ export default {
online: "Online",
offline: "Offline",
device: "Online Devices",
- role: "Role",
unit: "Unit",
loginAt: "Last login time",
conAt: "Last connection time",
@@ -153,6 +162,11 @@ export default {
kickTip: "Force user to log off",
releaseKick: "Release",
releaseKickTip: "Remove offline status",
+ createdAt: "Created at",
+ bannedUntil: "Banned until",
+ totalTraffic: "Total traffic",
+ copyUri: "Copy URI",
+ more: "More",
},
config: {
huiWebPort: "HY2XS admin Web Port",
diff --git a/apps/frontend/src/lang/package/ru.ts b/apps/frontend/src/lang/package/ru.ts
index 1b9ce36..00b8be7 100644
--- a/apps/frontend/src/lang/package/ru.ts
+++ b/apps/frontend/src/lang/package/ru.ts
@@ -18,6 +18,9 @@ export default {
username: "Логин",
password: "Пароль",
login: "Войти",
+ capsLockOn: "Caps Lock включён",
+ usernameFormatIncorrect: "Неверный формат логина",
+ passwordFormatIncorrect: "Неверный формат пароля",
},
dashboard: {
stale: "Данные дашборда устарели. Выполняется автоматическая повторная попытка...",
@@ -32,9 +35,19 @@ export default {
todayDownload: "Скачано за сегодня",
todayUpload: "Отдано за сегодня",
trafficChart: "Трафик и системные метрики",
+ trafficSeriesChart: "Трафик: download/upload",
+ systemSeriesChart: "Система: CPU/RAM",
download: "Скачано",
upload: "Отдано",
total: "Всего",
+ security: {
+ hysteriaStopped: "Hysteria2 остановлена",
+ trafficApiUnavailable: "Traffic API недоступен",
+ },
+ error: {
+ trafficApiUnavailable: "Traffic API недоступен",
+ collectorStale: "Данные коллектора устарели",
+ },
},
admin: {
changePasswordTitle: "Смена пароля",
@@ -89,8 +102,8 @@ export default {
yearLater: "Через год",
hourLater: "Через час",
dayLater: "Через день",
- deleteConfirm: "Вы уверены, что хотите удалить пользователя «{username}»?",
- resetTrafficConfirm: "Сбросить трафик для пользователя?",
+ deleteConfirm: "Удалить пир «{username}»?",
+ resetTrafficConfirm: "Сбросить трафик для пира?",
invalid: "Некорректное значение",
switchLanguageSuccess: "Язык переключён",
sizeChanged: "Размер интерфейса изменён",
@@ -111,7 +124,6 @@ export default {
peer: {
name: "Пир",
remark: "Комментарий",
- username: "Логин",
secret: "Секрет",
maxDevices: "Лимит устройств",
disabled: "Отключён",
@@ -125,8 +137,6 @@ export default {
clientQr: "QR клиента",
unlimited: "Безлимит",
secretRotateConfirm: "Сменить секрет пира? Текущие клиентские конфиги перестанут работать до обновления.",
- pass: "Пароль входа",
- conPass: "Пароль подключения",
quota: "Квота",
download: "Скачано",
upload: "Отдано",
@@ -138,7 +148,11 @@ export default {
online: "Онлайн",
offline: "Офлайн",
device: "Устройства",
- role: "Роль",
+ createdAt: "Создан",
+ bannedUntil: "Блокировка до",
+ totalTraffic: "Суммарный трафик",
+ copyUri: "Копировать URI",
+ more: "Ещё",
unit: "Ед. изм.",
loginAt: "Последний вход",
conAt: "Последнее подключение",
diff --git a/apps/frontend/src/views/dashboard/index.vue b/apps/frontend/src/views/dashboard/index.vue
index 4994096..965f602 100644
--- a/apps/frontend/src/views/dashboard/index.vue
+++ b/apps/frontend/src/views/dashboard/index.vue
@@ -51,13 +51,10 @@
-