提交前端代码

This commit is contained in:
dengqichen 2024-11-29 18:02:28 +08:00
parent 7b3ffc69c0
commit 8f6de47af3
5 changed files with 154 additions and 200 deletions

View File

@ -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;

View File

@ -15,7 +15,7 @@ export interface LoginResult {
} }
export const login = async (data: LoginParams): Promise<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> => { export const logout = async (): Promise<void> => {
@ -23,7 +23,7 @@ export const logout = async (): Promise<void> => {
}; };
export const getUserMenus = async (): Promise<MenuDTO[]> => { 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) => { export const getUsers = async (params: any) => {

View File

@ -1,120 +1,120 @@
import React, { useEffect, useState } from 'react'; import React, {useEffect, useState} from 'react';
import { Form, Input, Button, message, Select } from 'antd'; import {Form, Input, Button, message, Select} from 'antd';
import { useNavigate } from 'react-router-dom'; import {useNavigate} from 'react-router-dom';
import { useDispatch } from 'react-redux'; import {useDispatch} from 'react-redux';
import { login } from '../../api/user'; import {login} from '../../api/user';
import { getEnabledTenants } from '../../pages/System/Tenant/service'; import {getEnabledTenants} from '../System/Tenant/service';
import { setToken, setUserInfo } from '../../store/userSlice'; import {setToken, setUserInfo} from '../../store/userSlice';
import type { LoginParams } from '../../types/user'; import type {LoginParams} from '../../types/user';
import type { TenantDTO } from '../../pages/System/Tenant/types'; import type {TenantDTO} from '../System/Tenant/types';
const Login: React.FC = () => { const Login: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useDispatch(); const dispatch = useDispatch();
const [form] = Form.useForm(); const [form] = Form.useForm();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [tenants, setTenants] = useState<TenantDTO[]>([]); const [tenants, setTenants] = useState<TenantDTO[]>([]);
useEffect(() => { useEffect(() => {
fetchTenants(); fetchTenants();
}, []); }, []);
const fetchTenants = async () => { const fetchTenants = async () => {
try { try {
const data = await getEnabledTenants(); const data = await getEnabledTenants();
setTenants(data); setTenants(data);
} catch (error) { } catch (error) {
console.error('获取租户列表失败:', error); console.error('获取租户列表失败:', error);
} }
}; };
const onFinish = async (values: LoginParams & { tenantId?: string }) => { const onFinish = async (values: LoginParams & { tenantId?: string }) => {
try { try {
setLoading(true); setLoading(true);
const { tenantId, ...loginParams } = values; const {tenantId, ...loginParams} = values;
const result = await login(loginParams); const result = await login(loginParams);
// 保存租户ID到localStorage
if (tenantId) {
localStorage.setItem('tenantId', tenantId);
}
dispatch(setToken(result.token)); // 保存租户ID到localStorage
dispatch(setUserInfo({ if (tenantId) {
id: result.id, localStorage.setItem('tenantId', tenantId);
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);
}
};
return ( dispatch(setToken(result.token));
<div style={{ dispatch(setUserInfo({
height: '100vh', id: result.id,
display: 'flex', username: result.username,
justifyContent: 'center', nickname: result.nickname,
alignItems: 'center', email: result.email,
background: '#f0f2f5' phone: result.phone
}}> }));
<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 message.success('登录成功');
name="username" navigate('/dashboard', {replace: true});
rules={[{ required: true, message: '请输入用户名!' }]} } catch (error) {
> console.error('登录失败:', error);
<Input placeholder="用户名" size="large" /> } finally {
</Form.Item> setLoading(false);
}
};
<Form.Item return (
name="password" <div style={{
rules={[{ required: true, message: '请输入密码!' }]} height: '100vh',
> display: 'flex',
<Input.Password placeholder="密码" size="large" /> justifyContent: 'center',
</Form.Item> 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> <Form.Item
<Button type="primary" htmlType="submit" block size="large" loading={loading}> name="username"
rules={[{required: true, message: '请输入用户名!'}]}
</Button> >
</Form.Item> <Input placeholder="用户名" size="large"/>
</Form> </Form.Item>
</div>
</div> <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>
);
}; };
export default Login; export default Login;

View File

@ -1,37 +1,37 @@
import request from '@/utils/request'; import request from '@/utils/request';
import type { TenantDTO, TenantQuery } from './types'; import type {TenantDTO, TenantQuery} from './types';
// 获取租户列表(分页) // 获取租户列表(分页)
export const getTenants = async (params?: TenantQuery) => { 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 () => { 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>) => { 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>) => { 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) => { 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) => { 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) => { 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}});
}; };

View File

@ -1,55 +1,53 @@
import axios, { AxiosResponse } from 'axios'; import axios, {AxiosResponse} from 'axios';
import { message } from 'antd'; import {message} from 'antd';
export interface ApiResponse<T> { export interface ApiResponse<T> {
code: number; code: number;
message: string; message: string;
data: T; data: T;
success: boolean; success: boolean;
} }
const request = axios.create({ const request = axios.create({
baseURL: '', baseURL: '',
timeout: 300000, timeout: 300000,
withCredentials: true, withCredentials: true,
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}); });
request.interceptors.request.use( request.interceptors.request.use(
(config) => { (config) => {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
const tenantId = localStorage.getItem('tenantId'); const tenantId = localStorage.getItem('tenantId');
if (token) {
if (token) { config.headers.Authorization = `Bearer ${token}`;
config.headers.Authorization = `Bearer ${token}`; }
if (tenantId) {
config.headers['X-Devops-Tenant-Id'] = tenantId;
}
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( request.interceptors.response.use(
(response: AxiosResponse<ApiResponse<any>>) => { (response: AxiosResponse<ApiResponse<any>>) => {
const res = response.data; const res = response.data;
if (res.code !== 200) { if (res.code !== 200) {
message.error(res.message || '请求失败'); message.error(res.message || '请求失败');
return Promise.reject(new 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; export default request;