可正常启用

This commit is contained in:
戚辰先生 2024-12-01 13:01:31 +08:00
parent fa31848e9f
commit 76eeeb4b8e
6 changed files with 145 additions and 296 deletions

View File

@ -1,5 +1,5 @@
import {useState, useCallback, useEffect} from 'react'; import {useState, useCallback, useEffect} from 'react';
import {Modal} from 'antd'; import {message, Modal} from 'antd';
import type {TableState} from '@/types/table'; import type {TableState} from '@/types/table';
import {createInitialState} from '@/utils/table'; import {createInitialState} from '@/utils/table';
import request from '@/utils/request'; import request from '@/utils/request';
@ -38,8 +38,7 @@ export function useTableData<T extends { id: number }, P extends SortParams>({
...params, ...params,
pageNum: state.pagination.current, pageNum: state.pagination.current,
pageSize: state.pagination.pageSize, pageSize: state.pagination.pageSize,
sortOrder: params?.sortOrder === 'ascend' ? 'asc' : sortOrder: params?.sortOrder === 'ascend' ? 'asc' : params?.sortOrder === 'descend' ? 'desc' : undefined
params?.sortOrder === 'descend' ? 'desc' : undefined
} }
}); });
@ -60,10 +59,9 @@ export function useTableData<T extends { id: number }, P extends SortParams>({
// CRUD操作 // CRUD操作
const handleCreate = useCallback(async (data: Partial<T>) => { const handleCreate = useCallback(async (data: Partial<T>) => {
try { try {
await request.post<T>(service.baseUrl, data, { await request.post<T>(service.baseUrl, data);
successMessage: '创建成功' message.success("创建成功")
}); await loadData();
loadData();
return true; return true;
} catch (error) { } catch (error) {
return false; return false;
@ -72,10 +70,9 @@ export function useTableData<T extends { id: number }, P extends SortParams>({
const handleUpdate = useCallback(async (id: number, data: Partial<T>) => { const handleUpdate = useCallback(async (id: number, data: Partial<T>) => {
try { try {
await request.put<T>(`${service.baseUrl}/${id}`, data, { await request.put<T>(`${service.baseUrl}/${id}`, data);
successMessage: '更新成功' message.success("更新成功")
}); await loadData();
loadData();
return true; return true;
} catch (error) { } catch (error) {
return false; return false;
@ -92,9 +89,8 @@ export function useTableData<T extends { id: number }, P extends SortParams>({
cancelText: '取消', cancelText: '取消',
onOk: async () => { onOk: async () => {
try { try {
await request.delete(`${service.baseUrl}/${id}`, { await request.delete(`${service.baseUrl}/${id}`);
successMessage: '删除成功' message.success("删除成功")
});
loadData(); loadData();
resolve(true); resolve(true);
} catch (error) { } catch (error) {

View File

@ -51,19 +51,10 @@ const BasicLayout: React.FC = () => {
const initializeUserData = async () => { const initializeUserData = async () => {
// try { // try {
setLoading(true); setLoading(true);
const menuData = await getCurrentUserMenus().then((response) => { const menuData = await getCurrentUserMenus();
console.log(response) console.log(menuData)
dispatch(setMenus(response)); dispatch(setMenus(menuData));
setLoading(false); setLoading(false);
})
// } catch (error) {
// console.log(error);
// message.error('初始化用户数据失败');
// dispatch(logout());
// navigate('/login', {replace: true});
// } finally {
// setLoading(false);
// }
}; };
if (!userInfo) { if (!userInfo) {

View File

@ -6,8 +6,7 @@ import { useTableData } from '@/hooks/useTableData';
import type {FixedType} from 'rc-table/lib/interface'; import type {FixedType} from 'rc-table/lib/interface';
import type {TablePaginationConfig} from 'antd/es/table'; import type {TablePaginationConfig} from 'antd/es/table';
import type {FilterValue, SorterResult} from 'antd/es/table/interface'; import type {FilterValue, SorterResult} from 'antd/es/table/interface';
import { assignTags, getAllTags } from './service'; import {assignTags, createRoleTag, deleteRoleTag, getAllTags, updateRoleTag} from './service';
import request from '@/utils/request';
const RolePage: React.FC = () => { const RolePage: React.FC = () => {
const { const {
@ -42,9 +41,15 @@ const RolePage: React.FC = () => {
const [tagForm] = Form.useForm(); const [tagForm] = Form.useForm();
useEffect(() => { useEffect(() => {
getAllTags().then(response => { const fetchTags = async () => { // 定义一个异步函数
setAllTags(response); try {
}); const tags = await getAllTags(); // 在这里使用 await
setAllTags(tags);
} catch (error) {
console.error("获取标签失败", error); // 处理错误
}
};
fetchTags(); // 调用异步函数
}, []); }, []);
const handleAdd = () => { const handleAdd = () => {
@ -110,23 +115,18 @@ const RolePage: React.FC = () => {
const handleTagManageSubmit = async () => { const handleTagManageSubmit = async () => {
try { try {
const values = await tagForm.validateFields(); const values = await tagForm.validateFields();
const tagService = { if (values.id) {
baseUrl: '/api/v1/role-tag' await updateRoleTag(values.id, {
};
const formData = {
...values, ...values,
color: values.color.toHexString?.() || values.color color: values.color.toHexString?.() || values.color
};
if (values.id) {
await request.put(`${tagService.baseUrl}/${values.id}`, formData, {
successMessage: '更新标签成功'
}); });
message.success("更新标签成功")
} else { } else {
await request.post(tagService.baseUrl, formData, { await createRoleTag({
successMessage: '创建标签成功' ...values,
color: values.color.toHexString?.() || values.color
}); });
message.success("标签添加成功")
} }
setTagManageVisible(false); setTagManageVisible(false);
const tags = await getAllTags(); const tags = await getAllTags();
@ -137,16 +137,25 @@ const RolePage: React.FC = () => {
}; };
const handleTagDelete = async (id: number) => { const handleTagDelete = async (id: number) => {
Modal.confirm({
title: '确认删除',
content: '确定要删除该记录吗?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: async () => {
try { try {
await request.delete(`/api/v1/role-tag/${id}`, { await deleteRoleTag(id);
successMessage: '删除标签成功' message.success("删除成功");
});
// 刷新标签列表 // 刷新标签列表
const tags = await getAllTags(); const tags = await getAllTags();
setAllTags(tags); setAllTags(tags);
} catch (error) { } catch (error) {
console.error('删除标签失败:', error); console.error("角色标签删除失败", error);
} }
},
// onCancel: () => resolve(false)
});
}; };
const columns = [ const columns = [

View File

@ -1,52 +1,31 @@
import request from '@/utils/request'; import request from '@/utils/request';
import type {Page} from '@/types/base/page'; import type {Page} from '@/types/base/page';
import type { RoleResponse, RoleRequest, RoleQuery, RoleTagResponse } from './types'; import {RoleResponse, RoleRequest, RoleQuery, RoleTagResponse, RoleTagRequest} from './types';
const BASE_URL = '/api/v1/role'; const BASE_URL = '/api/v1/role';
const ROLE_TAG_BASE_URL = '/api/v1/role-tag'
// 获取角色列表(分页) // 获取角色列表(分页)
export const getRoles = (params?: RoleQuery) => export const getRoles = (params?: RoleQuery) => request.get<Page<RoleResponse>>(`${BASE_URL}/page`, {params});
request.get<Page<RoleResponse>>(`${BASE_URL}/page`, {
params
});
// 创建角色 // 创建角色
export const createRole = (data: RoleRequest) => export const createRole = (data: RoleRequest) => request.post<RoleResponse>(BASE_URL, data);
request.post<RoleResponse>(BASE_URL, data, {
successMessage: '创建角色成功'
});
// 更新角色 // 更新角色
export const updateRole = (id: number, data: RoleRequest) => export const updateRole = (id: number, data: RoleRequest) => request.put<RoleResponse>(`${BASE_URL}/${id}`, data);
request.put<RoleResponse>(`${BASE_URL}/${id}`, data, {
successMessage: '更新角色成功'
});
// 删除角色 // 删除角色
export const deleteRole = (id: number) => export const deleteRole = (id: number) => request.delete(`${BASE_URL}/${id}`);
request.delete(`${BASE_URL}/${id}`, {
successMessage: '删除角色成功'
});
export const assignMenus = async (roleId: number, menuIds: number[]) => {
return request.post(`/api/v1/role/${roleId}/menus`, menuIds, {
errorMessage: '分配菜单失败,请稍后重试'
});
};
export const getRoleMenus = async (roleId: number) => {
return request.get(`/api/v1/role/${roleId}/menus`, {
errorMessage: '获取角色菜单失败,请刷新重试'
});
};
// 分配标签 // 分配标签
export const assignTags = (roleId: number, tagIds: number[]) => export const assignTags = (roleId: number, tagIds: number[]) => request.post(`${BASE_URL}/${roleId}/tags`, tagIds);
request.post(`${BASE_URL}/${roleId}/tags`, tagIds, {
successMessage: '分配标签成功'
});
// 获取所有标签 // 获取所有标签
export const getAllTags = () => export const getAllTags = () => request.get<RoleTagResponse[]>(`${ROLE_TAG_BASE_URL}/list`);
request.get<RoleTagResponse[]>('/api/v1/role-tag/list');
export const deleteRoleTag = (id: number) => request.delete(`${ROLE_TAG_BASE_URL}/${id}`);
export const updateRoleTag = (id: number, data: RoleTagRequest) => request.put(`${ROLE_TAG_BASE_URL}/${id}`, data);
export const createRoleTag = (data: RoleRequest) => request.post<RoleResponse>(ROLE_TAG_BASE_URL, data);

View File

@ -1,124 +0,0 @@
import React, { useState } from 'react';
import { Table, Button, Modal, Form, Input, Space, ColorPicker } from 'antd';
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
import type { RoleTagResponse } from './types';
import { useTableData } from '@/hooks/useTableData';
import type { Color } from 'antd/es/color-picker';
const RoleTagPage: React.FC = () => {
const {
list: tags,
loading,
handleCreate,
handleUpdate,
handleDelete
} = useTableData({
service: {
baseUrl: '/api/v1/role-tag'
}
});
const [modalVisible, setModalVisible] = useState(false);
const [editingTag, setEditingTag] = useState<RoleTagResponse | null>(null);
const [form] = Form.useForm();
const columns = [
{
title: '标签名称',
dataIndex: 'name',
key: 'name'
},
{
title: '颜色',
dataIndex: 'color',
key: 'color',
render: (color: string) => (
<div style={{
backgroundColor: color,
width: 20,
height: 20,
borderRadius: 4
}} />
)
},
{
title: '描述',
dataIndex: 'description',
key: 'description'
},
{
title: '操作',
key: 'action',
render: (_: any, record: RoleTagResponse) => (
<Space>
<Button
type="link"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
>
</Button>
<Button
type="link"
danger
icon={<DeleteOutlined />}
onClick={() => handleDelete(record.id)}
>
</Button>
</Space>
)
}
];
return (
<div style={{ padding: '24px' }}>
<div style={{ marginBottom: 16 }}>
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
</Button>
</div>
<Table
loading={loading}
columns={columns}
dataSource={tags}
rowKey="id"
/>
<Modal
title={editingTag ? '编辑标签' : '新增标签'}
open={modalVisible}
onOk={handleSubmit}
onCancel={() => setModalVisible(false)}
>
<Form form={form} layout="vertical">
<Form.Item
name="name"
label="标签名称"
rules={[{ required: true }]}
>
<Input />
</Form.Item>
<Form.Item
name="color"
label="标签颜色"
rules={[{ required: true }]}
>
<ColorPicker />
</Form.Item>
<Form.Item
name="description"
label="描述"
>
<Input.TextArea />
</Form.Item>
</Form>
</Modal>
</div>
);
};
export default RoleTagPage;

View File

@ -9,8 +9,6 @@ export interface Response<T = any> {
} }
export interface RequestOptions extends AxiosRequestConfig { export interface RequestOptions extends AxiosRequestConfig {
successMessage?: string;
errorMessage?: string;
retryCount?: number; retryCount?: number;
retryDelay?: number; retryDelay?: number;
} }
@ -32,6 +30,8 @@ const request = axios.create({
} }
}); });
const defaultErrorMessage = '操作失败';
// 创建请求配置 // 创建请求配置
const createRequestConfig = (options?: Partial<RequestOptions>): RequestOptions => { const createRequestConfig = (options?: Partial<RequestOptions>): RequestOptions => {
return { return {
@ -41,52 +41,51 @@ const createRequestConfig = (options?: Partial<RequestOptions>): RequestOptions
}; };
const responseHandler = (response: AxiosResponse<Response<any>>) => { const responseHandler = (response: AxiosResponse<Response<any>>) => {
const data = response.data; const result = response.data;
const config = response.config as RequestOptions; if (result.success && result.code === 200) {
return result.data;
if (data.success && data.code === 200) {
config.successMessage && message.success(config.successMessage);
return data.data;
} else { } else {
message.error(config.errorMessage || data.message); if (result.message !== undefined) {
return Promise.reject(response); // 隐式返回 Promise message.error(result.message || defaultErrorMessage);
return Promise.reject(response);
}
return Promise.reject(response);
} }
}; };
const statusMessages: Record<number, string> = {
401: '未授权,请重新登录',
403: '拒绝访问',
404: '请求错误,未找到该资源',
500: '服务器错误'
};
const defaultErrorMessage = '服务器异常,请稍后再试!';
const errorHandler = (error: any) => { const errorHandler = (error: any) => {
const config = error.config as RequestOptions;
// 检查是否有响应
if (!error.response) { if (!error.response) {
message.error('网络连接异常,请检查网络'); message.error('网络连接异常,请检查网络');
return Promise.reject(error); return Promise.reject(error);
} }
// 检查是否为取消请求
if (axios.isCancel(error)) { if (axios.isCancel(error)) {
return Promise.reject(error); return Promise.reject(error);
} }
const status = error.response.status; const status = error.response.status;
const msg = statusMessages[status] || defaultErrorMessage; // 获取相应的消息 let errorMessage = '';
switch (status) {
// 显示错误信息 case 401:
message.error(config.errorMessage || msg); errorMessage = '未授权,请重新登录';
break;
return Promise.reject(error); // 拦截错误并返回 case 403:
errorMessage = '拒绝访问';
break;
case 404:
errorMessage = '请求错误,未找到该资源';
break;
case 500:
errorMessage = '服务异常,请稍后再试';
break;
default:
errorMessage = '服务器异常,请稍后再试!';
}
message.error(errorMessage);
return Promise.reject(error);
}; };
request.interceptors.request.use( request.interceptors.request.use(
(config) => { (config) => {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
@ -101,9 +100,8 @@ request.interceptors.request.use(
request.interceptors.response.use(responseHandler, errorHandler); request.interceptors.response.use(responseHandler, errorHandler);
const http = { const http = {
get: <T = any>(url: string, config?: RequestOptions) => { get: <T = any>(url: string, config?: RequestOptions) =>
return request.get<any, T>(url, createRequestConfig(config)); request.get<any, T>(url, createRequestConfig(config)),
},
post: <T = any>(url: string, data?: any, config?: RequestOptions) => post: <T = any>(url: string, data?: any, config?: RequestOptions) =>
request.post<any, Response<T>>(url, data, createRequestConfig(config)), request.post<any, Response<T>>(url, data, createRequestConfig(config)),