refactor: improve login-related logic (#617)

#### What type of PR is this?

/kind improvement
/milestone 2.0

#### What this PR does / why we need it:

适配 https://github.com/halo-dev/halo/pull/2453

1. 将生产构建的 base url 更改为 console
2. 优化登录之后跳转的逻辑。

#### Which issue(s) this PR fixes:

#### Special notes for your reviewer:

/cc @halo-dev/sig-halo-admin

测试方式:

1. 在本地根据此 PR 构建生产版本(pnpm build)
2. 根据 https://github.com/halo-dev/halo/pull/2453#issue-1381947867 中的描述修改配置文件。
3. 访问 http://localhost:8090/console

#### Does this PR introduce a user-facing change?

```release-note
None
```
pull/615/head
Ryan Wang 2022-09-22 20:46:12 +08:00 committed by GitHub
parent 32356070e4
commit 539fd8fd14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 75 deletions

View File

@ -1,2 +1,2 @@
VITE_API_URL= VITE_API_URL=
VITE_BASE_URL=/admin/ VITE_BASE_URL=/console/

View File

@ -8,7 +8,7 @@ import type {
MenuItemType, MenuItemType,
Plugin, Plugin,
} from "@halo-dev/admin-shared"; } from "@halo-dev/admin-shared";
import { apiClient, setApiUrl } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import { menus, minimenus, registerMenu } from "./router/menus.config"; import { menus, minimenus, registerMenu } from "./router/menus.config";
// setup // setup
import "./setup/setupStyles"; import "./setup/setupStyles";
@ -24,7 +24,6 @@ import { useRoleStore } from "@/stores/role";
const app = createApp(App); const app = createApp(App);
setupComponents(app); setupComponents(app);
setApiUrl(import.meta.env.VITE_API_URL);
app.use(createPinia()); app.use(createPinia());

View File

@ -1,12 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { import { IconShieldUser, IconUserLine, VButton } from "@halo-dev/components";
IconShieldUser,
IconUserSettings,
VButton,
} from "@halo-dev/components";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import qs from "qs"; import qs from "qs";
import logo from "../../../assets/logo.svg"; import logo from "@/assets/logo.svg";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { submitForm } from "@formkit/vue"; import { submitForm } from "@formkit/vue";
import router from "@/router"; import router from "@/router";
@ -17,30 +13,22 @@ interface LoginForm {
password: string; password: string;
} }
interface LoginFormState { const loginForm = ref<LoginForm>({
logging: boolean; _csrf: "",
state: LoginForm; username: "",
} password: "",
const loginForm = ref<LoginFormState>({
logging: false,
state: {
_csrf: "",
username: "ryanwang",
password: "12345678",
},
}); });
const loading = ref(false);
const handleGenerateToken = async () => { const handleGenerateToken = async () => {
const token = uuid(); const token = uuid();
loginForm.value.state._csrf = token; loginForm.value._csrf = token;
document.cookie = `XSRF-TOKEN=${token}; Path=/;`; document.cookie = `XSRF-TOKEN=${token}; Path=/;`;
}; };
const handleLogin = async () => { const handleLogin = async () => {
try { try {
loginForm.value.logging = true; loading.value = true;
await fetch(`${import.meta.env.VITE_API_URL}/login`, { await fetch(`${import.meta.env.VITE_API_URL}/login`, {
method: "POST", method: "POST",
headers: { headers: {
@ -48,14 +36,14 @@ const handleLogin = async () => {
}, },
credentials: "include", credentials: "include",
redirect: "manual", redirect: "manual",
body: qs.stringify(loginForm.value.state), body: qs.stringify(loginForm.value),
}); });
await router.push({ name: "Dashboard" }); await router.push({ name: "Dashboard" });
await router.go(0); await router.go(0);
} catch (e) { } catch (e) {
console.error(e); console.error("Failed to login", e);
} finally { } finally {
loginForm.value.logging = false; loading.value = false;
} }
}; };
@ -66,13 +54,15 @@ onMounted(() => {
<template> <template>
<div class="flex h-screen flex-col items-center justify-center"> <div class="flex h-screen flex-col items-center justify-center">
<img :src="logo" alt="Logo" class="mb-8 w-20" /> <img :src="logo" alt="Logo" class="mb-8 w-20" />
<div class="login-form w-72"> <div class="login-form flex w-72 flex-col gap-4">
<FormKit <FormKit
id="login" id="login-form"
v-model="loginForm.state" v-model="loginForm"
:actions="false" :actions="false"
type="form" type="form"
:config="{ animation: 'none' }"
@submit="handleLogin" @submit="handleLogin"
@keyup.enter="submitForm('login-form')"
> >
<FormKit <FormKit
:validation-messages="{ :validation-messages="{
@ -84,7 +74,7 @@ onMounted(() => {
validation="required" validation="required"
> >
<template #prefixIcon> <template #prefixIcon>
<IconUserSettings /> <IconUserLine />
</template> </template>
</FormKit> </FormKit>
<FormKit <FormKit
@ -100,10 +90,10 @@ onMounted(() => {
<IconShieldUser /> <IconShieldUser />
</template> </template>
</FormKit> </FormKit>
<VButton block type="secondary" @click="submitForm('login')">
登录
</VButton>
</FormKit> </FormKit>
<VButton block type="secondary" @click="submitForm('login-form')">
登录
</VButton>
</div> </div>
</div> </div>
</template> </template>

View File

@ -32,95 +32,101 @@ import {
} from "@halo-dev/api-client"; } from "@halo-dev/api-client";
import type { AxiosInstance } from "axios"; import type { AxiosInstance } from "axios";
import axios from "axios"; import axios from "axios";
import router from "@/router";
const baseURL = import.meta.env.VITE_API_URL;
let apiUrl: string | undefined;
const axiosInstance = axios.create({ const axiosInstance = axios.create({
baseURL,
withCredentials: true, withCredentials: true,
}); });
let apiClient = setupApiClient(axiosInstance);
axiosInstance.interceptors.response.use( axiosInstance.interceptors.response.use(
(response) => { (response) => {
return response; return response;
}, },
async (error) => { async (error) => {
console.log("error", error);
if (error.response.status === 401) { if (error.response.status === 401) {
window.location.href = "/#/login"; router.push({
name: "Login",
});
} }
return Promise.reject(error); return Promise.reject(error);
} }
); );
const setApiUrl = (url: string) => { const apiClient = setupApiClient(axiosInstance);
axiosInstance.defaults.baseURL = url;
apiUrl = url;
apiClient = setupApiClient(axiosInstance);
};
function setupApiClient(axios: AxiosInstance) { function setupApiClient(axios: AxiosInstance) {
return { return {
extension: { extension: {
configMap: new V1alpha1ConfigMapApi(undefined, apiUrl, axios), configMap: new V1alpha1ConfigMapApi(undefined, baseURL, axios),
personalAccessToken: new V1alpha1PersonalAccessTokenApi( personalAccessToken: new V1alpha1PersonalAccessTokenApi(
undefined, undefined,
apiUrl, baseURL,
axios axios
), ),
roleBinding: new V1alpha1RoleBindingApi(undefined, apiUrl, axios), roleBinding: new V1alpha1RoleBindingApi(undefined, baseURL, axios),
role: new V1alpha1RoleApi(undefined, apiUrl, axios), role: new V1alpha1RoleApi(undefined, baseURL, axios),
setting: new V1alpha1SettingApi(undefined, apiUrl, axios), setting: new V1alpha1SettingApi(undefined, baseURL, axios),
reverseProxy: new PluginHaloRunV1alpha1ReverseProxyApi( reverseProxy: new PluginHaloRunV1alpha1ReverseProxyApi(
undefined, undefined,
apiUrl, baseURL,
axios axios
), ),
plugin: new PluginHaloRunV1alpha1PluginApi(undefined, apiUrl, axios), plugin: new PluginHaloRunV1alpha1PluginApi(undefined, baseURL, axios),
user: new V1alpha1UserApi(undefined, apiUrl, axios), user: new V1alpha1UserApi(undefined, baseURL, axios),
theme: new ThemeHaloRunV1alpha1ThemeApi(undefined, apiUrl, axios), theme: new ThemeHaloRunV1alpha1ThemeApi(undefined, baseURL, axios),
menu: new V1alpha1MenuApi(undefined, apiUrl, axios), menu: new V1alpha1MenuApi(undefined, baseURL, axios),
menuItem: new V1alpha1MenuItemApi(undefined, apiUrl, axios), menuItem: new V1alpha1MenuItemApi(undefined, baseURL, axios),
post: new ContentHaloRunV1alpha1PostApi(undefined, apiUrl, axios), post: new ContentHaloRunV1alpha1PostApi(undefined, baseURL, axios),
singlePage: new ContentHaloRunV1alpha1SinglePageApi( singlePage: new ContentHaloRunV1alpha1SinglePageApi(
undefined, undefined,
apiUrl, baseURL,
axios axios
), ),
category: new ContentHaloRunV1alpha1CategoryApi(undefined, apiUrl, axios), category: new ContentHaloRunV1alpha1CategoryApi(
tag: new ContentHaloRunV1alpha1TagApi(undefined, apiUrl, axios), undefined,
snapshot: new ContentHaloRunV1alpha1SnapshotApi(undefined, apiUrl, axios), baseURL,
comment: new ContentHaloRunV1alpha1CommentApi(undefined, apiUrl, axios), axios
reply: new ContentHaloRunV1alpha1ReplyApi(undefined, apiUrl, axios), ),
tag: new ContentHaloRunV1alpha1TagApi(undefined, baseURL, axios),
snapshot: new ContentHaloRunV1alpha1SnapshotApi(
undefined,
baseURL,
axios
),
comment: new ContentHaloRunV1alpha1CommentApi(undefined, baseURL, axios),
reply: new ContentHaloRunV1alpha1ReplyApi(undefined, baseURL, axios),
storage: { storage: {
group: new StorageHaloRunV1alpha1GroupApi(undefined, apiUrl, axios), group: new StorageHaloRunV1alpha1GroupApi(undefined, baseURL, axios),
attachment: new StorageHaloRunV1alpha1AttachmentApi( attachment: new StorageHaloRunV1alpha1AttachmentApi(
undefined, undefined,
apiUrl, baseURL,
axios axios
), ),
policy: new StorageHaloRunV1alpha1PolicyApi(undefined, apiUrl, axios), policy: new StorageHaloRunV1alpha1PolicyApi(undefined, baseURL, axios),
policyTemplate: new StorageHaloRunV1alpha1PolicyTemplateApi( policyTemplate: new StorageHaloRunV1alpha1PolicyTemplateApi(
undefined, undefined,
apiUrl, baseURL,
axios axios
), ),
}, },
}, },
// custom endpoints // custom endpoints
user: new ApiConsoleHaloRunV1alpha1UserApi(undefined, apiUrl, axios), user: new ApiConsoleHaloRunV1alpha1UserApi(undefined, baseURL, axios),
plugin: new ApiConsoleHaloRunV1alpha1PluginApi(undefined, apiUrl, axios), plugin: new ApiConsoleHaloRunV1alpha1PluginApi(undefined, baseURL, axios),
theme: new ApiConsoleHaloRunV1alpha1ThemeApi(undefined, apiUrl, axios), theme: new ApiConsoleHaloRunV1alpha1ThemeApi(undefined, baseURL, axios),
post: new ApiConsoleHaloRunV1alpha1PostApi(undefined, apiUrl, axios), post: new ApiConsoleHaloRunV1alpha1PostApi(undefined, baseURL, axios),
singlePage: new ApiConsoleHaloRunV1alpha1SinglePageApi( singlePage: new ApiConsoleHaloRunV1alpha1SinglePageApi(
undefined, undefined,
apiUrl, baseURL,
axios axios
), ),
content: new ApiConsoleHaloRunV1alpha1ContentApi(undefined, apiUrl, axios), content: new ApiConsoleHaloRunV1alpha1ContentApi(undefined, baseURL, axios),
comment: new ApiConsoleHaloRunV1alpha1CommentApi(undefined, apiUrl, axios), comment: new ApiConsoleHaloRunV1alpha1CommentApi(undefined, baseURL, axios),
reply: new ApiConsoleHaloRunV1alpha1ReplyApi(undefined, apiUrl, axios), reply: new ApiConsoleHaloRunV1alpha1ReplyApi(undefined, baseURL, axios),
}; };
} }
export { apiClient, setApiUrl }; export { apiClient };