提交前端代码

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> => {
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) => {

View File

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

View File

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

View File

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