大改动
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { Table, Button, Form, Input, Popconfirm, message, Card } from 'antd';
|
import { Table, Button, Form, Input, Popconfirm, message, Card } from 'antd';
|
||||||
import { getTagListAPI, addTagDataAPI, editTagDataAPI, delTagDataAPI } from '@/api/Tag';
|
import { getTagListAPI, addTagDataAPI, editTagDataAPI, delTagDataAPI, getTagDataAPI } from '@/api/Tag';
|
||||||
import { Tag } from '@/types/app/tag';
|
import { Tag } from '@/types/app/tag';
|
||||||
import Title from '@/components/Title';
|
import Title from '@/components/Title';
|
||||||
import { ColumnsType } from 'antd/es/table';
|
import { ColumnsType } from 'antd/es/table';
|
||||||
|
|
||||||
const TagPage = () => {
|
const TagPage = () => {
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [btnLoading, setBtnLoading] = useState(false)
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
const [tag, setTag] = useState<Tag>({} as Tag);
|
const [tag, setTag] = useState<Tag>({} as Tag);
|
||||||
const [list, setList] = useState<Tag[]>([]);
|
const [list, setList] = useState<Tag[]>([]);
|
||||||
@@ -28,49 +31,76 @@ const TagPage = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const getTagList = async () => {
|
const getTagList = async () => {
|
||||||
setLoading(true);
|
try {
|
||||||
const { data } = await getTagListAPI();
|
const { data } = await getTagListAPI();
|
||||||
setList(data as Tag[]);
|
setList(data as Tag[]);
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
getTagList();
|
getTagList();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
const editTagData = async (record: Tag) => {
|
||||||
const editTagData = (record: Tag) => {
|
setLoading(true);
|
||||||
setTag(record);
|
|
||||||
form.setFieldsValue(record);
|
try {
|
||||||
|
const { data } = await getTagDataAPI(record.id)
|
||||||
|
setTag(data);
|
||||||
|
form.setFieldsValue(data);
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const delTagData = async (id: number) => {
|
const delTagData = async (id: number) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await delTagDataAPI(id);
|
|
||||||
message.success('🎉 删除标签成功');
|
try {
|
||||||
getTagList();
|
await delTagDataAPI(id);
|
||||||
|
await getTagList();
|
||||||
|
message.success('🎉 删除标签成功');
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
form.validateFields().then(async (values: Tag) => {
|
setBtnLoading(true);
|
||||||
if (tag.id) {
|
|
||||||
await editTagDataAPI({ ...tag, ...values });
|
|
||||||
message.success('🎉 编辑标签成功');
|
|
||||||
} else {
|
|
||||||
await addTagDataAPI(values);
|
|
||||||
message.success('🎉 新增标签成功');
|
|
||||||
}
|
|
||||||
|
|
||||||
getTagList();
|
try {
|
||||||
form.resetFields();
|
form.validateFields().then(async (values: Tag) => {
|
||||||
form.setFieldsValue({ name: '' })
|
if (tag.id) {
|
||||||
setTag({} as Tag);
|
await editTagDataAPI({ ...tag, ...values });
|
||||||
});
|
message.success('🎉 编辑标签成功');
|
||||||
|
} else {
|
||||||
|
await addTagDataAPI(values);
|
||||||
|
message.success('🎉 新增标签成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
await getTagList();
|
||||||
|
form.resetFields();
|
||||||
|
form.setFieldsValue({ name: '' })
|
||||||
|
setTag({} as Tag);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
setBtnLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setBtnLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div>
|
||||||
<Title value="标签管理" />
|
<Title value="标签管理" />
|
||||||
|
|
||||||
<div className='flex md:justify-between flex-col md:flex-row mx-auto mt-2'>
|
<div className='flex md:justify-between flex-col md:flex-row mx-auto mt-2'>
|
||||||
@@ -81,14 +111,13 @@ const TagPage = () => {
|
|||||||
initialValues={tag}
|
initialValues={tag}
|
||||||
onFinish={onSubmit}
|
onFinish={onSubmit}
|
||||||
size='large'
|
size='large'
|
||||||
|
|
||||||
>
|
>
|
||||||
<Form.Item label="标签名称" name="name" rules={[{ required: true, message: '标签名称不能为空' }]}>
|
<Form.Item label="标签名称" name="name" rules={[{ required: true, message: '标签名称不能为空' }]}>
|
||||||
<Input placeholder="请输入标签名称" />
|
<Input placeholder="请输入标签名称" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Button type="primary" htmlType="submit" loading={loading} className="w-full">{tag.id ? '编辑标签' : '新增标签'}</Button>
|
<Button type="primary" htmlType="submit" loading={btnLoading} className="w-full">{tag.id ? '编辑标签' : '新增标签'}</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -107,7 +136,7 @@ const TagPage = () => {
|
|||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import dayjs from 'dayjs';
|
|||||||
const UserPage = () => {
|
const UserPage = () => {
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
const [btnLoading, setBtnLoading] = useState(false)
|
const [btnLoading, setBtnLoading] = useState(false)
|
||||||
|
const [editLoading, setEditLoading] = useState(false)
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
const store = useUserStore()
|
const store = useUserStore()
|
||||||
|
|
||||||
const [userList, setUserList] = useState<User[]>([]);
|
const [userList, setUserList] = useState<User[]>([]);
|
||||||
@@ -107,76 +109,105 @@ const UserPage = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const [userForm] = Form.useForm();
|
|
||||||
|
|
||||||
const getUserList = async () => {
|
const getUserList = async () => {
|
||||||
setLoading(true);
|
try {
|
||||||
const { data } = await getUserListAPI();
|
const { data } = await getUserListAPI();
|
||||||
setUserList(data as User[]);
|
setUserList(data as User[]);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRoleList = async () => {
|
const getRoleList = async () => {
|
||||||
const { data } = await getRoleListAPI();
|
const { data } = await getRoleListAPI();
|
||||||
setRoleList(data as Role[]);
|
console.log(data);
|
||||||
|
|
||||||
|
setRoleList(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
getUserList();
|
getUserList();
|
||||||
getRoleList()
|
getRoleList()
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const delUserData = async (id: number) => {
|
const delUserData = async (id: number) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await delUserDataAPI(id);
|
|
||||||
await getUserList();
|
try {
|
||||||
notification.success({ message: '🎉 删除用户成功' });
|
await delUserDataAPI(id);
|
||||||
setLoading(false);
|
await getUserList();
|
||||||
|
notification.success({ message: '🎉 删除用户成功' });
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const editUserData = async (id: number) => {
|
const editUserData = async (id: number) => {
|
||||||
const { data } = await getUserDataAPI(id)
|
setEditLoading(true);
|
||||||
setUser({ ...data, role: data.role.id });
|
|
||||||
|
|
||||||
userForm.setFieldsValue({ ...data, roleId: data.role.id });
|
try {
|
||||||
setDrawerVisible(true);
|
setDrawerVisible(true);
|
||||||
|
const { data } = await getUserDataAPI(id)
|
||||||
|
setUser(data);
|
||||||
|
form.setFieldsValue(data);
|
||||||
|
} catch (error) {
|
||||||
|
setEditLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setEditLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
setUser({} as User)
|
setUser({} as User)
|
||||||
userForm.resetFields()
|
form.resetFields()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
setBtnLoading(true)
|
setBtnLoading(true)
|
||||||
|
|
||||||
userForm.validateFields().then(async (values: User) => {
|
try {
|
||||||
if (user.id) {
|
form.validateFields().then(async (values: User) => {
|
||||||
await editUserDataAPI({ ...user, ...values });
|
if (user.id) {
|
||||||
notification.success({ message: '🎉 编辑用户成功' });
|
await editUserDataAPI({ ...user, ...values });
|
||||||
} else {
|
notification.success({ message: '🎉 编辑用户成功' });
|
||||||
await addUserDataAPI({ ...values, password: "123456", createTime: new Date().getTime().toString() });
|
} else {
|
||||||
notification.success({ message: '🎉 创建用户成功' });
|
await addUserDataAPI({ ...values, password: "123456", createTime: new Date().getTime().toString() });
|
||||||
}
|
notification.success({ message: '🎉 创建用户成功' });
|
||||||
setDrawerVisible(false);
|
}
|
||||||
getUserList();
|
|
||||||
})
|
await getUserList();
|
||||||
|
setDrawerVisible(false);
|
||||||
|
reset()
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
setBtnLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
setBtnLoading(false)
|
setBtnLoading(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
const [filterForm] = Form.useForm();
|
|
||||||
|
|
||||||
const onFilterSubmit = async (values: FilterForm) => {
|
const onFilterSubmit = async (values: FilterForm) => {
|
||||||
const query: FilterUser = {
|
setLoading(true)
|
||||||
key: values.name,
|
|
||||||
roleId: values.role,
|
try {
|
||||||
startDate: values.createTime && values.createTime[0].valueOf() + '',
|
const query: FilterUser = {
|
||||||
endDate: values.createTime && values.createTime[1].valueOf() + ''
|
key: values.name,
|
||||||
|
roleId: values.role,
|
||||||
|
startDate: values.createTime && values.createTime[0].valueOf() + '',
|
||||||
|
endDate: values.createTime && values.createTime[1].valueOf() + ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await getUserListAPI({ query });
|
||||||
|
setUserList(data as User[]);
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await getUserListAPI({ query });
|
setLoading(false)
|
||||||
setUserList(data as User[]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -186,7 +217,7 @@ const UserPage = () => {
|
|||||||
</Title>
|
</Title>
|
||||||
|
|
||||||
<Card className='my-2 overflow-scroll'>
|
<Card className='my-2 overflow-scroll'>
|
||||||
<Form form={filterForm} layout="inline" onFinish={onFilterSubmit} autoComplete="off" className='flex-nowrap'>
|
<Form layout="inline" onFinish={onFilterSubmit} autoComplete="off" className='flex-nowrap'>
|
||||||
<Form.Item label="名称" name="name" className='min-w-[200px]'>
|
<Form.Item label="名称" name="name" className='min-w-[200px]'>
|
||||||
<Input placeholder='请输入名称' />
|
<Input placeholder='请输入名称' />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -227,9 +258,10 @@ const UserPage = () => {
|
|||||||
setDrawerVisible(false)
|
setDrawerVisible(false)
|
||||||
}}
|
}}
|
||||||
open={drawerVisible}
|
open={drawerVisible}
|
||||||
|
loading={editLoading}
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
form={userForm}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
size='large'
|
size='large'
|
||||||
onFinish={onSubmit}
|
onFinish={onSubmit}
|
||||||
@@ -278,7 +310,7 @@ const UserPage = () => {
|
|||||||
label="角色"
|
label="角色"
|
||||||
rules={[{ required: true, message: '请选择角色' }]}
|
rules={[{ required: true, message: '请选择角色' }]}
|
||||||
>
|
>
|
||||||
<Select options={roleList.map(item => ({ label: item.name, value: item.id }))} placeholder="选择用户角色" />
|
<Select options={roleList.map(item => ({ label: item.name, value: +item.id }))} placeholder="选择用户角色" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
|
|||||||
@@ -9,23 +9,35 @@ import dayjs from 'dayjs';
|
|||||||
|
|
||||||
const WallPage = () => {
|
const WallPage = () => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [wall, setWall] = useState<Wall>();
|
|
||||||
|
const [wall, setWall] = useState<Wall>({} as Wall);
|
||||||
const [list, setList] = useState<Wall[]>([]);
|
const [list, setList] = useState<Wall[]>([]);
|
||||||
|
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
|
||||||
const getWallList = async () => {
|
const getWallList = async () => {
|
||||||
const { data } = await getWallListAPI();
|
try {
|
||||||
|
const { data } = await getWallListAPI();
|
||||||
|
setList(data)
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
setList(data)
|
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const delWallData = async (id: number) => {
|
const delWallData = async (id: number) => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
await delWallDataAPI(id);
|
|
||||||
getWallList();
|
try {
|
||||||
message.success('🎉 删除留言成功');
|
await delWallDataAPI(id);
|
||||||
|
await getWallList();
|
||||||
|
message.success('🎉 删除留言成功');
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取留言的分类列表
|
// 获取留言的分类列表
|
||||||
@@ -105,16 +117,24 @@ const WallPage = () => {
|
|||||||
|
|
||||||
const { RangePicker } = DatePicker;
|
const { RangePicker } = DatePicker;
|
||||||
|
|
||||||
const onSubmit = async (values: FilterForm) => {
|
const onFilterSubmit = async (values: FilterForm) => {
|
||||||
const query: FilterWall = {
|
setLoading(true)
|
||||||
key: values.content,
|
|
||||||
cateId: values.cateId,
|
try {
|
||||||
startDate: values.createTime && values.createTime[0].valueOf() + '',
|
const query: FilterWall = {
|
||||||
endDate: values.createTime && values.createTime[1].valueOf() + ''
|
key: values.content,
|
||||||
|
cateId: values.cateId,
|
||||||
|
startDate: values.createTime && values.createTime[0].valueOf() + '',
|
||||||
|
endDate: values.createTime && values.createTime[1].valueOf() + ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await getWallListAPI({ query });
|
||||||
|
setList(data)
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await getWallListAPI({ query });
|
setLoading(false)
|
||||||
setList(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -122,7 +142,7 @@ const WallPage = () => {
|
|||||||
<Title value='留言管理' />
|
<Title value='留言管理' />
|
||||||
|
|
||||||
<Card className='my-2 overflow-scroll'>
|
<Card className='my-2 overflow-scroll'>
|
||||||
<Form layout="inline" onFinish={onSubmit} autoComplete="off" className='flex-nowrap'>
|
<Form layout="inline" onFinish={onFilterSubmit} autoComplete="off" className='flex-nowrap'>
|
||||||
<Form.Item label="内容" name="content" className='min-w-[200px]'>
|
<Form.Item label="内容" name="content" className='min-w-[200px]'>
|
||||||
<Input placeholder='请输入内容关键词' />
|
<Input placeholder='请输入内容关键词' />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { Tabs, Input, Button, Form, Spin, Empty, Card, Popconfirm, Select, message } from 'antd';
|
import { Tabs, Input, Button, Form, Spin, Empty, Card, Popconfirm, Select, message } from 'antd';
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import { getLinkListAPI, addLinkDataAPI, editLinkDataAPI, delLinkDataAPI, getWebTypeListAPI } from '@/api/Web';
|
import { getLinkListAPI, addLinkDataAPI, editLinkDataAPI, delLinkDataAPI, getWebTypeListAPI, getLinkDataAPI } from '@/api/Web';
|
||||||
import { WebType, Web } from '@/types/app/web';
|
import { WebType, Web } from '@/types/app/web';
|
||||||
import Title from '@/components/Title';
|
import Title from '@/components/Title';
|
||||||
import { RuleObject } from 'antd/es/form';
|
import { RuleObject } from 'antd/es/form';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
const LinkPage = () => {
|
export default () => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [btnLoading, setBtnLoading] = useState(false)
|
const [btnLoading, setBtnLoading] = useState(false)
|
||||||
|
const [editLoading, setEditLoading] = useState(false)
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
const [tab, setTab] = useState<string>('list');
|
const [tab, setTab] = useState<string>('list');
|
||||||
const [list, setList] = useState<Web[]>([]);
|
const [list, setList] = useState<Web[]>([]);
|
||||||
@@ -23,13 +26,18 @@ const LinkPage = () => {
|
|||||||
|
|
||||||
// 获取网站列表
|
// 获取网站列表
|
||||||
const getLinkList = async () => {
|
const getLinkList = async () => {
|
||||||
const { data } = await getLinkListAPI();
|
try {
|
||||||
data.sort((a, b) => a.order - b.order)
|
const { data } = await getLinkListAPI();
|
||||||
data.sort((a, b) => a.type.order - b.type.order)
|
data.sort((a, b) => a.order - b.order)
|
||||||
|
data.sort((a, b) => a.type.order - b.type.order)
|
||||||
|
|
||||||
setList(data as Web[]);
|
setList(data);
|
||||||
setListTemp(data as Web[]);
|
setListTemp(data);
|
||||||
setLoading(false);
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取网站类型列表
|
// 获取网站类型列表
|
||||||
@@ -50,18 +58,31 @@ const LinkPage = () => {
|
|||||||
|
|
||||||
const deleteLinkData = async (id: number) => {
|
const deleteLinkData = async (id: number) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await delLinkDataAPI(id);
|
|
||||||
message.success('🎉 删除网站成功');
|
try {
|
||||||
getLinkList();
|
await delLinkDataAPI(id);
|
||||||
|
await getLinkList();
|
||||||
|
message.success('🎉 删除网站成功');
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
const editLinkData = async (record: Web) => {
|
||||||
|
setEditLoading(true)
|
||||||
|
|
||||||
const editLinkData = (item: Web) => {
|
try {
|
||||||
setTab('operate');
|
setTab('operate');
|
||||||
setIsMethod("edit");
|
setIsMethod("edit");
|
||||||
setLink(item);
|
|
||||||
form.setFieldsValue(item); // 回显数据
|
const { data } = await getLinkDataAPI(record.id)
|
||||||
|
setLink(data);
|
||||||
|
form.setFieldsValue(data);
|
||||||
|
} catch (error) {
|
||||||
|
setEditLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
setEditLoading(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 做一些初始化的事情
|
// 做一些初始化的事情
|
||||||
@@ -79,19 +100,23 @@ const LinkPage = () => {
|
|||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
setBtnLoading(true)
|
setBtnLoading(true)
|
||||||
|
|
||||||
form.validateFields().then(async (values: Web) => {
|
try {
|
||||||
if (isMethod === "edit") {
|
form.validateFields().then(async (values: Web) => {
|
||||||
await editLinkDataAPI({ ...link, ...values });
|
if (isMethod === "edit") {
|
||||||
message.success('🎉 编辑网站成功');
|
await editLinkDataAPI({ ...link, ...values });
|
||||||
} else {
|
message.success('🎉 编辑网站成功');
|
||||||
await addLinkDataAPI({ ...values, createTime: new Date().getTime().toString() });
|
} else {
|
||||||
message.success('🎉 新增网站成功');
|
await addLinkDataAPI({ ...values, createTime: new Date().getTime().toString() });
|
||||||
}
|
message.success('🎉 新增网站成功');
|
||||||
|
}
|
||||||
|
|
||||||
getLinkList();
|
await getLinkList();
|
||||||
setTab('list');
|
reset()
|
||||||
reset()
|
setTab('list');
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
setBtnLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
setBtnLoading(false)
|
setBtnLoading(false)
|
||||||
};
|
};
|
||||||
@@ -164,47 +189,49 @@ const LinkPage = () => {
|
|||||||
<>
|
<>
|
||||||
<h2 className="text-xl pb-4 text-center">{isMethod === "edit" ? '编辑网站' : '新增网站'}</h2>
|
<h2 className="text-xl pb-4 text-center">{isMethod === "edit" ? '编辑网站' : '新增网站'}</h2>
|
||||||
|
|
||||||
<div className='w-full md:w-[500px] mx-auto'>
|
<Spin spinning={editLoading}>
|
||||||
<Form form={form} layout="vertical" size='large' initialValues={link} onFinish={submit}>
|
<div className='w-full md:w-[500px] mx-auto'>
|
||||||
<Form.Item label="网站标题" name="title" rules={[{ required: true, message: '网站标题不能为空' }]}>
|
<Form form={form} layout="vertical" size='large' initialValues={link} onFinish={submit}>
|
||||||
<Input placeholder="Thrive" />
|
<Form.Item label="网站标题" name="title" rules={[{ required: true, message: '网站标题不能为空' }]}>
|
||||||
</Form.Item>
|
<Input placeholder="Thrive" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="网站描述" name="description" rules={[{ required: true, message: '网站描述不能为空' }]}>
|
<Form.Item label="网站描述" name="description" rules={[{ required: true, message: '网站描述不能为空' }]}>
|
||||||
<Input placeholder="记录前端、Python、Java点点滴滴" />
|
<Input placeholder="记录前端、Python、Java点点滴滴" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="站长邮箱" name="email">
|
<Form.Item label="站长邮箱" name="email">
|
||||||
<Input placeholder="3311118881@qq.com" />
|
<Input placeholder="3311118881@qq.com" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="网站图标" name="image" rules={[{ required: true, message: '网站图标不能为空' }]}>
|
<Form.Item label="网站图标" name="image" rules={[{ required: true, message: '网站图标不能为空' }]}>
|
||||||
<Input placeholder="https://liuyuyang.net/logo.png" />
|
<Input placeholder="https://liuyuyang.net/logo.png" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="网站链接" name="url" rules={[{ required: true, message: '网站链接不能为空' }, { validator: validateURL }]}>
|
<Form.Item label="网站链接" name="url" rules={[{ required: true, message: '网站链接不能为空' }, { validator: validateURL }]}>
|
||||||
<Input placeholder="https://liuyuyang.net/" />
|
<Input placeholder="https://liuyuyang.net/" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="订阅地址" name="rss" rules={[{ validator: validateURL }]}>
|
<Form.Item label="订阅地址" name="rss" rules={[{ validator: validateURL }]}>
|
||||||
<Input placeholder="https://liuyuyang.net/api/rss" />
|
<Input placeholder="https://liuyuyang.net/api/rss" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item name="typeId" label="网站类型" rules={[{ required: true, message: '网站类型不能为空' }]}>
|
<Form.Item name="typeId" label="网站类型" rules={[{ required: true, message: '网站类型不能为空' }]}>
|
||||||
<Select placeholder="请选择网站类型" allowClear>
|
<Select placeholder="请选择网站类型" allowClear>
|
||||||
{typeList.map(item => <Option key={item.id} value={item.id}>{item.name}</Option>)}
|
{typeList.map(item => <Option key={item.id} value={item.id}>{item.name}</Option>)}
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="顺序" name="order">
|
<Form.Item label="顺序" name="order">
|
||||||
<Input placeholder="请输入网站顺序(值越小越靠前)" />
|
<Input placeholder="请输入网站顺序(值越小越靠前)" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Button type="primary" htmlType="submit" loading={btnLoading} className='w-full'>{isMethod === "edit" ? '编辑网站' : '新增网站'}</Button>
|
<Button type="primary" htmlType="submit" loading={btnLoading} className='w-full'>{isMethod === "edit" ? '编辑网站' : '新增网站'}</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
</Spin>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -219,6 +246,4 @@ const LinkPage = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LinkPage;
|
|
||||||
210
src/pages/Work/components/List/index.tsx
Normal file
210
src/pages/Work/components/List/index.tsx
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { Button, Dropdown, message, Modal } from "antd";
|
||||||
|
import { delLinkDataAPI, auditWebDataAPI } from '@/api/Web';
|
||||||
|
import { auditCommentDataAPI, delCommentDataAPI, addCommentDataAPI } from "@/api/Comment";
|
||||||
|
import { auditWallDataAPI, delWallDataAPI } from "@/api/Wall";
|
||||||
|
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import RandomAvatar from "@/components/RandomAvatar";
|
||||||
|
|
||||||
|
import { useUserStore, useWebStore } from '@/stores';
|
||||||
|
import TextArea from "antd/es/input/TextArea";
|
||||||
|
import { sendDismissEmailAPI } from "@/api/Email";
|
||||||
|
|
||||||
|
type Menu = "comment" | "link" | "wall";
|
||||||
|
|
||||||
|
interface ListItemProps {
|
||||||
|
item: any;
|
||||||
|
type: Menu;
|
||||||
|
fetchData: (type: Menu) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ({ item, type, fetchData }: ListItemProps) => {
|
||||||
|
const web = useWebStore(state => state.web)
|
||||||
|
const user = useUserStore(state => state.user)
|
||||||
|
|
||||||
|
const [btnType, setBtnType] = useState<"reply" | "dismiss" | string>("")
|
||||||
|
|
||||||
|
// 通过
|
||||||
|
const handleApproval = async () => {
|
||||||
|
if (type === "link") {
|
||||||
|
await auditWebDataAPI(item.id);
|
||||||
|
} else if (type === "comment") {
|
||||||
|
await auditCommentDataAPI(item.id);
|
||||||
|
} else if (type === "wall") {
|
||||||
|
await auditWallDataAPI(item.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
btnType != "reply" && message.success('🎉 审核成功');
|
||||||
|
fetchData(type);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 回复
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [replyInfo, setReplyInfo] = useState("")
|
||||||
|
const handleReply = async () => {
|
||||||
|
// 审核通过评论
|
||||||
|
await handleApproval()
|
||||||
|
|
||||||
|
// 发送回复内容
|
||||||
|
await addCommentDataAPI({
|
||||||
|
avatar: user.avatar,
|
||||||
|
url: web.url,
|
||||||
|
content: replyInfo,
|
||||||
|
commentId: item?.id!,
|
||||||
|
auditStatus: 1,
|
||||||
|
email: user.email ? user.email : null,
|
||||||
|
name: user.name,
|
||||||
|
articleId: item?.articleId!,
|
||||||
|
createTime: new Date().getTime().toString(),
|
||||||
|
})
|
||||||
|
|
||||||
|
message.success('🎉 回复成功');
|
||||||
|
setIsModalOpen(false)
|
||||||
|
fetchData(type);
|
||||||
|
setReplyInfo("")
|
||||||
|
setBtnType("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 驳回
|
||||||
|
const [dismissInfo, setDismissInfo] = useState("")
|
||||||
|
const handleDismiss = async () => {
|
||||||
|
if (type === "link") {
|
||||||
|
await delLinkDataAPI(item.id);
|
||||||
|
} else if (type === "comment") {
|
||||||
|
await delCommentDataAPI(item.id);
|
||||||
|
} else if (type === "wall") {
|
||||||
|
await delWallDataAPI(item.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 有内容就发送驳回通知邮件,反之直接删除
|
||||||
|
if (dismissInfo.trim().length) await sendDismissEmail()
|
||||||
|
|
||||||
|
message.success('🎉 驳回成功');
|
||||||
|
setIsModalOpen(false)
|
||||||
|
fetchData(type);
|
||||||
|
setDismissInfo("")
|
||||||
|
setBtnType("")
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送驳回通知邮件
|
||||||
|
const sendDismissEmail = async () => {
|
||||||
|
// 类型名称
|
||||||
|
let email_info = {
|
||||||
|
name: "",
|
||||||
|
type: "",
|
||||||
|
url: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "link":
|
||||||
|
email_info = {
|
||||||
|
name: item.title,
|
||||||
|
type: "友链",
|
||||||
|
url: `${web.url}/friend`,
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "comment":
|
||||||
|
email_info = {
|
||||||
|
name: item.name,
|
||||||
|
type: "评论",
|
||||||
|
url: `${web.url}/article/${item.articleId}`,
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "wall":
|
||||||
|
email_info = {
|
||||||
|
name: item.name,
|
||||||
|
type: "留言",
|
||||||
|
url: `${web.url}/wall/all`,
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 有邮箱才会邮件通知
|
||||||
|
item.email != null && await sendDismissEmailAPI({
|
||||||
|
to: item.email,
|
||||||
|
content: dismissInfo,
|
||||||
|
recipient: email_info.name,
|
||||||
|
subject: `${email_info.type}驳回通知`,
|
||||||
|
time: dayjs(Date.now()).format('YYYY年MM月DD日 HH:mm'),
|
||||||
|
type: email_info.type,
|
||||||
|
url: email_info.url
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={item.id}>
|
||||||
|
<div className="text-center text-xs text-[#e0e0e0] mb-4">
|
||||||
|
{dayjs(+item.createTime!).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-between md:p-7 rounded-md transition-colors">
|
||||||
|
<div className="flex mr-10">
|
||||||
|
{type !== "wall" ? (
|
||||||
|
<img src={item.avatar || item.image} alt="" className="w-13 h-13 border border-[#eee] rounded-full" />
|
||||||
|
) : <RandomAvatar className="w-13 h-13 border border-[#eee] rounded-full" />}
|
||||||
|
|
||||||
|
<div className="flex flex-col justify-center ml-4 px-4 py-2 min-w-[210px] text-xs md:text-sm bg-[#F9F9FD] dark:bg-[#4e5969] rounded-md">
|
||||||
|
{type === "link" ? (
|
||||||
|
<>
|
||||||
|
<div>名称:{item.title}</div>
|
||||||
|
<div>介绍:{item.description}</div>
|
||||||
|
<div>类型:{item.type.name}</div>
|
||||||
|
<div>网站:{item?.url ? <a href={item?.url} target='_blank' className="hover:text-primary font-bold">{item?.url}</a> : '无网站'}</div>
|
||||||
|
</>
|
||||||
|
) : type === "comment" ? (
|
||||||
|
<>
|
||||||
|
<div>名称:{item.name}</div>
|
||||||
|
<div>内容:{item.content}</div>
|
||||||
|
<div>网站:{item?.url ? <a href={item?.url} target='_blank' className="hover:text-primary font-bold">{item?.url}</a> : '无网站'}</div>
|
||||||
|
<div>所属文章:<a href={`${web.url}/article/${item.articleId}`} target='_blank' className="hover:text-primary">{item.articleTitle || '暂无'}</a></div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div>名称:{item.name}</div>
|
||||||
|
<div>内容:{item.content}</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div>邮箱:{item.email || '暂无'}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-end">
|
||||||
|
<Dropdown menu={{
|
||||||
|
items: type === "comment"
|
||||||
|
? [
|
||||||
|
{ key: 'ok', label: "通过", onClick: handleApproval },
|
||||||
|
{ key: 'reply', label: "回复", onClick: () => [setIsModalOpen(true), setBtnType("reply")] },
|
||||||
|
{ key: 'dismiss', label: "驳回", onClick: () => [setIsModalOpen(true), , setBtnType("dismiss")] }
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{ key: 'ok', label: "通过", onClick: handleApproval },
|
||||||
|
{ key: 'dismiss', label: "驳回", onClick: () => [setIsModalOpen(true), , setBtnType("dismiss")] }
|
||||||
|
]
|
||||||
|
}}>
|
||||||
|
<div className="flex justify-evenly items-center bg-[#F9F9FD] dark:bg-[#4e5969] w-11 h-5 rounded-md cursor-pointer">
|
||||||
|
<span className="inline-block w-2 h-2 bg-[#b5c2d3] rounded-full"></span>
|
||||||
|
<span className="inline-block w-2 h-2 bg-[#b5c2d3] rounded-full"></span>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Modal title={btnType === "reply" ? "回复内容" : "驳回原因"} open={isModalOpen} footer={null} onCancel={() => setIsModalOpen(false)} onClose={() => setIsModalOpen(false)}>
|
||||||
|
<TextArea
|
||||||
|
value={btnType === "reply" ? replyInfo : dismissInfo}
|
||||||
|
onChange={(e) => (btnType === "reply" ? setReplyInfo(e.target.value) : setDismissInfo(e.target.value))}
|
||||||
|
placeholder={btnType === "reply" ? "请输入回复内容" : "请输入驳回原因"}
|
||||||
|
autoSize={{ minRows: 3, maxRows: 5 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex space-x-4">
|
||||||
|
<Button className="w-full mt-2" onClick={() => setIsModalOpen(false)}>取消</Button>
|
||||||
|
<Button type="primary" className="w-full mt-2" onClick={btnType === "reply" ? handleReply : handleDismiss}>确定</Button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Button, Card, Dropdown, message, Modal } from "antd";
|
import { Card, Spin } from "antd";
|
||||||
import { getLinkListAPI, delLinkDataAPI, auditWebDataAPI } from '@/api/Web';
|
import { getLinkListAPI } from '@/api/Web';
|
||||||
import { getCommentListAPI, auditCommentDataAPI, delCommentDataAPI, addCommentDataAPI } from "@/api/Comment";
|
import { getCommentListAPI } from "@/api/Comment";
|
||||||
import { getWallListAPI, auditWallDataAPI, delWallDataAPI } from "@/api/Wall";
|
import { getWallListAPI } from "@/api/Wall";
|
||||||
|
|
||||||
import Title from "@/components/Title";
|
import Title from "@/components/Title";
|
||||||
|
|
||||||
@@ -10,213 +10,14 @@ import comment from './image/comment.svg';
|
|||||||
import info from './image/message.svg';
|
import info from './image/message.svg';
|
||||||
import link from './image/link.svg';
|
import link from './image/link.svg';
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import RandomAvatar from "@/components/RandomAvatar";
|
|
||||||
import Empty from "@/components/Empty";
|
import Empty from "@/components/Empty";
|
||||||
|
import List from "./components/List";
|
||||||
import { useUserStore, useWebStore } from '@/stores';
|
|
||||||
import TextArea from "antd/es/input/TextArea";
|
|
||||||
import { sendDismissEmailAPI } from "@/api/Email";
|
|
||||||
|
|
||||||
type Menu = "comment" | "link" | "wall";
|
type Menu = "comment" | "link" | "wall";
|
||||||
|
|
||||||
interface ListItemProps {
|
export default () => {
|
||||||
item: any;
|
const [loading, setLoading] = useState(false)
|
||||||
type: Menu;
|
|
||||||
fetchData: (type: Menu) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ListItem = ({ item, type, fetchData }: ListItemProps) => {
|
|
||||||
const web = useWebStore(state => state.web)
|
|
||||||
const user = useUserStore(state => state.user)
|
|
||||||
|
|
||||||
const [btnType, setBtnType] = useState<"reply" | "dismiss" | string>("")
|
|
||||||
|
|
||||||
// 通过
|
|
||||||
const handleApproval = async () => {
|
|
||||||
if (type === "link") {
|
|
||||||
await auditWebDataAPI(item.id);
|
|
||||||
} else if (type === "comment") {
|
|
||||||
await auditCommentDataAPI(item.id);
|
|
||||||
} else if (type === "wall") {
|
|
||||||
await auditWallDataAPI(item.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
btnType != "reply" && message.success('🎉 审核成功');
|
|
||||||
fetchData(type);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 回复
|
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
||||||
const [replyInfo, setReplyInfo] = useState("")
|
|
||||||
const handleReply = async () => {
|
|
||||||
// 审核通过评论
|
|
||||||
await handleApproval()
|
|
||||||
|
|
||||||
// 发送回复内容
|
|
||||||
await addCommentDataAPI({
|
|
||||||
avatar: user.avatar,
|
|
||||||
url: web.url,
|
|
||||||
content: replyInfo,
|
|
||||||
commentId: item?.id!,
|
|
||||||
auditStatus: 1,
|
|
||||||
email: user.email ? user.email : null,
|
|
||||||
name: user.name,
|
|
||||||
articleId: item?.articleId!,
|
|
||||||
createTime: new Date().getTime().toString(),
|
|
||||||
})
|
|
||||||
|
|
||||||
message.success('🎉 回复成功');
|
|
||||||
setIsModalOpen(false)
|
|
||||||
fetchData(type);
|
|
||||||
setReplyInfo("")
|
|
||||||
setBtnType("")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 驳回
|
|
||||||
const [dismissInfo, setDismissInfo] = useState("")
|
|
||||||
const handleDismiss = async () => {
|
|
||||||
if (type === "link") {
|
|
||||||
await delLinkDataAPI(item.id);
|
|
||||||
} else if (type === "comment") {
|
|
||||||
await delCommentDataAPI(item.id);
|
|
||||||
} else if (type === "wall") {
|
|
||||||
await delWallDataAPI(item.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 有内容就发送驳回通知邮件,反之直接删除
|
|
||||||
if (dismissInfo.trim().length) await sendDismissEmail()
|
|
||||||
|
|
||||||
message.success('🎉 驳回成功');
|
|
||||||
setIsModalOpen(false)
|
|
||||||
fetchData(type);
|
|
||||||
setDismissInfo("")
|
|
||||||
setBtnType("")
|
|
||||||
};
|
|
||||||
|
|
||||||
// 发送驳回通知邮件
|
|
||||||
const sendDismissEmail = async () => {
|
|
||||||
// 类型名称
|
|
||||||
let email_info = {
|
|
||||||
name: "",
|
|
||||||
type: "",
|
|
||||||
url: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case "link":
|
|
||||||
email_info = {
|
|
||||||
name: item.title,
|
|
||||||
type: "友链",
|
|
||||||
url: `${web.url}/friend`,
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "comment":
|
|
||||||
email_info = {
|
|
||||||
name: item.name,
|
|
||||||
type: "评论",
|
|
||||||
url: `${web.url}/article/${item.articleId}`,
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "wall":
|
|
||||||
email_info = {
|
|
||||||
name: item.name,
|
|
||||||
type: "留言",
|
|
||||||
url: `${web.url}/wall/all`,
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 有邮箱才会邮件通知
|
|
||||||
item.email != null && await sendDismissEmailAPI({
|
|
||||||
to: item.email,
|
|
||||||
content: dismissInfo,
|
|
||||||
recipient: email_info.name,
|
|
||||||
subject: `${email_info.type}驳回通知`,
|
|
||||||
time: dayjs(Date.now()).format('YYYY年MM月DD日 HH:mm'),
|
|
||||||
type: email_info.type,
|
|
||||||
url: email_info.url
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={item.id}>
|
|
||||||
<div className="text-center text-xs text-[#e0e0e0] mb-4">
|
|
||||||
{dayjs(+item.createTime!).format('YYYY-MM-DD HH:mm:ss')}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-between md:p-7 rounded-md transition-colors">
|
|
||||||
<div className="flex mr-10">
|
|
||||||
{type !== "wall" ? (
|
|
||||||
<img src={item.avatar || item.image} alt="" className="w-13 h-13 border border-[#eee] rounded-full" />
|
|
||||||
) : <RandomAvatar className="w-13 h-13 border border-[#eee] rounded-full" />}
|
|
||||||
|
|
||||||
<div className="flex flex-col justify-center ml-4 px-4 py-2 min-w-[210px] text-xs md:text-sm bg-[#F9F9FD] dark:bg-[#4e5969] rounded-md">
|
|
||||||
{type === "link" ? (
|
|
||||||
<>
|
|
||||||
<div>名称:{item.title}</div>
|
|
||||||
<div>介绍:{item.description}</div>
|
|
||||||
<div>类型:{item.type.name}</div>
|
|
||||||
<div>网站:{item?.url ? <a href={item?.url} target='_blank' className="hover:text-primary font-bold">{item?.url}</a> : '无网站'}</div>
|
|
||||||
</>
|
|
||||||
) : type === "comment" ? (
|
|
||||||
<>
|
|
||||||
<div>名称:{item.name}</div>
|
|
||||||
<div>内容:{item.content}</div>
|
|
||||||
<div>网站:{item?.url ? <a href={item?.url} target='_blank' className="hover:text-primary font-bold">{item?.url}</a> : '无网站'}</div>
|
|
||||||
<div>所属文章:<a href={`${web.url}/article/${item.articleId}`} target='_blank' className="hover:text-primary">{item.articleTitle || '暂无'}</a></div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div>名称:{item.name}</div>
|
|
||||||
<div>内容:{item.content}</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div>邮箱:{item.email || '暂无'}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-end">
|
|
||||||
<Dropdown menu={{
|
|
||||||
items: type === "comment"
|
|
||||||
? [
|
|
||||||
{ key: 'ok', label: "通过", onClick: handleApproval },
|
|
||||||
{ key: 'reply', label: "回复", onClick: () => [setIsModalOpen(true), setBtnType("reply")] },
|
|
||||||
{ key: 'dismiss', label: "驳回", onClick: () => [setIsModalOpen(true), , setBtnType("dismiss")] }
|
|
||||||
]
|
|
||||||
: [
|
|
||||||
{ key: 'ok', label: "通过", onClick: handleApproval },
|
|
||||||
{ key: 'dismiss', label: "驳回", onClick: () => [setIsModalOpen(true), , setBtnType("dismiss")] }
|
|
||||||
]
|
|
||||||
}}>
|
|
||||||
<div className="flex justify-evenly items-center bg-[#F9F9FD] dark:bg-[#4e5969] w-11 h-5 rounded-md cursor-pointer">
|
|
||||||
<span className="inline-block w-2 h-2 bg-[#b5c2d3] rounded-full"></span>
|
|
||||||
<span className="inline-block w-2 h-2 bg-[#b5c2d3] rounded-full"></span>
|
|
||||||
</div>
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Modal title={btnType === "reply" ? "回复内容" : "驳回原因"} open={isModalOpen} footer={null} onCancel={() => setIsModalOpen(false)} onClose={() => setIsModalOpen(false)}>
|
|
||||||
<TextArea
|
|
||||||
value={btnType === "reply" ? replyInfo : dismissInfo}
|
|
||||||
onChange={(e) => (btnType === "reply" ? setReplyInfo(e.target.value) : setDismissInfo(e.target.value))}
|
|
||||||
placeholder={btnType === "reply" ? "请输入回复内容" : "请输入驳回原因"}
|
|
||||||
autoSize={{ minRows: 3, maxRows: 5 }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="flex space-x-4">
|
|
||||||
<Button className="w-full mt-2" onClick={() => setIsModalOpen(false)}>取消</Button>
|
|
||||||
<Button type="primary" className="w-full mt-2" onClick={btnType === "reply" ? handleReply : handleDismiss}>确定</Button>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const WorkPage = () => {
|
|
||||||
const activeSty = "bg-[#f9f9ff] dark:bg-[#3c5370] text-primary";
|
const activeSty = "bg-[#f9f9ff] dark:bg-[#3c5370] text-primary";
|
||||||
const [active, setActive] = useState<Menu>("comment");
|
const [active, setActive] = useState<Menu>("comment");
|
||||||
const [commentList, setCommentList] = useState<any[]>([]);
|
const [commentList, setCommentList] = useState<any[]>([]);
|
||||||
@@ -225,19 +26,26 @@ const WorkPage = () => {
|
|||||||
|
|
||||||
// 重新获取最新数据
|
// 重新获取最新数据
|
||||||
const fetchData = async (type: Menu) => {
|
const fetchData = async (type: Menu) => {
|
||||||
if (type === "comment") {
|
try {
|
||||||
const { data } = await getCommentListAPI({ query: { status: 0 }, pattern: "list" });
|
if (type === "comment") {
|
||||||
setCommentList(data);
|
const { data } = await getCommentListAPI({ query: { status: 0 }, pattern: "list" });
|
||||||
} else if (type === "link") {
|
setCommentList(data);
|
||||||
const { data } = await getLinkListAPI({ query: { status: 0 } });
|
} else if (type === "link") {
|
||||||
setLinkList(data);
|
const { data } = await getLinkListAPI({ query: { status: 0 } });
|
||||||
} else if (type === "wall") {
|
setLinkList(data);
|
||||||
const { data } = await getWallListAPI({ query: { status: 0 } });
|
} else if (type === "wall") {
|
||||||
setWallList(data);
|
const { data } = await getWallListAPI({ query: { status: 0 } });
|
||||||
|
setWallList(data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setLoading(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setLoading(true)
|
||||||
fetchData(active);
|
fetchData(active);
|
||||||
}, [active]);
|
}, [active]);
|
||||||
|
|
||||||
@@ -246,39 +54,40 @@ const WorkPage = () => {
|
|||||||
return <Empty />;
|
return <Empty />;
|
||||||
}
|
}
|
||||||
return list.map(item => (
|
return list.map(item => (
|
||||||
<ListItem key={item.id} item={item} type={type} fetchData={(type) => fetchData(type)} />
|
<List key={item.id} item={item} type={type} fetchData={(type) => fetchData(type)} />
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title value="工作台" />
|
<Title value="工作台" />
|
||||||
<Card className="mt-2 min-h-[calc(100vh-180px)]">
|
|
||||||
<div className="flex flex-col md:flex-row w-full">
|
|
||||||
<div className="w-full min-w-[200px] md:w-2/12 md:min-h-96 mb-5 md:mb-0 pr-4 md:border-b-transparent md:border-r border-[#eee] dark:border-strokedark">
|
|
||||||
<ul className="space-y-1">
|
|
||||||
{(["comment", "link", "wall"] as Menu[]).map((menu) => (
|
|
||||||
<li
|
|
||||||
key={menu}
|
|
||||||
className={`flex items-center w-full py-3 px-4 hover:bg-[#f9f9ff] dark:hover:bg-[#3c5370] hover:text-primary ${active === menu ? activeSty : ''} rounded-md text-base cursor-pointer transition-colors`}
|
|
||||||
onClick={() => setActive(menu)}
|
|
||||||
>
|
|
||||||
<img src={menu === "comment" ? comment : menu === "link" ? link : info} alt="" className="w-8 mr-4" />
|
|
||||||
<span>{menu === "comment" ? "评论" : menu === "link" ? "友联" : "留言"}</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-full md:w-10/12 md:pl-6 py-4 space-y-10">
|
<Spin spinning={loading}>
|
||||||
{active === "link" && renderList(linkList, "link")}
|
<Card className="mt-2 min-h-[calc(100vh-180px)]">
|
||||||
{active === "comment" && renderList(commentList, "comment")}
|
<div className="flex flex-col md:flex-row w-full">
|
||||||
{active === "wall" && renderList(wallList, "wall")}
|
<div className="w-full min-w-[200px] md:w-2/12 md:min-h-96 mb-5 md:mb-0 pr-4 md:border-b-transparent md:border-r border-[#eee] dark:border-strokedark">
|
||||||
|
<ul className="space-y-1">
|
||||||
|
{(["comment", "link", "wall"] as Menu[]).map((menu) => (
|
||||||
|
<li
|
||||||
|
key={menu}
|
||||||
|
className={`flex items-center w-full py-3 px-4 hover:bg-[#f9f9ff] dark:hover:bg-[#3c5370] hover:text-primary ${active === menu ? activeSty : ''} rounded-md text-base cursor-pointer transition-colors`}
|
||||||
|
onClick={() => setActive(menu)}
|
||||||
|
>
|
||||||
|
<img src={menu === "comment" ? comment : menu === "link" ? link : info} alt="" className="w-8 mr-4" />
|
||||||
|
<span>{menu === "comment" ? "评论" : menu === "link" ? "友联" : "留言"}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full md:w-10/12 md:pl-6 py-4 space-y-10">
|
||||||
|
{active === "link" && renderList(linkList, "link")}
|
||||||
|
{active === "comment" && renderList(commentList, "comment")}
|
||||||
|
{active === "wall" && renderList(wallList, "wall")}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Card>
|
||||||
</Card>
|
</Spin>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WorkPage;
|
|
||||||
Reference in New Issue
Block a user