mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-19 02:12:46 +08:00
feat: migrate dashboard api runtime
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@guolao/vue-monaco-editor": "^1.6.0",
|
||||
"@hey-api/client-axios": "^0.9.1",
|
||||
"@tiptap/starter-kit": "3.20.5",
|
||||
"@tiptap/vue-3": "3.20.5",
|
||||
"apexcharts": "5.10.4",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,10 @@
|
||||
/* Auto-generated MDI subset – 279 icons */
|
||||
/* Auto-generated MDI subset – 281 icons */
|
||||
/* Do not edit manually. Run: pnpm run subset-icons */
|
||||
|
||||
@font-face {
|
||||
font-family: "Material Design Icons";
|
||||
src:
|
||||
url("./materialdesignicons-webfont-subset.woff2") format("woff2"),
|
||||
url("./materialdesignicons-webfont-subset.woff") format("woff");
|
||||
src: url("./materialdesignicons-webfont-subset.woff2") format("woff2"),
|
||||
url("./materialdesignicons-webfont-subset.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -13,7 +12,7 @@
|
||||
.mdi:before,
|
||||
.mdi-set {
|
||||
display: inline-block;
|
||||
font: normal normal normal 24px / 1 "Material Design Icons";
|
||||
font: normal normal normal 24px/1 "Material Design Icons";
|
||||
font-size: inherit;
|
||||
text-rendering: auto;
|
||||
line-height: inherit;
|
||||
@@ -61,10 +60,6 @@
|
||||
content: "\F002A";
|
||||
}
|
||||
|
||||
.mdi-api::before {
|
||||
content: "\F109B";
|
||||
}
|
||||
|
||||
.mdi-api-off::before {
|
||||
content: "\F1257";
|
||||
}
|
||||
@@ -121,10 +116,6 @@
|
||||
content: "\F09D1";
|
||||
}
|
||||
|
||||
.mdi-brightness-6::before {
|
||||
content: "\F00DF";
|
||||
}
|
||||
|
||||
.mdi-broadcast::before {
|
||||
content: "\F1720";
|
||||
}
|
||||
@@ -157,6 +148,10 @@
|
||||
content: "\F00F3";
|
||||
}
|
||||
|
||||
.mdi-calendar-range::before {
|
||||
content: "\F0679";
|
||||
}
|
||||
|
||||
.mdi-chat::before {
|
||||
content: "\F0B79";
|
||||
}
|
||||
@@ -193,6 +188,10 @@
|
||||
content: "\F0132";
|
||||
}
|
||||
|
||||
.mdi-checkbox-multiple-marked-outline::before {
|
||||
content: "\F0139";
|
||||
}
|
||||
|
||||
.mdi-chevron-double-left::before {
|
||||
content: "\F013D";
|
||||
}
|
||||
@@ -257,10 +256,6 @@
|
||||
content: "\F0167";
|
||||
}
|
||||
|
||||
.mdi-code-braces::before {
|
||||
content: "\F0169";
|
||||
}
|
||||
|
||||
.mdi-code-json::before {
|
||||
content: "\F0626";
|
||||
}
|
||||
@@ -341,6 +336,10 @@
|
||||
content: "\F164B";
|
||||
}
|
||||
|
||||
.mdi-database-import::before {
|
||||
content: "\F095D";
|
||||
}
|
||||
|
||||
.mdi-database-off::before {
|
||||
content: "\F1640";
|
||||
}
|
||||
@@ -349,10 +348,6 @@
|
||||
content: "\F1634";
|
||||
}
|
||||
|
||||
.mdi-database-search-outline::before {
|
||||
content: "\F1636";
|
||||
}
|
||||
|
||||
.mdi-delete::before {
|
||||
content: "\F01B4";
|
||||
}
|
||||
@@ -385,6 +380,10 @@
|
||||
content: "\F0B8F";
|
||||
}
|
||||
|
||||
.mdi-earth::before {
|
||||
content: "\F01E7";
|
||||
}
|
||||
|
||||
.mdi-emoticon::before {
|
||||
content: "\F0C68";
|
||||
}
|
||||
@@ -453,10 +452,6 @@
|
||||
content: "\F021C";
|
||||
}
|
||||
|
||||
.mdi-file-music-outline::before {
|
||||
content: "\F0E2A";
|
||||
}
|
||||
|
||||
.mdi-file-outline::before {
|
||||
content: "\F0224";
|
||||
}
|
||||
@@ -481,10 +476,6 @@
|
||||
content: "\F0A4D";
|
||||
}
|
||||
|
||||
.mdi-file-video-outline::before {
|
||||
content: "\F0E2C";
|
||||
}
|
||||
|
||||
.mdi-file-word-box::before {
|
||||
content: "\F022D";
|
||||
}
|
||||
@@ -493,6 +484,10 @@
|
||||
content: "\F0234";
|
||||
}
|
||||
|
||||
.mdi-filter-variant::before {
|
||||
content: "\F0236";
|
||||
}
|
||||
|
||||
.mdi-folder::before {
|
||||
content: "\F024B";
|
||||
}
|
||||
@@ -585,10 +580,6 @@
|
||||
content: "\F0EFE";
|
||||
}
|
||||
|
||||
.mdi-image-outline::before {
|
||||
content: "\F0976";
|
||||
}
|
||||
|
||||
.mdi-import::before {
|
||||
content: "\F02FA";
|
||||
}
|
||||
@@ -617,6 +608,10 @@
|
||||
content: "\F030B";
|
||||
}
|
||||
|
||||
.mdi-keyboard-outline::before {
|
||||
content: "\F097B";
|
||||
}
|
||||
|
||||
.mdi-label::before {
|
||||
content: "\F0315";
|
||||
}
|
||||
@@ -633,10 +628,6 @@
|
||||
content: "\F031D";
|
||||
}
|
||||
|
||||
.mdi-language-java::before {
|
||||
content: "\F0B37";
|
||||
}
|
||||
|
||||
.mdi-language-javascript::before {
|
||||
content: "\F031E";
|
||||
}
|
||||
@@ -725,6 +716,10 @@
|
||||
content: "\F035F";
|
||||
}
|
||||
|
||||
.mdi-message-off-outline::before {
|
||||
content: "\F164E";
|
||||
}
|
||||
|
||||
.mdi-message-outline::before {
|
||||
content: "\F0365";
|
||||
}
|
||||
@@ -733,6 +728,10 @@
|
||||
content: "\F0369";
|
||||
}
|
||||
|
||||
.mdi-message-text-outline::before {
|
||||
content: "\F036A";
|
||||
}
|
||||
|
||||
.mdi-microphone::before {
|
||||
content: "\F036C";
|
||||
}
|
||||
@@ -753,6 +752,10 @@
|
||||
content: "\F0A07";
|
||||
}
|
||||
|
||||
.mdi-moon-waning-crescent::before {
|
||||
content: "\F0F65";
|
||||
}
|
||||
|
||||
.mdi-music-note-outline::before {
|
||||
content: "\F0F74";
|
||||
}
|
||||
@@ -781,6 +784,10 @@
|
||||
content: "\F0B3C";
|
||||
}
|
||||
|
||||
.mdi-numeric-4::before {
|
||||
content: "\F0B3D";
|
||||
}
|
||||
|
||||
.mdi-open-in-new::before {
|
||||
content: "\F03CC";
|
||||
}
|
||||
@@ -789,10 +796,6 @@
|
||||
content: "\F03D6";
|
||||
}
|
||||
|
||||
.mdi-package-variant-closed::before {
|
||||
content: "\F03D7";
|
||||
}
|
||||
|
||||
.mdi-page-first::before {
|
||||
content: "\F0600";
|
||||
}
|
||||
@@ -801,8 +804,8 @@
|
||||
content: "\F0601";
|
||||
}
|
||||
|
||||
.mdi-palette-outline::before {
|
||||
content: "\F0E0C";
|
||||
.mdi-palette::before {
|
||||
content: "\F03D8";
|
||||
}
|
||||
|
||||
.mdi-paperclip::before {
|
||||
@@ -813,6 +816,10 @@
|
||||
content: "\F03E4";
|
||||
}
|
||||
|
||||
.mdi-pause-circle-outline::before {
|
||||
content: "\F03E6";
|
||||
}
|
||||
|
||||
.mdi-pencil::before {
|
||||
content: "\F03EB";
|
||||
}
|
||||
@@ -941,6 +948,10 @@
|
||||
content: "\F0832";
|
||||
}
|
||||
|
||||
.mdi-share-variant::before {
|
||||
content: "\F0497";
|
||||
}
|
||||
|
||||
.mdi-shield-check::before {
|
||||
content: "\F0565";
|
||||
}
|
||||
@@ -953,10 +964,6 @@
|
||||
content: "\F0BC4";
|
||||
}
|
||||
|
||||
.mdi-shield-lock-outline::before {
|
||||
content: "\F0CCC";
|
||||
}
|
||||
|
||||
.mdi-shuffle-variant::before {
|
||||
content: "\F049F";
|
||||
}
|
||||
@@ -1045,10 +1052,6 @@
|
||||
content: "\F13B8";
|
||||
}
|
||||
|
||||
.mdi-theme-light-dark::before {
|
||||
content: "\F050E";
|
||||
}
|
||||
|
||||
.mdi-timeline-text-outline::before {
|
||||
content: "\F0BD4";
|
||||
}
|
||||
@@ -1073,10 +1076,6 @@
|
||||
content: "\F0A7A";
|
||||
}
|
||||
|
||||
.mdi-tune-variant::before {
|
||||
content: "\F1542";
|
||||
}
|
||||
|
||||
.mdi-unfold-more-horizontal::before {
|
||||
content: "\F054F";
|
||||
}
|
||||
@@ -1105,6 +1104,14 @@
|
||||
content: "\F056E";
|
||||
}
|
||||
|
||||
.mdi-view-grid::before {
|
||||
content: "\F0570";
|
||||
}
|
||||
|
||||
.mdi-view-list::before {
|
||||
content: "\F0572";
|
||||
}
|
||||
|
||||
.mdi-volume-high::before {
|
||||
content: "\F057E";
|
||||
}
|
||||
@@ -1145,23 +1152,19 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.mdi-18px.mdi-set,
|
||||
.mdi-18px.mdi:before {
|
||||
.mdi-18px.mdi-set, .mdi-18px.mdi:before {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.mdi-24px.mdi-set,
|
||||
.mdi-24px.mdi:before {
|
||||
.mdi-24px.mdi-set, .mdi-24px.mdi:before {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.mdi-36px.mdi-set,
|
||||
.mdi-36px.mdi:before {
|
||||
.mdi-36px.mdi-set, .mdi-36px.mdi:before {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.mdi-48px.mdi-set,
|
||||
.mdi-48px.mdi:before {
|
||||
.mdi-48px.mdi-set, .mdi-48px.mdi:before {
|
||||
font-size: 48px;
|
||||
}
|
||||
|
||||
@@ -1182,21 +1185,21 @@
|
||||
}
|
||||
|
||||
.mdi-rotate-45 {
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(45deg);
|
||||
transform: scaleX(-1) rotate(45deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: scaleY(-1) rotate(45deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(45deg);
|
||||
transform: scaleX(-1) rotate(45deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: scaleY(-1) rotate(45deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1207,21 +1210,21 @@
|
||||
}
|
||||
|
||||
.mdi-rotate-90 {
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(90deg);
|
||||
transform: scaleX(-1) rotate(90deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
transform: scaleY(-1) rotate(90deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(90deg);
|
||||
transform: scaleX(-1) rotate(90deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
transform: scaleY(-1) rotate(90deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1232,21 +1235,21 @@
|
||||
}
|
||||
|
||||
.mdi-rotate-135 {
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(135deg);
|
||||
transform: scaleX(-1) rotate(135deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(135deg);
|
||||
-ms-transform: rotate(135deg);
|
||||
transform: scaleY(-1) rotate(135deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(135deg);
|
||||
transform: scaleX(-1) rotate(135deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(135deg);
|
||||
-ms-transform: rotate(135deg);
|
||||
transform: scaleY(-1) rotate(135deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1257,21 +1260,21 @@
|
||||
}
|
||||
|
||||
.mdi-rotate-180 {
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(180deg);
|
||||
transform: scaleX(-1) rotate(180deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(180deg);
|
||||
-ms-transform: rotate(180deg);
|
||||
transform: scaleY(-1) rotate(180deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(180deg);
|
||||
transform: scaleX(-1) rotate(180deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(180deg);
|
||||
-ms-transform: rotate(180deg);
|
||||
transform: scaleY(-1) rotate(180deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1282,21 +1285,21 @@
|
||||
}
|
||||
|
||||
.mdi-rotate-225 {
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(225deg);
|
||||
transform: scaleX(-1) rotate(225deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(225deg);
|
||||
-ms-transform: rotate(225deg);
|
||||
transform: scaleY(-1) rotate(225deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(225deg);
|
||||
transform: scaleX(-1) rotate(225deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(225deg);
|
||||
-ms-transform: rotate(225deg);
|
||||
transform: scaleY(-1) rotate(225deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1307,21 +1310,21 @@
|
||||
}
|
||||
|
||||
.mdi-rotate-270 {
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(270deg);
|
||||
transform: scaleX(-1) rotate(270deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(270deg);
|
||||
-ms-transform: rotate(270deg);
|
||||
transform: scaleY(-1) rotate(270deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(270deg);
|
||||
transform: scaleX(-1) rotate(270deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(270deg);
|
||||
-ms-transform: rotate(270deg);
|
||||
transform: scaleY(-1) rotate(270deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1332,21 +1335,21 @@
|
||||
}
|
||||
|
||||
.mdi-rotate-315 {
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(315deg);
|
||||
transform: scaleX(-1) rotate(315deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(315deg);
|
||||
-ms-transform: rotate(315deg);
|
||||
transform: scaleY(-1) rotate(315deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
/*
|
||||
// Not included in production
|
||||
&.mdi-flip-h:before {
|
||||
-webkit-transform: scaleX(-1) rotate(315deg);
|
||||
transform: scaleX(-1) rotate(315deg);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
&.mdi-flip-v:before {
|
||||
-webkit-transform: scaleY(-1) rotate(315deg);
|
||||
-ms-transform: rotate(315deg);
|
||||
transform: scaleY(-1) rotate(315deg);
|
||||
filter: FlipV;
|
||||
-ms-filter: "FlipV";
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -48,7 +48,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import axios, { type AxiosRequestConfig } from 'axios';
|
||||
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
@@ -58,6 +57,7 @@ import {
|
||||
type ApiEnvelope,
|
||||
type VersionData,
|
||||
} from '@/api/v1';
|
||||
import request, { resolveApiUrl } from '@/utils/request';
|
||||
import { useI18n } from '@/i18n/composables';
|
||||
|
||||
type StartTimeData = {
|
||||
@@ -81,7 +81,7 @@ const initialStartTime = ref<number | string | null>(null);
|
||||
|
||||
let restartTimer: ReturnType<typeof setInterval> | null = null;
|
||||
let detecting = false;
|
||||
const recoveryClient = axios.create();
|
||||
const recoveryClient = request;
|
||||
|
||||
function normalizeVersion(version?: string | null) {
|
||||
return (version || '').trim().replace(/^v/i, '');
|
||||
@@ -116,7 +116,7 @@ function getDismissKey() {
|
||||
return `astrbot-upgrade-recovery-dismissed:${coreVersion.value}:${dashboardVersion.value}`;
|
||||
}
|
||||
|
||||
function recoveryRequestConfig(validateStatus = false): AxiosRequestConfig {
|
||||
function recoveryRequestConfig(validateStatus = false) {
|
||||
const headers: Record<string, string> = {};
|
||||
const token =
|
||||
localStorage.getItem('token') ||
|
||||
@@ -136,7 +136,7 @@ function recoveryRequestConfig(validateStatus = false): AxiosRequestConfig {
|
||||
|
||||
async function fetchLegacyStartTime() {
|
||||
const response = await recoveryClient.get<ApiEnvelope<StartTimeData>>(
|
||||
'/api/stat/start-time',
|
||||
resolveApiUrl('/api/stat/start-time'),
|
||||
recoveryRequestConfig(),
|
||||
);
|
||||
return response.data?.data?.start_time ?? null;
|
||||
@@ -196,7 +196,7 @@ async function restartCore() {
|
||||
initialStartTime.value =
|
||||
initialStartTime.value ?? (await fetchLegacyStartTime());
|
||||
await recoveryClient.post<ApiEnvelope<unknown>>(
|
||||
'/api/stat/restart-core',
|
||||
resolveApiUrl('/api/stat/restart-core'),
|
||||
undefined,
|
||||
recoveryRequestConfig(),
|
||||
);
|
||||
@@ -239,7 +239,7 @@ async function detectUpgradeMismatch() {
|
||||
detecting = true;
|
||||
try {
|
||||
const v1Response = await recoveryClient.get<ApiEnvelope<unknown>>(
|
||||
'/api/v1/auth/setup-status',
|
||||
resolveApiUrl('/api/v1/auth/setup-status'),
|
||||
recoveryRequestConfig(true),
|
||||
);
|
||||
if (!isMissingApiKeyResponse(v1Response)) {
|
||||
@@ -247,7 +247,7 @@ async function detectUpgradeMismatch() {
|
||||
}
|
||||
|
||||
const legacyResponse = await recoveryClient.get<ApiEnvelope<VersionData>>(
|
||||
'/api/stat/version',
|
||||
resolveApiUrl('/api/stat/version'),
|
||||
recoveryRequestConfig(true),
|
||||
);
|
||||
if (legacyResponse.status === 401 || legacyResponse.status >= 400) {
|
||||
|
||||
@@ -18,7 +18,7 @@ interface AuthStore {
|
||||
password: string,
|
||||
code?: string,
|
||||
trustDeviceToken?: boolean,
|
||||
): Promise<undefined | "totp_required">;
|
||||
): Promise<undefined | "totp_required" | "upgrade_recovery_required">;
|
||||
logout(): void;
|
||||
has_token(): boolean;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { router } from "@/router";
|
||||
import { createLoginProof, type LoginChallenge } from "@/utils/authLoginProof";
|
||||
import axios from "@/utils/request";
|
||||
import {
|
||||
authApi,
|
||||
providerApi,
|
||||
systemConfigApi,
|
||||
UPGRADE_RECOVERY_EVENT,
|
||||
UPGRADE_RECOVERY_TOKEN_KEY,
|
||||
type ApiEnvelope,
|
||||
type VersionData,
|
||||
} from "@/api/v1";
|
||||
import { httpClient } from "@/api/http";
|
||||
|
||||
export const useAuthStore = defineStore("auth", {
|
||||
state: () => ({
|
||||
@@ -14,17 +22,18 @@ export const useAuthStore = defineStore("auth", {
|
||||
localStorage.setItem("user", this.username);
|
||||
localStorage.setItem("token", data.token);
|
||||
const passwordUpgradeRequired = !!data?.password_upgrade_required;
|
||||
const passwordWarning = !!data?.change_pwd_hint || (!!data?.legacy_pwd_hint && !passwordUpgradeRequired);
|
||||
const md5PwdHint = !!data?.md5_pwd_hint;
|
||||
const passwordWarning = !!data?.change_pwd_hint || (md5PwdHint && !passwordUpgradeRequired);
|
||||
if (passwordWarning) {
|
||||
localStorage.setItem("change_pwd_hint", "true");
|
||||
if (data?.legacy_pwd_hint && !passwordUpgradeRequired) {
|
||||
localStorage.setItem("legacy_pwd_hint", "true");
|
||||
if (md5PwdHint && !passwordUpgradeRequired) {
|
||||
localStorage.setItem("md5_pwd_hint", "true");
|
||||
} else {
|
||||
localStorage.removeItem("legacy_pwd_hint");
|
||||
localStorage.removeItem("md5_pwd_hint");
|
||||
}
|
||||
} else {
|
||||
localStorage.removeItem("change_pwd_hint");
|
||||
localStorage.removeItem("legacy_pwd_hint");
|
||||
localStorage.removeItem("md5_pwd_hint");
|
||||
}
|
||||
if (passwordUpgradeRequired) {
|
||||
localStorage.setItem("password_upgrade_required", "true");
|
||||
@@ -49,64 +58,74 @@ export const useAuthStore = defineStore("auth", {
|
||||
password: string,
|
||||
code?: string,
|
||||
trustDeviceToken = false,
|
||||
): Promise<"totp_required" | undefined> {
|
||||
): Promise<"totp_required" | "upgrade_recovery_required" | void> {
|
||||
try {
|
||||
const challengeRes = await axios.post("/api/auth/login/challenge");
|
||||
const challenge = challengeRes.data?.data as LoginChallenge | undefined;
|
||||
if (!challenge) {
|
||||
return Promise.reject("Failed to initialize secure login");
|
||||
}
|
||||
|
||||
let res;
|
||||
if (challenge.algorithm === "argon2") {
|
||||
res = await axios.post(
|
||||
"/api/auth/login",
|
||||
{
|
||||
username: username,
|
||||
password: password,
|
||||
code: code,
|
||||
trust_device_flag: trustDeviceToken,
|
||||
},
|
||||
{
|
||||
validateStatus: (status) => (status >= 200 && status < 300) || status === 401,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const passwordProof = await createLoginProof(password, challenge);
|
||||
res = await axios.post(
|
||||
"/api/auth/login",
|
||||
{
|
||||
username: username,
|
||||
challenge_id: challenge.challenge_id,
|
||||
password_proof: passwordProof,
|
||||
code: code,
|
||||
trust_device_flag: trustDeviceToken,
|
||||
},
|
||||
{
|
||||
validateStatus: (status) => (status >= 200 && status < 300) || status === 401,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (res.status === 401 && res.data?.data?.totp_required) {
|
||||
return "totp_required";
|
||||
}
|
||||
const res = await authApi.login({
|
||||
username,
|
||||
password,
|
||||
code,
|
||||
trust_device_flag: trustDeviceToken,
|
||||
});
|
||||
|
||||
if (res.data.status === "error") {
|
||||
return Promise.reject(res.data.message);
|
||||
}
|
||||
|
||||
const legacyToken = String(res.data.data?.token || "");
|
||||
if (res.legacyFallback && legacyToken) {
|
||||
const versionRes = await httpClient.get<ApiEnvelope<VersionData>>(
|
||||
"/api/stat/version",
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${legacyToken}`,
|
||||
},
|
||||
validateStatus: () => true,
|
||||
},
|
||||
);
|
||||
const versionData = versionRes.data?.data || {};
|
||||
const coreVersion = String(versionData.version || "")
|
||||
.trim()
|
||||
.replace(/^v/i, "");
|
||||
const dashboardVersion = String(versionData.dashboard_version || "")
|
||||
.trim()
|
||||
.replace(/^v/i, "");
|
||||
if (
|
||||
versionRes.status < 400 &&
|
||||
coreVersion &&
|
||||
dashboardVersion &&
|
||||
coreVersion !== dashboardVersion
|
||||
) {
|
||||
sessionStorage.setItem(UPGRADE_RECOVERY_TOKEN_KEY, legacyToken);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent(UPGRADE_RECOVERY_EVENT, {
|
||||
detail: {
|
||||
version: versionData.version,
|
||||
dashboard_version: versionData.dashboard_version,
|
||||
blocking: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return "upgrade_recovery_required";
|
||||
}
|
||||
}
|
||||
|
||||
await this.finishAuthenticatedSession(res.data.data);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
} catch (error: any) {
|
||||
if (error?.response?.status === 401 && error.response?.data?.data?.totp_required) {
|
||||
return "totp_required";
|
||||
}
|
||||
return Promise.reject(error?.response?.data?.message || error);
|
||||
}
|
||||
},
|
||||
async setup(username: string, password: string, confirmPassword: string): Promise<void> {
|
||||
async setup(
|
||||
username: string,
|
||||
password: string,
|
||||
confirmPassword: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const endpoint = this.has_token() ? "/api/auth/setup-authenticated" : "/api/auth/setup";
|
||||
const res = await axios.post(endpoint, {
|
||||
username: username,
|
||||
password: password,
|
||||
const res = await authApi.setup({
|
||||
username,
|
||||
password,
|
||||
confirm_password: confirmPassword,
|
||||
});
|
||||
|
||||
@@ -122,12 +141,13 @@ export const useAuthStore = defineStore("auth", {
|
||||
async checkOnboardingCompleted(): Promise<boolean> {
|
||||
try {
|
||||
// 1. 检查平台配置
|
||||
const platformRes = await axios.get("/api/config/get");
|
||||
const hasPlatform = (platformRes.data.data.config.platform || []).length > 0;
|
||||
const platformRes = await systemConfigApi.get();
|
||||
const systemConfig = (platformRes.data.data as any).config || {};
|
||||
const hasPlatform = (systemConfig.platform || []).length > 0;
|
||||
if (!hasPlatform) return false;
|
||||
|
||||
// 2. 检查提供者配置
|
||||
const providerRes = await axios.get("/api/config/provider/template");
|
||||
const providerRes = await providerApi.schema();
|
||||
const providers = providerRes.data.data?.providers || [];
|
||||
const sources = providerRes.data.data?.provider_sources || [];
|
||||
const sourceMap = new Map();
|
||||
@@ -153,9 +173,9 @@ export const useAuthStore = defineStore("auth", {
|
||||
localStorage.removeItem("user");
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("change_pwd_hint");
|
||||
localStorage.removeItem("legacy_pwd_hint");
|
||||
localStorage.removeItem("md5_pwd_hint");
|
||||
localStorage.removeItem("password_upgrade_required");
|
||||
void axios.post("/api/auth/logout").catch(() => undefined);
|
||||
void authApi.logout().catch(() => undefined);
|
||||
router.push("/auth/login");
|
||||
},
|
||||
has_token(): boolean {
|
||||
|
||||
@@ -31,7 +31,7 @@ export function getPlatformIcon(name) {
|
||||
} else if (name === "kook") {
|
||||
return new URL("@/assets/images/platform_logos/kook.png", import.meta.url).href;
|
||||
} else if (name === "vocechat") {
|
||||
return new URL("@/assets/images/platform_logos/vocechat.png", import.meta.url).href;
|
||||
return new URL("@/assets/images/platform_logos/qq.png", import.meta.url).href;
|
||||
} else if (name === "satori" || name === "Satori") {
|
||||
return new URL("@/assets/images/platform_logos/satori.png", import.meta.url).href;
|
||||
} else if (name === "misskey") {
|
||||
|
||||
Reference in New Issue
Block a user