完成标签管理
This commit is contained in:
11
src/App.tsx
11
src/App.tsx
@@ -8,6 +8,7 @@ import Create from './pages/Create';
|
|||||||
import Cate from './pages/Cate';
|
import Cate from './pages/Cate';
|
||||||
import Article from './pages/Article';
|
import Article from './pages/Article';
|
||||||
import Comment from './pages/Comment';
|
import Comment from './pages/Comment';
|
||||||
|
import Tag from './pages/Tag';
|
||||||
import Web from './pages/Web';
|
import Web from './pages/Web';
|
||||||
import Swiper from './pages/Swiper';
|
import Swiper from './pages/Swiper';
|
||||||
import Setup from './pages/Setup';
|
import Setup from './pages/Setup';
|
||||||
@@ -101,6 +102,16 @@ function App() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
path="/tag"
|
||||||
|
element={
|
||||||
|
<>
|
||||||
|
<PageTitle title="Thrive - 标签管理" />
|
||||||
|
<Tag />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/comment"
|
path="/comment"
|
||||||
element={
|
element={
|
||||||
|
|||||||
@@ -182,6 +182,18 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen }: SidebarProps) => {
|
|||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<NavLink
|
||||||
|
to="/tag"
|
||||||
|
className={({ isActive }) =>
|
||||||
|
'group relative flex items-center gap-2.5 rounded-md px-4 font-medium text-bodydark2 duration-300 ease-in-out hover:text-white ' +
|
||||||
|
(isActive && '!text-white')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
标签管理
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<NavLink
|
<NavLink
|
||||||
to="/comment"
|
to="/comment"
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-tree-node-selected {
|
// .ant-tree-node-selected {
|
||||||
.controls {
|
// .controls {
|
||||||
display: block !important;
|
// display: block !important;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { Cate } from '@/types/cate';
|
import { Cate } from '@/types/cate';
|
||||||
import { addCateDataAPI, delCateDataAPI, editCateDataAPI, getCateDataAPI, getCateListAPI } from '@/api/Cate';
|
import { addCateDataAPI, delCateDataAPI, editCateDataAPI, getCateDataAPI, getCateListAPI } from '@/api/Cate';
|
||||||
import { DownOutlined } from '@ant-design/icons';
|
import { DownOutlined } from '@ant-design/icons';
|
||||||
@@ -6,13 +6,14 @@ import { Form, Input, Button, Tree, Modal, Spin, Dropdown, Card, MenuProps, Popc
|
|||||||
import Title from '@/components/Title';
|
import Title from '@/components/Title';
|
||||||
import "./index.scss"
|
import "./index.scss"
|
||||||
|
|
||||||
const CatePage: React.FC = () => {
|
const CatePage = () => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [model, setModel] = useState(false);
|
const [isModelOpen, setIsModelOpen] = useState(false);
|
||||||
const [cate, setCate] = useState<Cate>({} as Cate);
|
const [cate, setCate] = useState<Cate>({} as Cate);
|
||||||
const [list, setList] = useState<Cate[]>([]);
|
const [list, setList] = useState<Cate[]>([]);
|
||||||
const [isMethod, setIsMethod] = useState<'create' | 'edit'>('create');
|
const [isMethod, setIsMethod] = useState<'create' | 'edit'>('create');
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
const getCateList = async () => {
|
const getCateList = async () => {
|
||||||
const { data } = await getCateListAPI();
|
const { data } = await getCateListAPI();
|
||||||
setList(data as Cate[]);
|
setList(data as Cate[]);
|
||||||
@@ -21,14 +22,18 @@ const CatePage: React.FC = () => {
|
|||||||
|
|
||||||
const addCateData = (id: number) => {
|
const addCateData = (id: number) => {
|
||||||
setIsMethod("create")
|
setIsMethod("create")
|
||||||
setModel(true);
|
setIsModelOpen(true);
|
||||||
|
console.log(cate, 333);
|
||||||
|
|
||||||
|
form.resetFields();
|
||||||
|
|
||||||
setCate({ ...cate, level: id });
|
setCate({ ...cate, level: id });
|
||||||
};
|
};
|
||||||
|
|
||||||
const editCateData = async (id: number) => {
|
const editCateData = async (id: number) => {
|
||||||
setIsMethod("edit")
|
setIsMethod("edit")
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setModel(true);
|
setIsModelOpen(true);
|
||||||
const { data } = await getCateDataAPI(id);
|
const { data } = await getCateDataAPI(id);
|
||||||
setCate(data);
|
setCate(data);
|
||||||
form.setFieldsValue(data);
|
form.setFieldsValue(data);
|
||||||
@@ -42,8 +47,6 @@ const CatePage: React.FC = () => {
|
|||||||
getCateList();
|
getCateList();
|
||||||
};
|
};
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
form.validateFields().then(async (values: Cate) => {
|
form.validateFields().then(async (values: Cate) => {
|
||||||
if (isMethod === "edit") {
|
if (isMethod === "edit") {
|
||||||
@@ -58,7 +61,7 @@ const CatePage: React.FC = () => {
|
|||||||
form.resetFields();
|
form.resetFields();
|
||||||
setCate({} as Cate);
|
setCate({} as Cate);
|
||||||
|
|
||||||
setModel(false);
|
setIsModelOpen(false);
|
||||||
getCateList();
|
getCateList();
|
||||||
setIsMethod("create")
|
setIsMethod("create")
|
||||||
})
|
})
|
||||||
@@ -66,7 +69,7 @@ const CatePage: React.FC = () => {
|
|||||||
|
|
||||||
const closeModel = () => {
|
const closeModel = () => {
|
||||||
setIsMethod("create")
|
setIsMethod("create")
|
||||||
setModel(false);
|
setIsModelOpen(false);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
setCate({} as Cate);
|
setCate({} as Cate);
|
||||||
};
|
};
|
||||||
@@ -98,11 +101,9 @@ const CatePage: React.FC = () => {
|
|||||||
<div className='group w-full flex justify-between items-center'>
|
<div className='group w-full flex justify-between items-center'>
|
||||||
<h3>{item.name}</h3>
|
<h3>{item.name}</h3>
|
||||||
|
|
||||||
<div className='controls hidden'>
|
<Dropdown menu={{ items }} arrow>
|
||||||
<Dropdown menu={{ items }} arrow>
|
<Button type='link' size='small'>操作 <DownOutlined /></Button>
|
||||||
<Button type='link' size='small'>操作 <DownOutlined /></Button>
|
</Dropdown>
|
||||||
</Dropdown>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
key: item.id,
|
key: item.id,
|
||||||
@@ -122,14 +123,14 @@ const CatePage: React.FC = () => {
|
|||||||
|
|
||||||
<Card className={`CatePage [&>.ant-card-body]:!p-2 [&>.ant-card-body]:!pb-6 mt-2`}>
|
<Card className={`CatePage [&>.ant-card-body]:!p-2 [&>.ant-card-body]:!pb-6 mt-2`}>
|
||||||
<div className='my-2 text-center'>
|
<div className='my-2 text-center'>
|
||||||
<Button type="primary" onClick={() => setModel(true)}>新增一级分类</Button>
|
<Button type="primary" onClick={() => addCateData(0)}>新增一级分类</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<Tree defaultExpandAll={true} treeData={treeData(list)} />
|
<Tree defaultExpandAll={true} treeData={treeData(list)} />
|
||||||
</Spin>
|
</Spin>
|
||||||
|
|
||||||
<Modal title={isMethod === "edit" ? "编辑分类" : "新增分类"} open={model} onCancel={closeModel} footer={null}>
|
<Modal title={isMethod === "edit" ? "编辑分类" : "新增分类"} open={isModelOpen} onCancel={closeModel} footer={null}>
|
||||||
<Form form={form} layout="vertical" initialValues={cate} size='large' className='mt-6'>
|
<Form form={form} layout="vertical" initialValues={cate} size='large' className='mt-6'>
|
||||||
<Form.Item label="名称" name="name" rules={[{ required: true, message: '分类名称不能为空' }]}>
|
<Form.Item label="名称" name="name" rules={[{ required: true, message: '分类名称不能为空' }]}>
|
||||||
<Input placeholder="大前端" />
|
<Input placeholder="大前端" />
|
||||||
|
|||||||
120
src/pages/Tag/index.tsx
Normal file
120
src/pages/Tag/index.tsx
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Form, Input, Button, Table, notification, Card, message, Popconfirm } from 'antd';
|
||||||
|
import { TagOutlined, SettingOutlined } from '@ant-design/icons';
|
||||||
|
import { addTagDataAPI, delTagDataAPI, editTagDataAPI, getTagListAPI } from '@/api/Tag';
|
||||||
|
import Title from '@/components/Title';
|
||||||
|
|
||||||
|
interface Tag {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TagManagement: React.FC = () => {
|
||||||
|
const [form] = Form.useForm<Tag>();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [tag, setTag] = useState<Tag>({ name: '' });
|
||||||
|
const [title, setTitle] = useState<string>('新增标签');
|
||||||
|
const [list, setList] = useState<Tag[]>([]);
|
||||||
|
|
||||||
|
// 获取标签列表
|
||||||
|
const getTagList = async () => {
|
||||||
|
const { data } = await getTagListAPI()
|
||||||
|
setList(data as Tag[]);
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(true)
|
||||||
|
getTagList()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const delTagData = async (id: number) => {
|
||||||
|
setLoading(true);
|
||||||
|
await delTagDataAPI(id);
|
||||||
|
message.success('🎉 删除标签成功');
|
||||||
|
getTagList()
|
||||||
|
};
|
||||||
|
|
||||||
|
const editTagData = (data: Tag) => {
|
||||||
|
setLoading(true);
|
||||||
|
setTag(data);
|
||||||
|
setTitle('编辑标签');
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = () => {
|
||||||
|
form.validateFields().then(async (values) => {
|
||||||
|
const fn = (message: string) => {
|
||||||
|
form.resetFields();
|
||||||
|
|
||||||
|
notification.success({
|
||||||
|
message: '成功',
|
||||||
|
description: message,
|
||||||
|
});
|
||||||
|
getTagList()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tag.id) {
|
||||||
|
await editTagDataAPI(tag);
|
||||||
|
setTitle('新增标签');
|
||||||
|
fn('🎉 编辑标签成功');
|
||||||
|
} else {
|
||||||
|
await addTagDataAPI(values);
|
||||||
|
fn('🎉 新增标签成功');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Title value="标签管理" />
|
||||||
|
|
||||||
|
<Card className="mt-2">
|
||||||
|
<div className="w-8/12 flex justify-between px-8 mx-auto">
|
||||||
|
<div className="flex flex-col w-[40%]">
|
||||||
|
<h2 className="text-xl pb-4 text-center">{title}</h2>
|
||||||
|
|
||||||
|
<Form form={form} size="large" layout="vertical" initialValues={tag}>
|
||||||
|
<Form.Item
|
||||||
|
label="标签名称"
|
||||||
|
name="name"
|
||||||
|
rules={[{ required: true, message: '标签不能为空' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="大前端" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="primary" size="large" onClick={submit} className="w-full">{title}</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col w-[50%]">
|
||||||
|
<h2 className="text-xl pb-4 text-center">标签列表</h2>
|
||||||
|
|
||||||
|
<Table dataSource={list} rowKey="id">
|
||||||
|
<Table.Column title="ID" dataIndex="id" />
|
||||||
|
<Table.Column title="名称" dataIndex="name" align="center" />
|
||||||
|
<Table.Column
|
||||||
|
title="操作"
|
||||||
|
align="center"
|
||||||
|
render={(text, record: Tag) => (
|
||||||
|
<>
|
||||||
|
<div className='flex justify-center space-x-4'>
|
||||||
|
<Button size="small" onClick={() => editTagData(record)}>编辑</Button>
|
||||||
|
|
||||||
|
<Popconfirm title="警告" description="你确定要删除吗" okText="确定" cancelText="取消" onConfirm={() => delTagData(record.id!)}>
|
||||||
|
<Button size="small" type="primary" danger>删除</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagManagement;
|
||||||
Reference in New Issue
Block a user