diff --git a/frontend/src/pages/System/Role/index.tsx b/frontend/src/pages/System/Role/index.tsx index 16fddecf..b9a6042a 100644 --- a/frontend/src/pages/System/Role/index.tsx +++ b/frontend/src/pages/System/Role/index.tsx @@ -1,12 +1,13 @@ import React, { useState, useEffect } from 'react'; -import { Table, Button, Modal, Form, Input, Space, message, InputNumber, Switch, Select, Tag } from 'antd'; -import { PlusOutlined, EditOutlined, DeleteOutlined, TagOutlined } from '@ant-design/icons'; +import { Table, Button, Modal, Form, Input, Space, message, InputNumber, Switch, Select, Tag, ColorPicker } from 'antd'; +import { PlusOutlined, EditOutlined, DeleteOutlined, TagOutlined, SettingOutlined } from '@ant-design/icons'; import type { RoleResponse, RoleTagResponse } from './types'; import { useTableData } from '@/hooks/useTableData'; import type { FixedType } from 'rc-table/lib/interface'; import type { TablePaginationConfig } from 'antd/es/table'; import type { FilterValue, SorterResult } from 'antd/es/table/interface'; import { assignTags, getAllTags } from './service'; +import request from '@/utils/request'; const RolePage: React.FC = () => { const { @@ -36,6 +37,9 @@ const RolePage: React.FC = () => { const [selectedRole, setSelectedRole] = useState(null); const [selectedTags, setSelectedTags] = useState([]); const [allTags, setAllTags] = useState([]); + const [tagManageVisible, setTagManageVisible] = useState(false); + const [editingTag, setEditingTag] = useState(null); + const [tagForm] = Form.useForm(); useEffect(() => { getAllTags().then(response => { @@ -81,7 +85,7 @@ const RolePage: React.FC = () => { const handleAssignTags = (record: RoleResponse) => { setSelectedRole(record); - if (record.tags) { + if (record.tags && record.tags.length > 0) { setSelectedTags(record.tags.map(tag => tag.id)); } else { setSelectedTags([]); @@ -89,7 +93,7 @@ const RolePage: React.FC = () => { setTagModalVisible(true); }; - const handleTagSubmit = async () => { + const handleAssignTagSubmit = async () => { if (selectedRole) { await assignTags(selectedRole.id, selectedTags); setTagModalVisible(false); @@ -97,6 +101,54 @@ const RolePage: React.FC = () => { } }; + const handleTagManage = () => { + setTagManageVisible(true); + setEditingTag(null); + tagForm.resetFields(); + }; + + const handleTagManageSubmit = async () => { + try { + const values = await tagForm.validateFields(); + const tagService = { + baseUrl: '/api/v1/role-tag' + }; + + const formData = { + ...values, + color: values.color.toHexString?.() || values.color + }; + + if (values.id) { + await request.put(`${tagService.baseUrl}/${values.id}`, formData, { + successMessage: '更新标签成功' + }); + } else { + await request.post(tagService.baseUrl, formData, { + successMessage: '创建标签成功' + }); + } + setTagManageVisible(false); + const tags = await getAllTags(); + setAllTags(tags); + } catch (error) { + console.error('操作失败:', error); + } + }; + + const handleTagDelete = async (id: number) => { + try { + await request.delete(`/api/v1/role-tag/${id}`, { + successMessage: '删除标签成功' + }); + // 刷新标签列表 + const tags = await getAllTags(); + setAllTags(tags); + } catch (error) { + console.error('删除标签失败:', error); + } + }; + const columns = [ { title: 'ID', @@ -225,9 +277,14 @@ const RolePage: React.FC = () => { return (
- + + + +
{ setTagModalVisible(false)} width={600} destroyOnClose @@ -313,6 +370,109 @@ const RolePage: React.FC = () => { + + { + setTagManageVisible(false); + setEditingTag(null); + }} + width={800} + footer={null} + > +
+ +
+ +
( +
+ ) + }, + { + title: '描述', + dataIndex: 'description' + }, + { + title: '操作', + render: (_, record) => ( + + + + + ) + } + ]} + rowKey="id" + pagination={false} + /> + + {(editingTag || !editingTag) && ( +
+ + + + + + + + + + + + + + + )} +
); }; diff --git a/frontend/src/pages/System/RoleTag/index.tsx b/frontend/src/pages/System/RoleTag/index.tsx new file mode 100644 index 00000000..390ed7bf --- /dev/null +++ b/frontend/src/pages/System/RoleTag/index.tsx @@ -0,0 +1,124 @@ +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(null); + const [form] = Form.useForm(); + + const columns = [ + { + title: '标签名称', + dataIndex: 'name', + key: 'name' + }, + { + title: '颜色', + dataIndex: 'color', + key: 'color', + render: (color: string) => ( +
+ ) + }, + { + title: '描述', + dataIndex: 'description', + key: 'description' + }, + { + title: '操作', + key: 'action', + render: (_: any, record: RoleTagResponse) => ( + + + + + ) + } + ]; + + return ( +
+
+ +
+ +
+ + setModalVisible(false)} + > +
+ + + + + + + + + + + + +
+ + ); +}; + +export default RoleTagPage; \ No newline at end of file