提交前端代码
This commit is contained in:
parent
7b3ffc69c0
commit
8f6de47af3
@ -1,44 +0,0 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { message } from 'antd';
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number;
|
||||
message: string;
|
||||
data: T;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
const request = axios.create({
|
||||
baseURL: '/api',
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
request.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
request.interceptors.response.use(
|
||||
(response: AxiosResponse<ApiResponse<any>>) => {
|
||||
const res = response.data;
|
||||
if (res.code !== 200) {
|
||||
message.error(res.message || '请求失败');
|
||||
return Promise.reject(new Error(res.message || '请求失败'));
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
(error) => {
|
||||
message.error(error.message || '请求失败');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default request;
|
||||
@ -15,7 +15,7 @@ export interface LoginResult {
|
||||
}
|
||||
|
||||
export const login = async (data: LoginParams): Promise<LoginResult> => {
|
||||
return request.post('/api/auth/login', data);
|
||||
return request.post('/api/v1/users/login', data);
|
||||
};
|
||||
|
||||
export const logout = async (): Promise<void> => {
|
||||
@ -23,7 +23,7 @@ export const logout = async (): Promise<void> => {
|
||||
};
|
||||
|
||||
export const getUserMenus = async (): Promise<MenuDTO[]> => {
|
||||
return request.get('/api/system/user/menus');
|
||||
return request.get('/api/v1/menu/user');
|
||||
};
|
||||
|
||||
export const getUsers = async (params: any) => {
|
||||
|
||||
@ -1,120 +1,120 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Form, Input, Button, message, Select } from 'antd';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { login } from '../../api/user';
|
||||
import { getEnabledTenants } from '../../pages/System/Tenant/service';
|
||||
import { setToken, setUserInfo } from '../../store/userSlice';
|
||||
import type { LoginParams } from '../../types/user';
|
||||
import type { TenantDTO } from '../../pages/System/Tenant/types';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {Form, Input, Button, message, Select} from 'antd';
|
||||
import {useNavigate} from 'react-router-dom';
|
||||
import {useDispatch} from 'react-redux';
|
||||
import {login} from '../../api/user';
|
||||
import {getEnabledTenants} from '../System/Tenant/service';
|
||||
import {setToken, setUserInfo} from '../../store/userSlice';
|
||||
import type {LoginParams} from '../../types/user';
|
||||
import type {TenantDTO} from '../System/Tenant/types';
|
||||
|
||||
const Login: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [tenants, setTenants] = useState<TenantDTO[]>([]);
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [tenants, setTenants] = useState<TenantDTO[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchTenants();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
fetchTenants();
|
||||
}, []);
|
||||
|
||||
const fetchTenants = async () => {
|
||||
try {
|
||||
const data = await getEnabledTenants();
|
||||
setTenants(data);
|
||||
} catch (error) {
|
||||
console.error('获取租户列表失败:', error);
|
||||
}
|
||||
};
|
||||
const fetchTenants = async () => {
|
||||
try {
|
||||
const data = await getEnabledTenants();
|
||||
setTenants(data);
|
||||
} catch (error) {
|
||||
console.error('获取租户列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const onFinish = async (values: LoginParams & { tenantId?: string }) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { tenantId, ...loginParams } = values;
|
||||
const result = await login(loginParams);
|
||||
const onFinish = async (values: LoginParams & { tenantId?: string }) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const {tenantId, ...loginParams} = values;
|
||||
const result = await login(loginParams);
|
||||
|
||||
// 保存租户ID到localStorage
|
||||
if (tenantId) {
|
||||
localStorage.setItem('tenantId', tenantId);
|
||||
}
|
||||
// 保存租户ID到localStorage
|
||||
if (tenantId) {
|
||||
localStorage.setItem('tenantId', tenantId);
|
||||
}
|
||||
|
||||
dispatch(setToken(result.token));
|
||||
dispatch(setUserInfo({
|
||||
id: result.id,
|
||||
username: result.username,
|
||||
nickname: result.nickname,
|
||||
email: result.email,
|
||||
phone: result.phone
|
||||
}));
|
||||
dispatch(setToken(result.token));
|
||||
dispatch(setUserInfo({
|
||||
id: result.id,
|
||||
username: result.username,
|
||||
nickname: result.nickname,
|
||||
email: result.email,
|
||||
phone: result.phone
|
||||
}));
|
||||
|
||||
message.success('登录成功');
|
||||
navigate('/dashboard', { replace: true });
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
message.success('登录成功');
|
||||
navigate('/dashboard', {replace: true});
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
height: '100vh',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
background: '#f0f2f5'
|
||||
}}>
|
||||
<div style={{
|
||||
width: '400px',
|
||||
padding: '40px',
|
||||
background: '#fff',
|
||||
borderRadius: '8px',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
|
||||
}}>
|
||||
<h2 style={{ textAlign: 'center', marginBottom: '30px' }}>系统登录</h2>
|
||||
<Form
|
||||
form={form}
|
||||
name="login"
|
||||
onFinish={onFinish}
|
||||
autoComplete="off"
|
||||
>
|
||||
<Form.Item
|
||||
name="tenantId"
|
||||
rules={[{ required: true, message: '请选择租户!' }]}
|
||||
>
|
||||
<Select
|
||||
placeholder="请选择租户"
|
||||
options={tenants.map(tenant => ({
|
||||
label: tenant.name,
|
||||
value: tenant.code
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
return (
|
||||
<div style={{
|
||||
height: '100vh',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
background: '#f0f2f5'
|
||||
}}>
|
||||
<div style={{
|
||||
width: '400px',
|
||||
padding: '40px',
|
||||
background: '#fff',
|
||||
borderRadius: '8px',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
|
||||
}}>
|
||||
<h2 style={{textAlign: 'center', marginBottom: '30px'}}>系统登录</h2>
|
||||
<Form
|
||||
form={form}
|
||||
name="login"
|
||||
onFinish={onFinish}
|
||||
autoComplete="off"
|
||||
>
|
||||
<Form.Item
|
||||
name="tenantId"
|
||||
rules={[{required: true, message: '请选择租户!'}]}
|
||||
>
|
||||
<Select
|
||||
placeholder="请选择租户"
|
||||
options={tenants.map(tenant => ({
|
||||
label: tenant.name,
|
||||
value: tenant.code
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="username"
|
||||
rules={[{ required: true, message: '请输入用户名!' }]}
|
||||
>
|
||||
<Input placeholder="用户名" size="large" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="username"
|
||||
rules={[{required: true, message: '请输入用户名!'}]}
|
||||
>
|
||||
<Input placeholder="用户名" size="large"/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="password"
|
||||
rules={[{ required: true, message: '请输入密码!' }]}
|
||||
>
|
||||
<Input.Password placeholder="密码" size="large" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="password"
|
||||
rules={[{required: true, message: '请输入密码!'}]}
|
||||
>
|
||||
<Input.Password placeholder="密码" size="large"/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" block size="large" loading={loading}>
|
||||
登录
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" block size="large" loading={loading}>
|
||||
登录
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
@ -1,37 +1,37 @@
|
||||
import request from '@/utils/request';
|
||||
import type { TenantDTO, TenantQuery } from './types';
|
||||
import type {TenantDTO, TenantQuery} from './types';
|
||||
|
||||
// 获取租户列表(分页)
|
||||
export const getTenants = async (params?: TenantQuery) => {
|
||||
return request.get<TenantDTO[]>('/api/system/tenants', { params });
|
||||
return request.get<TenantDTO[]>('/api/system/tenants', {params});
|
||||
};
|
||||
|
||||
// 获取所有启用的租户(用于登录页面)
|
||||
export const getEnabledTenants = async () => {
|
||||
return request.get<TenantDTO[]>('/api/system/tenants/list');
|
||||
return request.get<TenantDTO[]>('/api/v1/tenant/list');
|
||||
};
|
||||
|
||||
// 创建租户
|
||||
export const createTenant = async (data: Partial<TenantDTO>) => {
|
||||
return request.post<TenantDTO>('/api/system/tenants', data);
|
||||
return request.post<TenantDTO>('/api/system/tenants', data);
|
||||
};
|
||||
|
||||
// 更新租户
|
||||
export const updateTenant = async (id: number, data: Partial<TenantDTO>) => {
|
||||
return request.put<TenantDTO>(`/api/system/tenants/${id}`, data);
|
||||
return request.put<TenantDTO>(`/api/system/tenants/${id}`, data);
|
||||
};
|
||||
|
||||
// 删除租户
|
||||
export const deleteTenant = async (id: number) => {
|
||||
return request.delete(`/api/system/tenants/${id}`);
|
||||
return request.delete(`/api/system/tenants/${id}`);
|
||||
};
|
||||
|
||||
// 检查租户编码是否存在
|
||||
export const checkTenantCode = async (code: string) => {
|
||||
return request.get<boolean>(`/api/system/tenants/check-code`, { params: { code } });
|
||||
return request.get<boolean>(`/api/system/tenants/check-code`, {params: {code}});
|
||||
};
|
||||
|
||||
// 检查租户名称是否存在
|
||||
export const checkTenantName = async (name: string) => {
|
||||
return request.get<boolean>(`/api/system/tenants/check-name`, { params: { name } });
|
||||
return request.get<boolean>(`/api/system/tenants/check-name`, {params: {name}});
|
||||
};
|
||||
@ -1,55 +1,53 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { message } from 'antd';
|
||||
import axios, {AxiosResponse} from 'axios';
|
||||
import {message} from 'antd';
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number;
|
||||
message: string;
|
||||
data: T;
|
||||
success: boolean;
|
||||
code: number;
|
||||
message: string;
|
||||
data: T;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
const request = axios.create({
|
||||
baseURL: '',
|
||||
timeout: 300000,
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
baseURL: '',
|
||||
timeout: 300000,
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
request.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = localStorage.getItem('token');
|
||||
const tenantId = localStorage.getItem('tenantId');
|
||||
(config) => {
|
||||
const token = localStorage.getItem('token');
|
||||
const tenantId = localStorage.getItem('tenantId');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
if (tenantId) {
|
||||
config.headers['X-Devops-Tenant-Id'] = tenantId;
|
||||
}
|
||||
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
if (tenantId) {
|
||||
config.headers['X-Tenant-ID'] = tenantId;
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
request.interceptors.response.use(
|
||||
(response: AxiosResponse<ApiResponse<any>>) => {
|
||||
const res = response.data;
|
||||
if (res.code !== 200) {
|
||||
message.error(res.message || '请求失败');
|
||||
return Promise.reject(new Error(res.message || '请求失败'));
|
||||
(response: AxiosResponse<ApiResponse<any>>) => {
|
||||
const res = response.data;
|
||||
if (res.code !== 200) {
|
||||
message.error(res.message || '请求失败');
|
||||
return Promise.reject(new Error(res.message || '请求失败'));
|
||||
}
|
||||
return Promise.resolve(res.data);
|
||||
},
|
||||
(error) => {
|
||||
message.error(error.response?.data?.message || '请求失败');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
return Promise.resolve(res.data);
|
||||
},
|
||||
(error) => {
|
||||
message.error(error.response?.data?.message || '请求失败');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default request;
|
||||
Loading…
Reference in New Issue
Block a user