加入自动刷新RefreshToken的逻辑
This commit is contained in:
@@ -8,6 +8,7 @@ export namespace AuthApi {
|
||||
account?: string;
|
||||
password?: string;
|
||||
}
|
||||
|
||||
/** 注册 */
|
||||
export interface RegisterParams {
|
||||
account?: string;
|
||||
@@ -29,8 +30,8 @@ export namespace AuthApi {
|
||||
}
|
||||
|
||||
export interface RefreshTokenResult {
|
||||
data: string;
|
||||
status: number;
|
||||
accessToken: Token;
|
||||
refreshToken: Token;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,26 +59,23 @@ export async function sendCodeApi(str: string) {
|
||||
export async function registerApi(data: AuthApi.RegisterParams) {
|
||||
// 密码加密
|
||||
data.password = sha256(data.password?.toString() || '');
|
||||
return requestClient.post<any>('/user/register', data);
|
||||
return requestClient.post<AuthApi.LoginResult>('/user/register', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新accessToken
|
||||
*/
|
||||
export async function refreshTokenApi() {
|
||||
return baseRequestClient.post<AuthApi.RefreshTokenResult>(
|
||||
'/user/refreshToken',
|
||||
{
|
||||
withCredentials: true,
|
||||
},
|
||||
);
|
||||
export async function refreshTokenApi(refreshToken: null | string) {
|
||||
return requestClient.post<AuthApi.RefreshTokenResult>('/user/refreshToken', {
|
||||
refreshToken,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
export async function logoutApi() {
|
||||
return baseRequestClient.post('/auth/logout', {
|
||||
return baseRequestClient.post('/auth/logout', null, {
|
||||
withCredentials: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -53,10 +53,14 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
|
||||
*/
|
||||
async function doRefreshToken() {
|
||||
const accessStore = useAccessStore();
|
||||
const resp = await refreshTokenApi();
|
||||
const newToken = resp.data;
|
||||
accessStore.setAccessToken(newToken);
|
||||
return newToken;
|
||||
const resp = await refreshTokenApi(accessStore.refreshToken);
|
||||
const newAccessToken = resp.accessToken.token;
|
||||
const newRefreshToken = resp.refreshToken.token;
|
||||
if (newAccessToken) {
|
||||
accessStore.setAccessToken(newAccessToken);
|
||||
accessStore.setRefreshToken(newRefreshToken);
|
||||
}
|
||||
return newAccessToken;
|
||||
}
|
||||
|
||||
function formatToken(token: null | string) {
|
||||
|
||||
@@ -12,7 +12,8 @@ export const overridesPreferences = defineOverridesPreferences({
|
||||
layout: 'header-sidebar-nav',
|
||||
defaultHomePath: '/workspace', // 默认首页路径
|
||||
enablePreferences: false, // 是否启用偏好设置
|
||||
loginExpiredMode: 'page', // 登录过期模式 不用弹窗登录 跳转到页面登录,防止一些界面不会再加载
|
||||
enableRefreshToken: true, // 启动刷新token模式
|
||||
loginExpiredMode: 'modal', // 登录过期模式 不用弹窗登录 跳转到页面登录,防止一些界面不会再加载
|
||||
},
|
||||
theme: {
|
||||
mode: 'light',
|
||||
|
||||
@@ -33,11 +33,12 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
let userInfo: null | UserInfo = null;
|
||||
try {
|
||||
loginLoading.value = true;
|
||||
const { accessToken } = await loginApi(params);
|
||||
const { accessToken, refreshToken } = await loginApi(params);
|
||||
|
||||
// 如果成功获取到 accessToken
|
||||
if (accessToken) {
|
||||
accessStore.setAccessToken(accessToken.token);
|
||||
accessStore.setRefreshToken(refreshToken.token);
|
||||
|
||||
// 获取用户信息并存储到 accessStore 中
|
||||
const [fetchUserInfoResult, accessCodes] = await Promise.all([
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { Form, Input, message } from 'ant-design-vue';
|
||||
|
||||
import { createVideoTask } from '#/api/cv/iva';
|
||||
|
||||
const projectName = ref('');
|
||||
const fileName = ref('');
|
||||
const selectedFile = ref<File | null>(null);
|
||||
const fileInputRef = ref<HTMLInputElement | null>(null);
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
title: '新建蚕茧分析任务',
|
||||
class: 'w-[600px]',
|
||||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
onConfirm() {
|
||||
if (!projectName.value || !selectedFile.value) {
|
||||
message.warning('请填写项目名并选择蚕茧图片');
|
||||
return;
|
||||
}
|
||||
uploadFile();
|
||||
},
|
||||
});
|
||||
|
||||
async function uploadFile() {
|
||||
const formData = new FormData();
|
||||
formData.append('file', selectedFile.value!);
|
||||
formData.append('projectName', projectName.value);
|
||||
await createVideoTask(formData).then(() => {
|
||||
message.success('任务创建成功,正在处理图像,请稍后刷新列表查看');
|
||||
modalApi.close();
|
||||
// 清空表单
|
||||
projectName.value = '';
|
||||
fileName.value = '';
|
||||
selectedFile.value = null;
|
||||
});
|
||||
}
|
||||
|
||||
function selectFile() {
|
||||
fileInputRef.value?.click();
|
||||
}
|
||||
|
||||
function handleFileChange(event: Event) {
|
||||
const files = (event.target as HTMLInputElement).files;
|
||||
if (files && files.length > 0) {
|
||||
selectedFile.value = files[0];
|
||||
fileName.value = files[0].name;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal>
|
||||
<Form layout="vertical">
|
||||
<Form.Item label="项目名*" required>
|
||||
<Input v-model:value="projectName" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="上传图片*" required>
|
||||
<div
|
||||
@click="selectFile"
|
||||
style="
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: 1px dashed #d9d9d9;
|
||||
"
|
||||
>
|
||||
{{ fileName || '点击选择文件' }}
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
ref="fileInputRef"
|
||||
@change="handleFileChange"
|
||||
style="display: none"
|
||||
/>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</template>
|
||||
@@ -3,15 +3,12 @@ import type { EchartsUIType } from '@vben/plugins/echarts';
|
||||
|
||||
import { onActivated, onDeactivated, onMounted, ref, watch } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
||||
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
|
||||
import * as api from '#/api';
|
||||
|
||||
import CreateYSATaskModal from './CreateYSATaskModal.vue';
|
||||
|
||||
const list = ref<any[]>([]);
|
||||
const error = ref<null | string>(null);
|
||||
const filterKeyword = ref('');
|
||||
@@ -26,14 +23,6 @@ function refreshList() {
|
||||
loadList();
|
||||
message.success('列表加载完成');
|
||||
}
|
||||
const [BaseModal, baseModalApi] = useVbenModal({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: CreateYSATaskModal,
|
||||
});
|
||||
|
||||
function createTask() {
|
||||
baseModalApi.open();
|
||||
}
|
||||
|
||||
async function selectItem(item: any) {
|
||||
selectedItem.value = item;
|
||||
@@ -159,18 +148,12 @@ onActivated(() => {
|
||||
<template>
|
||||
<div class="flex h-[90dvh] w-full flex-col">
|
||||
<BaseModal />
|
||||
<CreateYSATaskModal />
|
||||
<div class="flex h-[90dvh] w-full bg-gray-50">
|
||||
<!-- 左侧:筛选 + 列表 -->
|
||||
<div class="flex w-64 flex-col border-r bg-white p-4">
|
||||
<!-- 按钮组 -->
|
||||
<div class="mb-4 flex justify-between space-x-2">
|
||||
<Button
|
||||
type="primary"
|
||||
@click="createTask"
|
||||
class="flex-1"
|
||||
:disabled="true"
|
||||
>
|
||||
<Button type="primary" class="flex-1" :disabled="true">
|
||||
新建任务
|
||||
</Button>
|
||||
<Button @click="refreshList" class="flex-1"> 刷新列表 </Button>
|
||||
|
||||
Reference in New Issue
Block a user