大改动
This commit is contained in:
@@ -15,27 +15,29 @@ import { useWebStore } from '@/stores';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const ArticlePage = () => {
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const [form] = Form.useForm();
|
||||
const web = useWebStore(state => state.web)
|
||||
|
||||
const [current, setCurrent] = useState<number>(1);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [articleList, setArticleList] = useState<Article[]>([]);
|
||||
|
||||
const [form] = Form.useForm();
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const getArticleList = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const { data } = await getArticleListAPI();
|
||||
setArticleList(data as Article[]);
|
||||
setArticleList(data);
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getArticleList()
|
||||
}, []);
|
||||
|
||||
const delArticleData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
@@ -46,7 +48,6 @@ const ArticlePage = () => {
|
||||
form.resetFields()
|
||||
setCurrent(1)
|
||||
notification.success({ message: '🎉 删除文章成功' })
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -149,7 +150,10 @@ const ArticlePage = () => {
|
||||
},
|
||||
];
|
||||
|
||||
const onSubmit = async (values: FilterForm) => {
|
||||
const onFilterSubmit = async (values: FilterForm) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
const query: FilterArticle = {
|
||||
key: values.title,
|
||||
cateIds: values.cateIds,
|
||||
@@ -161,7 +165,12 @@ const ArticlePage = () => {
|
||||
}
|
||||
|
||||
const { data } = await getArticleListAPI({ query });
|
||||
setArticleList(data as Article[]);
|
||||
setArticleList(data);
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const [cateList, setCateList] = useState<Cate[]>([])
|
||||
@@ -178,16 +187,18 @@ const ArticlePage = () => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getArticleList()
|
||||
getCateList()
|
||||
getTagList()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Title value="文章管理" />
|
||||
|
||||
<Card className='my-2 overflow-scroll'>
|
||||
<Form form={form} layout="inline" onFinish={onSubmit} autoComplete="off" className='flex-nowrap'>
|
||||
<Form form={form} layout="inline" onFinish={onFilterSubmit} autoComplete="off" className='flex-nowrap'>
|
||||
<Form.Item label="标题" name="title" className='min-w-[200px]'>
|
||||
<Input placeholder='请输入关键词' />
|
||||
</Form.Item>
|
||||
@@ -225,7 +236,6 @@ const ArticlePage = () => {
|
||||
rowKey="id"
|
||||
dataSource={articleList}
|
||||
columns={columns as any}
|
||||
loading={loading}
|
||||
scroll={{ x: 'max-content' }}
|
||||
pagination={{
|
||||
position: ['bottomCenter'],
|
||||
@@ -235,10 +245,9 @@ const ArticlePage = () => {
|
||||
setCurrent(current)
|
||||
}
|
||||
}}
|
||||
loading={loading}
|
||||
/>
|
||||
</Card>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ArticlePage;
|
||||
@@ -6,9 +6,10 @@ import { Form, Input, Button, Tree, Modal, Spin, Dropdown, Card, MenuProps, Popc
|
||||
import Title from '@/components/Title';
|
||||
import "./index.scss"
|
||||
|
||||
const CatePage = () => {
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false)
|
||||
const [editLoading, setEditLoading] = useState(false)
|
||||
|
||||
const [isModelOpen, setIsModelOpen] = useState(false);
|
||||
const [cate, setCate] = useState<Cate>({} as Cate);
|
||||
@@ -41,19 +42,22 @@ const CatePage = () => {
|
||||
};
|
||||
|
||||
const editCateData = async (id: number) => {
|
||||
setLoading(true);
|
||||
setIsMethod("edit")
|
||||
setIsModelOpen(true);
|
||||
setEditLoading(true);
|
||||
|
||||
try {
|
||||
setIsMethod("edit")
|
||||
setIsModelOpen(true);
|
||||
const { data } = await getCateDataAPI(id);
|
||||
setIsCateShow(data.type === "cate" ? false : true)
|
||||
setCate(data);
|
||||
|
||||
form.setFieldsValue(data);
|
||||
|
||||
// 判断是分类还是导航
|
||||
setIsCateShow(data.type === "cate" ? false : true)
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
setEditLoading(false);
|
||||
}
|
||||
|
||||
setEditLoading(false);
|
||||
};
|
||||
|
||||
const delCateData = async (id: number) => {
|
||||
@@ -61,8 +65,8 @@ const CatePage = () => {
|
||||
|
||||
try {
|
||||
await delCateDataAPI(id);
|
||||
await getCateList();
|
||||
message.success('🎉 删除分类成功');
|
||||
getCateList();
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -83,17 +87,19 @@ const CatePage = () => {
|
||||
message.success('🎉 新增分类成功');
|
||||
}
|
||||
|
||||
await getCateList();
|
||||
|
||||
// 初始化表单状态
|
||||
form.resetFields();
|
||||
setCate({} as Cate);
|
||||
|
||||
setIsModelOpen(false);
|
||||
getCateList();
|
||||
setIsMethod("create")
|
||||
})
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
const closeModel = () => {
|
||||
@@ -153,7 +159,7 @@ const CatePage = () => {
|
||||
<Tree defaultExpandAll={true} treeData={treeData(list)} />
|
||||
</Spin>
|
||||
|
||||
<Modal title={isMethod === "edit" ? "编辑分类" : "新增分类"} open={isModelOpen} onCancel={closeModel} destroyOnClose footer={null}>
|
||||
<Modal loading={editLoading} title={isMethod === "edit" ? "编辑分类" : "新增分类"} open={isModelOpen} onCancel={closeModel} destroyOnClose footer={null}>
|
||||
<Form form={form} layout="vertical" initialValues={cate} size='large' preserve={false} className='mt-6'>
|
||||
<Form.Item label="名称" name="name" rules={[{ required: true, message: '分类名称不能为空' }]}>
|
||||
<Input placeholder="请输入分类名称" />
|
||||
@@ -196,5 +202,3 @@ const CatePage = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CatePage;
|
||||
@@ -15,11 +15,12 @@ import { useWebStore, useUserStore } from '@/stores'
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const CommentPage = () => {
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const web = useWebStore(state => state.web)
|
||||
const user = useUserStore(state => state.user)
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false);
|
||||
|
||||
const [comment, setComment] = useState<Comment>({} as Comment);
|
||||
@@ -28,21 +29,15 @@ const CommentPage = () => {
|
||||
const [isCommentModalOpen, setIsCommentModalOpen] = useState(false);
|
||||
|
||||
const getCommentList = async () => {
|
||||
try {
|
||||
const { data } = await getCommentListAPI();
|
||||
setList(data)
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const delCommentData = async (id: number) => {
|
||||
setLoading(true)
|
||||
try {
|
||||
await delCommentDataAPI(id);
|
||||
getCommentList();
|
||||
message.success('🎉 删除评论成功');
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
};
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
@@ -119,6 +114,18 @@ const CommentPage = () => {
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const delCommentData = async (id: number) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
await delCommentDataAPI(id);
|
||||
await getCommentList();
|
||||
message.success('🎉 删除评论成功');
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = async (values: FilterForm) => {
|
||||
setLoading(true)
|
||||
|
||||
@@ -135,6 +142,8 @@ const CommentPage = () => {
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// 回复内容
|
||||
@@ -156,18 +165,17 @@ const CommentPage = () => {
|
||||
createTime: new Date().getTime().toString(),
|
||||
})
|
||||
|
||||
await getCommentList()
|
||||
message.success('🎉 回复评论成功');
|
||||
|
||||
setIsReplyModalOpen(false)
|
||||
setReplyInfo("")
|
||||
getCommentList()
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Title value='评论管理' />
|
||||
|
||||
<Card className='my-2 overflow-scroll'>
|
||||
@@ -195,13 +203,13 @@ const CommentPage = () => {
|
||||
rowKey="id"
|
||||
dataSource={list}
|
||||
columns={columns}
|
||||
loading={loading}
|
||||
expandable={{ defaultExpandAllRows: true }}
|
||||
scroll={{ x: 'max-content' }}
|
||||
pagination={{
|
||||
position: ['bottomCenter'],
|
||||
defaultPageSize: 8,
|
||||
}}
|
||||
loading={loading}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -231,9 +239,6 @@ const CommentPage = () => {
|
||||
<Button type="primary" loading={btnLoading} onClick={handleReply} className="w-full mt-2">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommentPage;
|
||||
|
||||
|
||||
@@ -15,6 +15,11 @@ import { Article, Status } from "@/types/app/article";
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
interface Props {
|
||||
data: Article,
|
||||
closeModel: () => void
|
||||
}
|
||||
|
||||
interface FieldType {
|
||||
title: string,
|
||||
createTime: number;
|
||||
@@ -28,7 +33,7 @@ interface FieldType {
|
||||
password: string
|
||||
}
|
||||
|
||||
const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => void }) => {
|
||||
const PublishForm = ({ data, closeModel }: Props) => {
|
||||
const [params] = useSearchParams()
|
||||
const id = +params.get('id')!
|
||||
const isDraftParams = Boolean(params.get('draft'))
|
||||
@@ -167,9 +172,6 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo
|
||||
} as any)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
// 关闭弹框
|
||||
closeModel()
|
||||
@@ -179,6 +181,10 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo
|
||||
isDraft ? navigate("/draft") : navigate("/article")
|
||||
// 初始化表单
|
||||
form.resetFields()
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
@@ -191,7 +197,7 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Form
|
||||
form={form}
|
||||
name="basic"
|
||||
@@ -277,7 +283,7 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,13 +13,13 @@ import { BiSave } from "react-icons/bi";
|
||||
import { AiOutlineEdit, AiOutlineSend } from 'react-icons/ai';
|
||||
import { titleSty } from '@/styles/sty';
|
||||
|
||||
const CreatePage = () => {
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const [params] = useSearchParams()
|
||||
const id = +params.get('id')!
|
||||
const isDraftParams = Boolean(params.get('draft'))
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const [data, setData] = useState<Article>({} as Article)
|
||||
const [content, setContent] = useState('');
|
||||
const [publishOpen, setPublishOpen] = useState(false)
|
||||
@@ -38,6 +38,8 @@ const CreatePage = () => {
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// 回显数据
|
||||
@@ -91,6 +93,9 @@ const CreatePage = () => {
|
||||
|
||||
// 解析接口数据
|
||||
const parsingData = async (command: string) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
const res = await fetch(`/ai/v1/chat/completions`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
@@ -138,6 +143,11 @@ const CreatePage = () => {
|
||||
// 保留最后一行未处理的数据
|
||||
receivedText = lines[lines.length - 1];
|
||||
}
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// AI功能
|
||||
@@ -166,7 +176,7 @@ const CreatePage = () => {
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Title value="创作">
|
||||
<div className='flex items-center space-x-4 w-[360px]'>
|
||||
<Dropdown.Button menu={{ items }}>
|
||||
@@ -196,8 +206,6 @@ const CreatePage = () => {
|
||||
<PublishForm data={data} closeModel={() => setPublishOpen(false)} />
|
||||
</Drawer>
|
||||
</Card >
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreatePage;
|
||||
|
||||
@@ -15,12 +15,12 @@ import { LuImagePlus } from "react-icons/lu";
|
||||
import { RiDeleteBinLine } from "react-icons/ri";
|
||||
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const [params] = useSearchParams()
|
||||
const id = +params.get('id')!
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const [content, setContent] = useState("")
|
||||
const [imageList, setImageList] = useState<string[]>([])
|
||||
|
||||
@@ -61,17 +61,20 @@ export default () => {
|
||||
}
|
||||
|
||||
const getRecordData = async () => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
const { data } = await getRecordDataAPI(id)
|
||||
setContent(data.content)
|
||||
setImageList(JSON.parse(data.images as string))
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// 回显数据
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
// 有Id就回显指定的数据
|
||||
if (id) getRecordData()
|
||||
}, [id])
|
||||
@@ -130,7 +133,7 @@ export default () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Title value="闪念" />
|
||||
|
||||
<Spin spinning={loading}>
|
||||
@@ -172,6 +175,7 @@ export default () => {
|
||||
type="primary"
|
||||
size="large"
|
||||
icon={<BiLogoTelegram className="text-xl" />}
|
||||
loading={loading}
|
||||
className="absolute bottom-4 right-4"
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
@@ -188,6 +192,6 @@ export default () => {
|
||||
}}
|
||||
onCancel={() => setIsModalOpen(false)}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -17,9 +17,12 @@ interface ListItemProps {
|
||||
item: any;
|
||||
type: Menu;
|
||||
fetchData: (type: Menu) => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
}
|
||||
|
||||
export default ({ item, type, fetchData }: ListItemProps) => {
|
||||
export default ({ item, type, fetchData, setLoading }: ListItemProps) => {
|
||||
const [btnLoading, setBtnLoading] = useState<boolean>(false)
|
||||
|
||||
const web = useWebStore(state => state.web)
|
||||
const user = useUserStore(state => state.user)
|
||||
|
||||
@@ -27,6 +30,9 @@ export default ({ item, type, fetchData }: ListItemProps) => {
|
||||
|
||||
// 通过
|
||||
const handleApproval = async () => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
if (type === "link") {
|
||||
await auditWebDataAPI(item.id);
|
||||
} else if (type === "comment") {
|
||||
@@ -35,14 +41,20 @@ export default ({ item, type, fetchData }: ListItemProps) => {
|
||||
await auditWallDataAPI(item.id);
|
||||
}
|
||||
|
||||
await fetchData(type);
|
||||
btnType != "reply" && message.success('🎉 审核成功');
|
||||
fetchData(type);
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
};
|
||||
|
||||
// 回复
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [replyInfo, setReplyInfo] = useState("")
|
||||
const handleReply = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
// 审核通过评论
|
||||
await handleApproval()
|
||||
|
||||
@@ -59,16 +71,24 @@ export default ({ item, type, fetchData }: ListItemProps) => {
|
||||
createTime: new Date().getTime().toString(),
|
||||
})
|
||||
|
||||
await fetchData(type);
|
||||
message.success('🎉 回复成功');
|
||||
setIsModalOpen(false)
|
||||
fetchData(type);
|
||||
setReplyInfo("")
|
||||
setBtnType("")
|
||||
setIsModalOpen(false)
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
// 驳回
|
||||
const [dismissInfo, setDismissInfo] = useState("")
|
||||
const handleDismiss = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
if (type === "link") {
|
||||
await delLinkDataAPI(item.id);
|
||||
} else if (type === "comment") {
|
||||
@@ -80,11 +100,16 @@ export default ({ item, type, fetchData }: ListItemProps) => {
|
||||
// 有内容就发送驳回通知邮件,反之直接删除
|
||||
if (dismissInfo.trim().length) await sendDismissEmail()
|
||||
|
||||
await fetchData(type);
|
||||
message.success('🎉 驳回成功');
|
||||
setIsModalOpen(false)
|
||||
fetchData(type);
|
||||
setDismissInfo("")
|
||||
setBtnType("")
|
||||
setIsModalOpen(false)
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
// 发送驳回通知邮件
|
||||
@@ -202,7 +227,7 @@ export default ({ item, type, fetchData }: ListItemProps) => {
|
||||
|
||||
<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>
|
||||
<Button type="primary" onClick={btnType === "reply" ? handleReply : handleDismiss} loading={btnLoading} className="w-full mt-2">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
|
||||
@@ -54,7 +54,7 @@ export default () => {
|
||||
return <Empty />;
|
||||
}
|
||||
return list.map(item => (
|
||||
<List key={item.id} item={item} type={type} fetchData={(type) => fetchData(type)} />
|
||||
<List key={item.id} item={item} type={type} fetchData={(type) => fetchData(type)} setLoading={setLoading} />
|
||||
));
|
||||
};
|
||||
|
||||
@@ -62,7 +62,6 @@ export default () => {
|
||||
<>
|
||||
<Title value="工作台" />
|
||||
|
||||
<Spin spinning={loading}>
|
||||
<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">
|
||||
@@ -80,14 +79,16 @@ export default () => {
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<Spin spinning={loading}>
|
||||
<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>
|
||||
</Spin>
|
||||
</div>
|
||||
</Card>
|
||||
</Spin>
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user