增加了request、reponse、service规范
This commit is contained in:
parent
39b26ac2f8
commit
9fce8ff134
@ -1,47 +0,0 @@
|
|||||||
import request from '@/utils/request';
|
|
||||||
import type { MenuDTO } from '@/pages/System/Menu/types';
|
|
||||||
import type { UserDTO } from '@/pages/System/User/types';
|
|
||||||
|
|
||||||
export interface LoginParams {
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoginResult {
|
|
||||||
token: string;
|
|
||||||
userId: number;
|
|
||||||
username: string;
|
|
||||||
nickname: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const login = async (data: LoginParams): Promise<LoginResult> => {
|
|
||||||
return request.post('/api/v1/users/login', data);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const logout = async (): Promise<void> => {
|
|
||||||
return request.post('/api/auth/logout');
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getUserMenus = async (): Promise<MenuDTO[]> => {
|
|
||||||
return request.get('/api/v1/menu/user');
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getUsers = async (params: any) => {
|
|
||||||
return request.get('/api/system/users', { params });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createUser = async (data: any) => {
|
|
||||||
return request.post('/api/system/users', data);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateUser = async (id: number, data: any) => {
|
|
||||||
return request.put(`/api/system/users/${id}`, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteUser = async (id: number) => {
|
|
||||||
return request.delete(`/api/system/users/${id}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const resetPassword = async (id: number) => {
|
|
||||||
return request.post(`/api/system/users/${id}/reset-password`);
|
|
||||||
};
|
|
||||||
@ -11,9 +11,9 @@ import {
|
|||||||
CloudOutlined
|
CloudOutlined
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import * as AntdIcons from '@ant-design/icons';
|
import * as AntdIcons from '@ant-design/icons';
|
||||||
import { logout, setMenus } from '../store/userSlice';
|
import { logout, setMenus, setUserInfo } from '../store/userSlice';
|
||||||
import type { MenuProps } from 'antd';
|
import type { MenuProps } from 'antd';
|
||||||
import { getUserMenus } from '../api/user';
|
import { getCurrentUser, getUserMenus } from '../pages/Login/service';
|
||||||
import { getWeather } from '../services/weather';
|
import { getWeather } from '../services/weather';
|
||||||
import type { MenuDTO } from '../pages/System/Menu/types';
|
import type { MenuDTO } from '../pages/System/Menu/types';
|
||||||
import type { RootState } from '../store';
|
import type { RootState } from '../store';
|
||||||
@ -35,6 +35,7 @@ const BasicLayout: React.FC = () => {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [currentTime, setCurrentTime] = useState(dayjs());
|
const [currentTime, setCurrentTime] = useState(dayjs());
|
||||||
const [weather, setWeather] = useState({ temp: '--', weather: '未知', city: '未知' });
|
const [weather, setWeather] = useState({ temp: '--', weather: '未知', city: '未知' });
|
||||||
|
const [isInitialized, setIsInitialized] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 每秒更新时间
|
// 每秒更新时间
|
||||||
@ -44,11 +45,39 @@ const BasicLayout: React.FC = () => {
|
|||||||
|
|
||||||
// 获取天气信息
|
// 获取天气信息
|
||||||
const fetchWeather = async () => {
|
const fetchWeather = async () => {
|
||||||
const data = await getWeather();
|
try {
|
||||||
setWeather(data);
|
const data = await getWeather();
|
||||||
|
setWeather(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取天气信息失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化用户数据
|
||||||
|
const initializeUserData = async () => {
|
||||||
|
if (isInitialized) return;
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
// 获取并更新用户信息
|
||||||
|
const userData = await getCurrentUser();
|
||||||
|
dispatch(setUserInfo(userData));
|
||||||
|
|
||||||
|
// 获取并更新用户菜单
|
||||||
|
const menuData = await getUserMenus();
|
||||||
|
dispatch(setMenus(menuData));
|
||||||
|
|
||||||
|
setIsInitialized(true);
|
||||||
|
} catch (error) {
|
||||||
|
message.error('初始化用户数据失败');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchWeather();
|
fetchWeather();
|
||||||
|
initializeUserData();
|
||||||
|
|
||||||
// 每半小时更新一次天气
|
// 每半小时更新一次天气
|
||||||
const weatherTimer = setInterval(fetchWeather, 30 * 60 * 1000);
|
const weatherTimer = setInterval(fetchWeather, 30 * 60 * 1000);
|
||||||
|
|
||||||
@ -56,22 +85,7 @@ const BasicLayout: React.FC = () => {
|
|||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
clearInterval(weatherTimer);
|
clearInterval(weatherTimer);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [isInitialized]);
|
||||||
|
|
||||||
const fetchUserMenus = async () => {
|
|
||||||
try {
|
|
||||||
const data = await getUserMenus();
|
|
||||||
dispatch(setMenus(data));
|
|
||||||
} catch (error) {
|
|
||||||
message.error('获取菜单失败');
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchUserMenus();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
confirm({
|
confirm({
|
||||||
|
|||||||
@ -2,18 +2,11 @@ import React from 'react';
|
|||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { ConfigProvider } from 'antd';
|
|
||||||
import zhCN from 'antd/locale/zh_CN';
|
|
||||||
import router from './router';
|
import router from './router';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
import './index.css';
|
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<React.StrictMode>
|
<Provider store={store}>
|
||||||
<Provider store={store}>
|
<RouterProvider router={router} />
|
||||||
<ConfigProvider locale={zhCN}>
|
</Provider>
|
||||||
<RouterProvider router={router} />
|
|
||||||
</ConfigProvider>
|
|
||||||
</Provider>
|
|
||||||
</React.StrictMode>
|
|
||||||
);
|
);
|
||||||
@ -1,17 +1,62 @@
|
|||||||
.container {
|
.loginContainer {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #f0f2f5;
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.loginCard {
|
.loginBox {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
|
padding: 40px;
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.loginCard :global(.ant-card-head-title) {
|
.logo {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo img {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo h1 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: bold;
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:hover,
|
||||||
|
.input:focus {
|
||||||
|
border-color: #764ba2;
|
||||||
|
box-shadow: 0 0 0 2px rgba(118, 75, 162, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loginButton {
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
border: none;
|
||||||
|
margin-top: 16px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loginButton:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(118, 75, 162, 0.4);
|
||||||
}
|
}
|
||||||
@ -2,52 +2,36 @@ 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, getTenantList} from './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 styles from './index.module.css';
|
||||||
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([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const fetchTenants = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getTenantList();
|
||||||
|
setTenants(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取租户列表失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
fetchTenants();
|
fetchTenants();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchTenants = async () => {
|
const onFinish = async (values) => {
|
||||||
try {
|
|
||||||
const data = await getEnabledTenants();
|
|
||||||
setTenants(data);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取租户列表失败:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onFinish = async (values: LoginParams & { tenantId?: string }) => {
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const {tenantId, ...loginParams} = values;
|
const result = await login(values);
|
||||||
const result = await login(loginParams);
|
|
||||||
|
|
||||||
// 保存租户ID到localStorage
|
|
||||||
if (tenantId) {
|
|
||||||
localStorage.setItem('tenantId', tenantId);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(setToken(result.token));
|
dispatch(setToken(result.token));
|
||||||
dispatch(setUserInfo({
|
dispatch(setUserInfo(result));
|
||||||
id: result.id,
|
|
||||||
username: result.username,
|
|
||||||
nickname: result.nickname,
|
|
||||||
email: result.email,
|
|
||||||
phone: result.phone
|
|
||||||
}));
|
|
||||||
|
|
||||||
message.success('登录成功');
|
message.success('登录成功');
|
||||||
navigate('/dashboard', {replace: true});
|
navigate('/dashboard', {replace: true});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -58,26 +42,18 @@ const Login: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div className={styles.loginContainer}>
|
||||||
height: '100vh',
|
<div className={styles.loginBox}>
|
||||||
display: 'flex',
|
<div className={styles.logo}>
|
||||||
justifyContent: 'center',
|
<img src="/logo.png" alt="QC-NAS" />
|
||||||
alignItems: 'center',
|
<h1>QC-NAS</h1>
|
||||||
background: '#f0f2f5'
|
</div>
|
||||||
}}>
|
|
||||||
<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={form}
|
form={form}
|
||||||
name="login"
|
name="login"
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
|
size="large"
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="tenantId"
|
name="tenantId"
|
||||||
@ -89,6 +65,7 @@ const Login: React.FC = () => {
|
|||||||
label: tenant.name,
|
label: tenant.name,
|
||||||
value: tenant.code
|
value: tenant.code
|
||||||
}))}
|
}))}
|
||||||
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
@ -96,18 +73,30 @@ const Login: React.FC = () => {
|
|||||||
name="username"
|
name="username"
|
||||||
rules={[{required: true, message: '请输入用户名!'}]}
|
rules={[{required: true, message: '请输入用户名!'}]}
|
||||||
>
|
>
|
||||||
<Input placeholder="用户名" size="large"/>
|
<Input
|
||||||
|
placeholder="用户名"
|
||||||
|
className={styles.input}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="password"
|
name="password"
|
||||||
rules={[{required: true, message: '请输入密码!'}]}
|
rules={[{required: true, message: '请输入密码!'}]}
|
||||||
>
|
>
|
||||||
<Input.Password placeholder="密码" size="large"/>
|
<Input.Password
|
||||||
|
placeholder="密码"
|
||||||
|
className={styles.input}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Button type="primary" htmlType="submit" block size="large" loading={loading}>
|
<Button
|
||||||
|
type="primary"
|
||||||
|
htmlType="submit"
|
||||||
|
block
|
||||||
|
loading={loading}
|
||||||
|
className={styles.loginButton}
|
||||||
|
>
|
||||||
登录
|
登录
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
34
frontend/src/pages/Login/service.ts
Normal file
34
frontend/src/pages/Login/service.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import type { LoginRequest, LoginResponse } from './types';
|
||||||
|
import type { TenantResponse } from '../System/Tenant/types';
|
||||||
|
import type { MenuResponse } from '../System/Menu/types';
|
||||||
|
|
||||||
|
export const login = async (data: LoginRequest): Promise<LoginResponse> => {
|
||||||
|
return request.post('/api/v1/user/login', data, {
|
||||||
|
errorMessage: '登录失败,请检查用户名和密码'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const logout = async (): Promise<void> => {
|
||||||
|
return request.post('/api/v1/user/logout', null, {
|
||||||
|
errorMessage: '退出登录失败,请稍后重试'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getCurrentUser = async (): Promise<LoginResponse> => {
|
||||||
|
return request.get('/api/v1/user/current', {
|
||||||
|
errorMessage: '获取用户信息失败,请重新登录'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getUserMenus = async (): Promise<MenuResponse[]> => {
|
||||||
|
return request.get('/api/v1/user/menus', {
|
||||||
|
errorMessage: '获取菜单失败,请刷新页面重试'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTenantList = async (): Promise<TenantResponse[]> => {
|
||||||
|
return request.get('/api/v1/tenant/list', {
|
||||||
|
errorMessage: '获取租户列表失败,请刷新重试'
|
||||||
|
});
|
||||||
|
};
|
||||||
14
frontend/src/pages/Login/types.ts
Normal file
14
frontend/src/pages/Login/types.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export interface LoginRequest {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
tenantId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginResponse {
|
||||||
|
id: number;
|
||||||
|
username: string;
|
||||||
|
nickname?: string;
|
||||||
|
email?: string;
|
||||||
|
phone?: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
2
frontend/src/pages/Login/types/index.ts
Normal file
2
frontend/src/pages/Login/types/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './request';
|
||||||
|
export * from './response';
|
||||||
5
frontend/src/pages/Login/types/request.ts
Normal file
5
frontend/src/pages/Login/types/request.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export interface LoginRequest {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
tenantId?: string;
|
||||||
|
}
|
||||||
8
frontend/src/pages/Login/types/response.ts
Normal file
8
frontend/src/pages/Login/types/response.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface LoginResponse {
|
||||||
|
id: number;
|
||||||
|
username: string;
|
||||||
|
nickname?: string;
|
||||||
|
email?: string;
|
||||||
|
phone?: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
@ -1,24 +1,33 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type { DepartmentDTO } from './types';
|
import type { DepartmentResponse, DepartmentRequest, DepartmentQuery } from './types';
|
||||||
|
|
||||||
export const getDepartmentTree = async (): Promise<DepartmentDTO[]> => {
|
export const getDepartments = async (params?: DepartmentQuery) => {
|
||||||
return request.get('/api/system/departments/tree');
|
return request.get('/api/v1/department', {
|
||||||
|
params,
|
||||||
|
errorMessage: '获取部门列表失败,请刷新重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createDepartment = async (data: Partial<DepartmentDTO>): Promise<DepartmentDTO> => {
|
export const createDepartment = async (data: DepartmentRequest) => {
|
||||||
return request.post('/api/system/departments', data);
|
return request.post('/api/v1/department', data, {
|
||||||
|
errorMessage: '创建部门失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateDepartment = async (id: number, data: Partial<DepartmentDTO>): Promise<DepartmentDTO> => {
|
export const updateDepartment = async (id: number, data: DepartmentRequest) => {
|
||||||
return request.put(`/api/system/departments/${id}`, data);
|
return request.put(`/api/v1/department/${id}`, data, {
|
||||||
|
errorMessage: '更新部门失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteDepartment = async (id: number): Promise<void> => {
|
export const deleteDepartment = async (id: number) => {
|
||||||
return request.delete(`/api/system/departments/${id}`);
|
return request.delete(`/api/v1/department/${id}`, {
|
||||||
|
errorMessage: '删除部门失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getNextSort = async (parentId?: number): Promise<number> => {
|
export const getDepartmentTree = async () => {
|
||||||
return request.get('/api/system/departments/next-sort', {
|
return request.get('/api/v1/department/tree', {
|
||||||
params: { parentId }
|
errorMessage: '获取部门树失败,请刷新重试'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
7
frontend/src/pages/System/Department/types/query.ts
Normal file
7
frontend/src/pages/System/Department/types/query.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { BaseQuery } from '@/types/base/query';
|
||||||
|
|
||||||
|
export interface DepartmentQuery extends BaseQuery {
|
||||||
|
name?: string;
|
||||||
|
code?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
9
frontend/src/pages/System/Department/types/request.ts
Normal file
9
frontend/src/pages/System/Department/types/request.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { BaseRequest } from '@/types/base/request';
|
||||||
|
|
||||||
|
export interface DepartmentRequest extends BaseRequest {
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
parentId?: number;
|
||||||
|
sort?: number;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
10
frontend/src/pages/System/Department/types/response.ts
Normal file
10
frontend/src/pages/System/Department/types/response.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { BaseResponse } from '@/types/base/response';
|
||||||
|
|
||||||
|
export interface DepartmentResponse extends BaseResponse {
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
parentId?: number;
|
||||||
|
sort: number;
|
||||||
|
description?: string;
|
||||||
|
children?: DepartmentResponse[];
|
||||||
|
}
|
||||||
@ -1,22 +1,33 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type { MenuDTO, MenuQuery } from './types';
|
import type { MenuResponse, MenuRequest, MenuQuery } from './types';
|
||||||
|
|
||||||
export const getMenuTree = async (): Promise<MenuDTO[]> => {
|
export const getMenus = async (params?: MenuQuery) => {
|
||||||
return request.get('/api/system/menus/tree');
|
return request.get('/api/v1/menu', {
|
||||||
|
params,
|
||||||
|
errorMessage: '获取菜单列表失败,请刷新重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getMenuTreeWithoutButtons = async (): Promise<MenuDTO[]> => {
|
export const createMenu = async (data: MenuRequest) => {
|
||||||
return request.get('/api/system/menus/tree/menu');
|
return request.post('/api/v1/menu', data, {
|
||||||
|
errorMessage: '创建菜单失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createMenu = async (data: Partial<MenuDTO>): Promise<MenuDTO> => {
|
export const updateMenu = async (id: number, data: MenuRequest) => {
|
||||||
return request.post('/api/system/menus', data);
|
return request.put(`/api/v1/menu/${id}`, data, {
|
||||||
|
errorMessage: '更新菜单失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateMenu = async (id: number, data: Partial<MenuDTO>): Promise<MenuDTO> => {
|
export const deleteMenu = async (id: number) => {
|
||||||
return request.put(`/api/system/menus/${id}`, data);
|
return request.delete(`/api/v1/menu/${id}`, {
|
||||||
|
errorMessage: '删除菜单失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteMenu = async (id: number): Promise<void> => {
|
export const getMenuTree = async () => {
|
||||||
return request.delete(`/api/system/menus/${id}`);
|
return request.get('/api/v1/menu/tree', {
|
||||||
|
errorMessage: '获取菜单树失败,请刷新重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
@ -1,40 +1,31 @@
|
|||||||
export interface MenuDTO {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
permission?: string;
|
|
||||||
path?: string;
|
|
||||||
component?: string;
|
|
||||||
type: MenuTypeEnum;
|
|
||||||
icon?: string;
|
|
||||||
parentId?: number;
|
|
||||||
sort: number;
|
|
||||||
hidden: boolean;
|
|
||||||
enabled: boolean;
|
|
||||||
children?: MenuDTO[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MenuQuery {
|
export interface MenuQuery {
|
||||||
name?: string;
|
name?: string;
|
||||||
permission?: string;
|
path?: string;
|
||||||
type?: MenuTypeEnum;
|
enabled?: boolean;
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
sortField?: string;
|
||||||
|
sortOrder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MenuRequest {
|
||||||
|
name: string;
|
||||||
|
path?: string;
|
||||||
|
icon?: string;
|
||||||
parentId?: number;
|
parentId?: number;
|
||||||
|
sort?: number;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MenuTypeEnum {
|
export interface MenuResponse {
|
||||||
DIRECTORY = 0,
|
id: number;
|
||||||
MENU = 1,
|
name: string;
|
||||||
BUTTON = 2
|
path?: string;
|
||||||
}
|
icon?: string;
|
||||||
|
parentId?: number;
|
||||||
export const MenuTypeNames: Record<MenuTypeEnum, string> = {
|
sort: number;
|
||||||
[MenuTypeEnum.DIRECTORY]: '目录',
|
enabled: boolean;
|
||||||
[MenuTypeEnum.MENU]: '菜单',
|
children?: MenuResponse[];
|
||||||
[MenuTypeEnum.BUTTON]: '按钮'
|
createTime: string;
|
||||||
};
|
updateTime: string;
|
||||||
|
}
|
||||||
export const MenuTypeOptions = [
|
|
||||||
{ label: '目录', value: MenuTypeEnum.DIRECTORY },
|
|
||||||
{ label: '菜单', value: MenuTypeEnum.MENU },
|
|
||||||
{ label: '按钮', value: MenuTypeEnum.BUTTON }
|
|
||||||
];
|
|
||||||
3
frontend/src/pages/System/Menu/types/index.ts
Normal file
3
frontend/src/pages/System/Menu/types/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './query';
|
||||||
|
export * from './request';
|
||||||
|
export * from './response';
|
||||||
7
frontend/src/pages/System/Menu/types/query.ts
Normal file
7
frontend/src/pages/System/Menu/types/query.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { BaseQuery } from '@/types/base/query';
|
||||||
|
|
||||||
|
export interface MenuQuery extends BaseQuery {
|
||||||
|
name?: string;
|
||||||
|
path?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
9
frontend/src/pages/System/Menu/types/request.ts
Normal file
9
frontend/src/pages/System/Menu/types/request.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { BaseRequest } from '@/types/base/request';
|
||||||
|
|
||||||
|
export interface MenuRequest extends BaseRequest {
|
||||||
|
name: string;
|
||||||
|
path?: string;
|
||||||
|
icon?: string;
|
||||||
|
parentId?: number;
|
||||||
|
sort?: number;
|
||||||
|
}
|
||||||
10
frontend/src/pages/System/Menu/types/response.ts
Normal file
10
frontend/src/pages/System/Menu/types/response.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { BaseResponse } from '@/types/base/response';
|
||||||
|
|
||||||
|
export interface MenuResponse extends BaseResponse {
|
||||||
|
name: string;
|
||||||
|
path?: string;
|
||||||
|
icon?: string;
|
||||||
|
parentId?: number;
|
||||||
|
sort: number;
|
||||||
|
children?: MenuResponse[];
|
||||||
|
}
|
||||||
@ -1,26 +1,39 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type { RoleDTO } from './types';
|
import type { RoleResponse, RoleRequest, RoleQuery } from './types';
|
||||||
|
|
||||||
export const getRoles = async (): Promise<RoleDTO[]> => {
|
export const getRoles = async (params?: RoleQuery) => {
|
||||||
return request.get('/api/system/roles');
|
return request.get('/api/v1/role', {
|
||||||
|
params,
|
||||||
|
errorMessage: '获取角色列表失败,请刷新重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createRole = async (data: Partial<RoleDTO>): Promise<RoleDTO> => {
|
export const createRole = async (data: RoleRequest) => {
|
||||||
return request.post('/api/system/roles', data);
|
return request.post('/api/v1/role', data, {
|
||||||
|
errorMessage: '创建角色失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateRole = async (id: number, data: Partial<RoleDTO>): Promise<RoleDTO> => {
|
export const updateRole = async (id: number, data: RoleRequest) => {
|
||||||
return request.put(`/api/system/roles/${id}`, data);
|
return request.put(`/api/v1/role/${id}`, data, {
|
||||||
|
errorMessage: '更新角色失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteRole = async (id: number): Promise<void> => {
|
export const deleteRole = async (id: number) => {
|
||||||
return request.delete(`/api/system/roles/${id}`);
|
return request.delete(`/api/v1/role/${id}`, {
|
||||||
|
errorMessage: '删除角色失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRoleMenuIds = async (roleId: number): Promise<number[]> => {
|
export const assignMenus = async (roleId: number, menuIds: number[]) => {
|
||||||
return request.get(`/api/system/roles/${roleId}/menus`);
|
return request.post(`/api/v1/role/${roleId}/menus`, menuIds, {
|
||||||
|
errorMessage: '分配菜单失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateRoleMenus = async (roleId: number, menuIds: number[]): Promise<void> => {
|
export const getRoleMenus = async (roleId: number) => {
|
||||||
return request.put(`/api/system/roles/${roleId}/menus`, menuIds);
|
return request.get(`/api/v1/role/${roleId}/menus`, {
|
||||||
|
errorMessage: '获取角色菜单失败,请刷新重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
3
frontend/src/pages/System/Role/types/index.ts
Normal file
3
frontend/src/pages/System/Role/types/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './query';
|
||||||
|
export * from './request';
|
||||||
|
export * from './response';
|
||||||
7
frontend/src/pages/System/Role/types/query.ts
Normal file
7
frontend/src/pages/System/Role/types/query.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { BaseQuery } from '@/types/base/query';
|
||||||
|
|
||||||
|
export interface RoleQuery extends BaseQuery {
|
||||||
|
name?: string;
|
||||||
|
code?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
7
frontend/src/pages/System/Role/types/request.ts
Normal file
7
frontend/src/pages/System/Role/types/request.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { BaseRequest } from '@/types/base/request';
|
||||||
|
|
||||||
|
export interface RoleRequest extends BaseRequest {
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
7
frontend/src/pages/System/Role/types/response.ts
Normal file
7
frontend/src/pages/System/Role/types/response.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { BaseResponse } from '@/types/base/response';
|
||||||
|
|
||||||
|
export interface RoleResponse extends BaseResponse {
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
@ -1,37 +1,33 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type {TenantDTO, TenantQuery} from './types';
|
import type { TenantResponse, TenantRequest, 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('/api/v1/tenant', {
|
||||||
|
params,
|
||||||
|
errorMessage: '获取租户列表失败,请刷新重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取所有启用的租户(用于登录页面)
|
export const createTenant = async (data: TenantRequest) => {
|
||||||
export const getEnabledTenants = async () => {
|
return request.post('/api/v1/tenant', data, {
|
||||||
return request.get<TenantDTO[]>('/api/v1/tenant/list');
|
errorMessage: '创建租户失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 创建租户
|
export const updateTenant = async (id: number, data: TenantRequest) => {
|
||||||
export const createTenant = async (data: Partial<TenantDTO>) => {
|
return request.put(`/api/v1/tenant/${id}`, data, {
|
||||||
return request.post<TenantDTO>('/api/system/tenants', data);
|
errorMessage: '更新租户失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新租户
|
|
||||||
export const updateTenant = async (id: number, data: Partial<TenantDTO>) => {
|
|
||||||
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/v1/tenant/${id}`, {
|
||||||
|
errorMessage: '删除租户失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 检查租户编码是否存在
|
export const getEnabledTenants = async () => {
|
||||||
export const checkTenantCode = async (code: string) => {
|
return request.get('/api/v1/tenant/enabled', {
|
||||||
return request.get<boolean>(`/api/system/tenants/check-code`, {params: {code}});
|
errorMessage: '获取可用租户列表失败,请刷新重试'
|
||||||
};
|
});
|
||||||
|
|
||||||
// 检查租户名称是否存在
|
|
||||||
export const checkTenantName = async (name: string) => {
|
|
||||||
return request.get<boolean>(`/api/system/tenants/check-name`, {params: {name}});
|
|
||||||
};
|
};
|
||||||
@ -1,19 +1,32 @@
|
|||||||
export interface TenantDTO {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
code: string;
|
|
||||||
contactName?: string;
|
|
||||||
contactPhone?: string;
|
|
||||||
email?: string;
|
|
||||||
address?: string;
|
|
||||||
enabled: boolean;
|
|
||||||
createTime?: string;
|
|
||||||
updateTime?: string;
|
|
||||||
version?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TenantQuery {
|
export interface TenantQuery {
|
||||||
name?: string;
|
name?: string;
|
||||||
code?: string;
|
code?: string;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
sortField?: string;
|
||||||
|
sortOrder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TenantRequest {
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
address?: string;
|
||||||
|
contactName?: string;
|
||||||
|
contactPhone?: string;
|
||||||
|
email?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TenantResponse {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
address?: string;
|
||||||
|
contactName?: string;
|
||||||
|
contactPhone?: string;
|
||||||
|
email?: string;
|
||||||
|
enabled: boolean;
|
||||||
|
createTime: string;
|
||||||
|
updateTime: string;
|
||||||
}
|
}
|
||||||
3
frontend/src/pages/System/Tenant/types/index.ts
Normal file
3
frontend/src/pages/System/Tenant/types/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './query';
|
||||||
|
export * from './request';
|
||||||
|
export * from './response';
|
||||||
7
frontend/src/pages/System/Tenant/types/query.ts
Normal file
7
frontend/src/pages/System/Tenant/types/query.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { BaseQuery } from '@/types/base/query';
|
||||||
|
|
||||||
|
export interface TenantQuery extends BaseQuery {
|
||||||
|
name?: string;
|
||||||
|
code?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
10
frontend/src/pages/System/Tenant/types/request.ts
Normal file
10
frontend/src/pages/System/Tenant/types/request.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { BaseRequest } from '@/types/base/request';
|
||||||
|
|
||||||
|
export interface TenantRequest extends BaseRequest {
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
address?: string;
|
||||||
|
contactName?: string;
|
||||||
|
contactPhone?: string;
|
||||||
|
email?: string;
|
||||||
|
}
|
||||||
10
frontend/src/pages/System/Tenant/types/response.ts
Normal file
10
frontend/src/pages/System/Tenant/types/response.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { BaseResponse } from '@/types/base/response';
|
||||||
|
|
||||||
|
export interface TenantResponse extends BaseResponse {
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
address?: string;
|
||||||
|
contactName?: string;
|
||||||
|
contactPhone?: string;
|
||||||
|
email?: string;
|
||||||
|
}
|
||||||
@ -1,30 +1,57 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type { UserDTO, UserQuery } from './types';
|
import type { UserResponse, UserRequest, UserQuery } from './types';
|
||||||
|
|
||||||
export const getUsers = async (params: UserQuery): Promise<UserDTO[]> => {
|
export const getUsers = async (params?: UserQuery) => {
|
||||||
return request.get('/api/system/users', { params });
|
return request.get('/api/v1/user', {
|
||||||
|
params,
|
||||||
|
errorMessage: '获取用户列表失败,请刷新重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createUser = async (data: Partial<UserDTO>): Promise<UserDTO> => {
|
export const createUser = async (data: UserRequest) => {
|
||||||
return request.post('/api/system/users', data);
|
return request.post('/api/v1/user', data, {
|
||||||
|
errorMessage: '创建用户失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateUser = async (id: number, data: Partial<UserDTO>): Promise<UserDTO> => {
|
export const updateUser = async (id: number, data: UserRequest) => {
|
||||||
return request.put(`/api/system/users/${id}`, data);
|
return request.put(`/api/v1/user/${id}`, data, {
|
||||||
|
errorMessage: '更新用户信息失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteUser = async (id: number): Promise<void> => {
|
export const deleteUser = async (id: number) => {
|
||||||
return request.delete(`/api/system/users/${id}`);
|
return request.delete(`/api/v1/user/${id}`, {
|
||||||
|
errorMessage: '删除用户失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const resetPassword = async (id: number, password: string): Promise<void> => {
|
export const assignRoles = async (userId: number, roleIds: number[]) => {
|
||||||
return request.post(`/api/system/users/${id}/reset-password`, { password });
|
return request.post(`/api/v1/user/${userId}/roles`, roleIds, {
|
||||||
|
errorMessage: '分配角色失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserRoleIds = async (userId: number): Promise<number[]> => {
|
export const resetPassword = async (id: number) => {
|
||||||
return request.get(`/api/system/users/${userId}/roles`);
|
return request.post(`/api/v1/user/${id}/reset-password`, null, {
|
||||||
|
errorMessage: '重置密码失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateUserRoles = async (userId: number, roleIds: number[]): Promise<void> => {
|
export const updatePassword = async (id: number, data: { oldPassword: string; newPassword: string }) => {
|
||||||
return request.put(`/api/system/users/${userId}/roles`, roleIds);
|
return request.post(`/api/v1/user/${id}/update-password`, data, {
|
||||||
|
errorMessage: '修改密码失败,请稍后重试'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const enableUser = async (id: number) => {
|
||||||
|
return request.post(`/api/v1/user/${id}/enable`, null, {
|
||||||
|
errorMessage: '启用用户失败,请稍后重试'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const disableUser = async (id: number) => {
|
||||||
|
return request.post(`/api/v1/user/${id}/disable`, null, {
|
||||||
|
errorMessage: '禁用用户失败,请稍后重试'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
@ -1,21 +1,30 @@
|
|||||||
export interface UserDTO {
|
export interface UserQuery {
|
||||||
|
username?: string;
|
||||||
|
nickname?: string;
|
||||||
|
email?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
sortField?: string;
|
||||||
|
sortOrder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserRequest {
|
||||||
|
username: string;
|
||||||
|
nickname?: string;
|
||||||
|
email?: string;
|
||||||
|
phone?: string;
|
||||||
|
password?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserResponse {
|
||||||
id: number;
|
id: number;
|
||||||
username: string;
|
username: string;
|
||||||
nickname?: string;
|
nickname?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
deptId?: number;
|
createTime: string;
|
||||||
deptName?: string;
|
updateTime: string;
|
||||||
version?: number;
|
|
||||||
createTime?: string;
|
|
||||||
updateTime?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserQuery {
|
|
||||||
page: number;
|
|
||||||
size: number;
|
|
||||||
keyword?: string;
|
|
||||||
deptId?: number;
|
|
||||||
enabled?: boolean;
|
|
||||||
}
|
}
|
||||||
3
frontend/src/pages/System/User/types/index.ts
Normal file
3
frontend/src/pages/System/User/types/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './query';
|
||||||
|
export * from './request';
|
||||||
|
export * from './response';
|
||||||
8
frontend/src/pages/System/User/types/query.ts
Normal file
8
frontend/src/pages/System/User/types/query.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { BaseQuery } from '@/types/base/query';
|
||||||
|
|
||||||
|
export interface UserQuery extends BaseQuery {
|
||||||
|
username?: string;
|
||||||
|
nickname?: string;
|
||||||
|
email?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
9
frontend/src/pages/System/User/types/request.ts
Normal file
9
frontend/src/pages/System/User/types/request.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { BaseRequest } from '@/types/base/request';
|
||||||
|
|
||||||
|
export interface UserRequest extends BaseRequest {
|
||||||
|
username: string;
|
||||||
|
nickname?: string;
|
||||||
|
email?: string;
|
||||||
|
phone?: string;
|
||||||
|
password?: string;
|
||||||
|
}
|
||||||
8
frontend/src/pages/System/User/types/response.ts
Normal file
8
frontend/src/pages/System/User/types/response.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { BaseResponse } from '@/types/base/response';
|
||||||
|
|
||||||
|
export interface UserResponse extends BaseResponse {
|
||||||
|
username: string;
|
||||||
|
nickname?: string;
|
||||||
|
email?: string;
|
||||||
|
phone?: string;
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
import type { MenuDTO } from '@/pages/System/Menu/types';
|
import type { MenuResponse } from '@/pages/System/Menu/types';
|
||||||
|
|
||||||
interface UserInfo {
|
interface UserInfo {
|
||||||
id: number;
|
id: number;
|
||||||
@ -12,12 +12,12 @@ interface UserInfo {
|
|||||||
interface UserState {
|
interface UserState {
|
||||||
token: string | null;
|
token: string | null;
|
||||||
userInfo: UserInfo | null;
|
userInfo: UserInfo | null;
|
||||||
menus: MenuDTO[];
|
menus: MenuResponse[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: UserState = {
|
const initialState: UserState = {
|
||||||
token: localStorage.getItem('token'),
|
token: localStorage.getItem('token'),
|
||||||
userInfo: localStorage.getItem('userInfo') ? JSON.parse(localStorage.getItem('userInfo')!) : null,
|
userInfo: null,
|
||||||
menus: []
|
menus: []
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ const userSlice = createSlice({
|
|||||||
state.userInfo = action.payload;
|
state.userInfo = action.payload;
|
||||||
localStorage.setItem('userInfo', JSON.stringify(action.payload));
|
localStorage.setItem('userInfo', JSON.stringify(action.payload));
|
||||||
},
|
},
|
||||||
setMenus: (state, action: PayloadAction<MenuDTO[]>) => {
|
setMenus: (state, action: PayloadAction<MenuResponse[]>) => {
|
||||||
state.menus = action.payload;
|
state.menus = action.payload;
|
||||||
},
|
},
|
||||||
logout: (state) => {
|
logout: (state) => {
|
||||||
@ -41,6 +41,7 @@ const userSlice = createSlice({
|
|||||||
state.userInfo = null;
|
state.userInfo = null;
|
||||||
state.menus = [];
|
state.menus = [];
|
||||||
localStorage.removeItem('token');
|
localStorage.removeItem('token');
|
||||||
|
localStorage.removeItem('tenantId');
|
||||||
localStorage.removeItem('userInfo');
|
localStorage.removeItem('userInfo');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
frontend/src/types/base/query.ts
Normal file
6
frontend/src/types/base/query.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export interface BaseQuery {
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
sortField?: string;
|
||||||
|
sortOrder?: string;
|
||||||
|
}
|
||||||
3
frontend/src/types/base/request.ts
Normal file
3
frontend/src/types/base/request.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export interface BaseRequest {
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
9
frontend/src/types/base/response.ts
Normal file
9
frontend/src/types/base/response.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export interface BaseResponse {
|
||||||
|
id: number;
|
||||||
|
createTime: string;
|
||||||
|
updateTime: string;
|
||||||
|
createBy?: string;
|
||||||
|
updateBy?: string;
|
||||||
|
enabled: boolean;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
@ -13,7 +13,11 @@ export interface UserInfo {
|
|||||||
|
|
||||||
export interface LoginResult {
|
export interface LoginResult {
|
||||||
token: string;
|
token: string;
|
||||||
userInfo: UserInfo;
|
id: number;
|
||||||
|
username: string;
|
||||||
|
nickname: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserState {
|
export interface UserState {
|
||||||
|
|||||||
@ -1,13 +1,19 @@
|
|||||||
import axios, {AxiosResponse} from 'axios';
|
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
import {message} from 'antd';
|
import { message } from 'antd';
|
||||||
|
|
||||||
export interface ApiResponse<T> {
|
export interface ApiResponse<T = any> {
|
||||||
code: number;
|
code: number;
|
||||||
message: string;
|
message: string;
|
||||||
data: T;
|
data: T;
|
||||||
success: boolean;
|
success: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RequestOptions extends AxiosRequestConfig {
|
||||||
|
skipErrorHandler?: boolean;
|
||||||
|
hideErrorMessage?: boolean;
|
||||||
|
errorMessage?: string;
|
||||||
|
}
|
||||||
|
|
||||||
const request = axios.create({
|
const request = axios.create({
|
||||||
baseURL: '',
|
baseURL: '',
|
||||||
timeout: 300000,
|
timeout: 300000,
|
||||||
@ -21,11 +27,13 @@ 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) {
|
if (tenantId) {
|
||||||
config.headers['X-Devops-Tenant-Id'] = tenantId;
|
config.headers['X-Tenant-Id'] = tenantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
@ -38,16 +46,48 @@ request.interceptors.request.use(
|
|||||||
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) {
|
const config = response.config as RequestOptions;
|
||||||
message.error(res.message || '请求失败');
|
|
||||||
return Promise.reject(new Error(res.message || '请求失败'));
|
if (res.success) {
|
||||||
|
return res.data;
|
||||||
}
|
}
|
||||||
return Promise.resolve(res.data);
|
|
||||||
|
if (!config.hideErrorMessage) {
|
||||||
|
message.error(res.message || '操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
message.error(error.response?.data?.message || '请求失败');
|
const config = error.config as RequestOptions;
|
||||||
|
const response = error.response;
|
||||||
|
|
||||||
|
if (!config.hideErrorMessage) {
|
||||||
|
if (response?.data?.message && response?.status !== 500) {
|
||||||
|
message.error(response.data.message);
|
||||||
|
} else {
|
||||||
|
message.error(config.errorMessage || '系统错误,请稍后重试');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default request;
|
const extendedRequest = {
|
||||||
|
get: <T = any>(url: string, config?: RequestOptions) =>
|
||||||
|
request.get<any, T>(url, config),
|
||||||
|
|
||||||
|
post: <T = any>(url: string, data?: any, config?: RequestOptions) =>
|
||||||
|
request.post<any, T>(url, data, config),
|
||||||
|
|
||||||
|
put: <T = any>(url: string, data?: any, config?: RequestOptions) =>
|
||||||
|
request.put<any, T>(url, data, config),
|
||||||
|
|
||||||
|
delete: <T = any>(url: string, config?: RequestOptions) =>
|
||||||
|
request.delete<any, T>(url, config),
|
||||||
|
|
||||||
|
request: request
|
||||||
|
};
|
||||||
|
|
||||||
|
export default extendedRequest;
|
||||||
23
frontend/tsconfig.json
Normal file
23
frontend/tsconfig.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
}
|
||||||
@ -10,12 +10,11 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: 3000,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://localhost:8080',
|
target: 'http://localhost:8080',
|
||||||
changeOrigin: true,
|
changeOrigin: true
|
||||||
secure: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user