diff --git a/index.html b/index.html index 1350d84..e90d17b 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,5 @@ - + diff --git a/src/pages/Cate/index.tsx b/src/pages/Cate/index.tsx index 3cb4ac9..6cc4fc2 100644 --- a/src/pages/Cate/index.tsx +++ b/src/pages/Cate/index.tsx @@ -41,20 +41,24 @@ const CatePage = () => { }; const editCateData = async (id: number) => { - setIsMethod("edit") setLoading(true); + setIsMethod("edit") setIsModelOpen(true); - const { data } = await getCateDataAPI(id); - setIsCateShow(data.type === "cate" ? false : true) - setCate(data); + try { + const { data } = await getCateDataAPI(id); + setIsCateShow(data.type === "cate" ? false : true) + setCate(data); - form.setFieldsValue(data); - setLoading(false); + form.setFieldsValue(data); + } catch (error) { + setLoading(false); + } }; const delCateData = async (id: number) => { setLoading(true); + try { await delCateDataAPI(id); message.success('🎉 删除分类成功'); @@ -67,27 +71,29 @@ const CatePage = () => { const submit = async () => { setBtnLoading(true) - form.validateFields().then(async (values: Cate) => { - if (values.type === "cate") values.url = '/' + try { + form.validateFields().then(async (values: Cate) => { + if (values.type === "cate") values.url = '/' - if (isMethod === "edit") { - await editCateDataAPI({ ...cate, ...values }); - message.success('🎉 修改分类成功'); - } else { - await addCateDataAPI({ ...cate, ...values }); - message.success('🎉 新增分类成功'); - } + if (isMethod === "edit") { + await editCateDataAPI({ ...cate, ...values }); + message.success('🎉 修改分类成功'); + } else { + await addCateDataAPI({ ...cate, ...values }); + message.success('🎉 新增分类成功'); + } - // 初始化表单状态 - form.resetFields(); - setCate({} as Cate); + // 初始化表单状态 + form.resetFields(); + setCate({} as Cate); - setIsModelOpen(false); - getCateList(); - setIsMethod("create") - }) - - setBtnLoading(false) + setIsModelOpen(false); + getCateList(); + setIsMethod("create") + }) + } catch (error) { + setBtnLoading(false) + } }; const closeModel = () => { diff --git a/src/pages/Comment/index.tsx b/src/pages/Comment/index.tsx index 2aa62f1..a8b597a 100644 --- a/src/pages/Comment/index.tsx +++ b/src/pages/Comment/index.tsx @@ -20,6 +20,8 @@ const CommentPage = () => { const user = useUserStore(state => state.user) const [loading, setLoading] = useState(false); + const [btnLoading, setBtnLoading] = useState(false); + const [comment, setComment] = useState({} as Comment); const [list, setList] = useState([]); @@ -27,16 +29,19 @@ const CommentPage = () => { const getCommentList = async () => { const { data } = await getCommentListAPI(); - setList(data) setLoading(false) } const delCommentData = async (id: number) => { setLoading(true) - await delCommentDataAPI(id); - getCommentList(); - message.success('🎉 删除评论成功'); + try { + await delCommentDataAPI(id); + getCommentList(); + message.success('🎉 删除评论成功'); + } catch (error) { + setLoading(false) + } }; useEffect(() => { @@ -115,38 +120,50 @@ const CommentPage = () => { const { RangePicker } = DatePicker; const onSubmit = async (values: FilterForm) => { - const query: FilterData = { - key: values?.title, - content: values?.content, - startDate: values.createTime && values.createTime[0].valueOf() + '', - endDate: values.createTime && values.createTime[1].valueOf() + '' - } + setLoading(true) - const { data } = await getCommentListAPI({ query }); - setList(data) + try { + const query: FilterData = { + key: values?.title, + content: values?.content, + startDate: values.createTime && values.createTime[0].valueOf() + '', + endDate: values.createTime && values.createTime[1].valueOf() + '' + } + + const { data } = await getCommentListAPI({ query }); + setList(data) + } catch (error) { + setLoading(false) + } } // 回复内容 const [replyInfo, setReplyInfo] = useState("") const [isReplyModalOpen, setIsReplyModalOpen] = useState(false); const handleReply = async () => { - await addCommentDataAPI({ - avatar: user.avatar, - url: web.url, - content: replyInfo, - commentId: comment?.id!, - auditStatus: 1, - email: user.email, - name: user.name, - articleId: comment?.articleId!, - createTime: new Date().getTime().toString(), - }) + setBtnLoading(true) - message.success('🎉 回复评论成功'); + try { + await addCommentDataAPI({ + avatar: user.avatar, + url: web.url, + content: replyInfo, + commentId: comment?.id!, + auditStatus: 1, + email: user.email, + name: user.name, + articleId: comment?.articleId!, + createTime: new Date().getTime().toString(), + }) - setIsReplyModalOpen(false) - setReplyInfo("") - getCommentList() + message.success('🎉 回复评论成功'); + + setIsReplyModalOpen(false) + setReplyInfo("") + getCommentList() + } catch (error) { + setBtnLoading(false) + } } return ( @@ -198,7 +215,7 @@ const CommentPage = () => {
内容: {comment?.content}
- + setIsReplyModalOpen(false)}> @@ -211,7 +228,7 @@ const CommentPage = () => {
- +
diff --git a/src/pages/Create/components/Editor/index.tsx b/src/pages/Create/components/Editor/index.tsx index 57bed86..a093c11 100644 --- a/src/pages/Create/components/Editor/index.tsx +++ b/src/pages/Create/components/Editor/index.tsx @@ -25,22 +25,26 @@ const EditorMD = ({ value, onChange }: Props) => { const uploadImages = async (files: File[]) => { setLoading(true); - // 处理成后端需要的格式 - const formData = new FormData(); - formData.append("dir", "article"); - for (let i = 0; i < files.length; i++) formData.append('files', files[i]) + try { + // 处理成后端需要的格式 + const formData = new FormData(); + formData.append("dir", "article"); + for (let i = 0; i < files.length; i++) formData.append('files', files[i]) - const { data: { code, data } } = await axios.post(`${baseURL}/file`, formData, { - headers: { - "Authorization": `Bearer ${store.token}`, - "Content-Type": "multipart/form-data" - } - }); + const { data: { code, data } } = await axios.post(`${baseURL}/file`, formData, { + headers: { + "Authorization": `Bearer ${store.token}`, + "Content-Type": "multipart/form-data" + } + }); + + // 返回图片信息数组 + return data.map((url: string) => ({ url })); + } catch (error) { + setLoading(false); + } setLoading(false); - - // 返回图片信息数组 - return data.map((url: string) => ({ url })); } return ( diff --git a/src/pages/Create/components/PublishForm/index.tsx b/src/pages/Create/components/PublishForm/index.tsx index f6ea628..62d4857 100644 --- a/src/pages/Create/components/PublishForm/index.tsx +++ b/src/pages/Create/components/PublishForm/index.tsx @@ -93,79 +93,82 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo const onSubmit = async (values: FieldType, isDraft?: boolean) => { setBtnLoading(true) - console.log(values); - values.isEncrypt = values.isEncrypt ? 1 : 0 + try { + values.isEncrypt = values.isEncrypt ? 1 : 0 - // 如果是文章标签,则先判断是否存在,如果不存在则添加 - let tagIds: number[] = [] - for (const item of (values.tagIds ? values.tagIds : [])) { - if (typeof item === "string") { - // 如果已经有这个标签了,就没必要再创建一个了 - // 先转换为大写进行查找,否则会出现大小写不匹配问题 - const tag1 = tagList.find(t => t.name.toUpperCase() === item.toUpperCase())?.id; + // 如果是文章标签,则先判断是否存在,如果不存在则添加 + let tagIds: number[] = [] + for (const item of (values.tagIds ? values.tagIds : [])) { + if (typeof item === "string") { + // 如果已经有这个标签了,就没必要再创建一个了 + // 先转换为大写进行查找,否则会出现大小写不匹配问题 + const tag1 = tagList.find(t => t.name.toUpperCase() === item.toUpperCase())?.id; - if (tag1) { - tagIds.push(tag1) - continue + if (tag1) { + tagIds.push(tag1) + continue + } + + await addTagDataAPI({ name: item }); + const { data: list } = await getTagListAPI(); + // 添加成功后查找对应的标签id + const tag2 = list.find(t => t.name === item)?.id; + if (tag2) tagIds.push(tag2); + } else { + tagIds.push(item); } - - await addTagDataAPI({ name: item }); - const { data: list } = await getTagListAPI(); - // 添加成功后查找对应的标签id - const tag2 = list.find(t => t.name === item)?.id; - if (tag2) tagIds.push(tag2); - } else { - tagIds.push(item); } - } - values.createTime = values.createTime.valueOf() - values.cateIds = [...new Set(values.cateIds?.flat())] + values.createTime = values.createTime.valueOf() + values.cateIds = [...new Set(values.cateIds?.flat())] - if (id && !isDraftParams) { - await editArticleDataAPI({ - id, - ...values, - content: data.content, - tagIds: tagIds.join(','), - config: { - status: values.status, - password: values.password - } - } as any) - message.success("🎉 编辑成功") - } else { - if (!isDraftParams) { - await addArticleDataAPI({ - id, - ...values, - content: data.content, - tagIds: tagIds.join(','), - isDraft: isDraft ? 1 : 0, - isDel: 0, - isEncrypt: 0, - config: { - status: values.status, - password: values.password - }, - createTime: values.createTime.toString() - }) - - isDraft ? message.success("🎉 保存为草稿成功") : message.success("🎉 发布成功") - } else { - // 修改草稿状态为发布文章 + if (id && !isDraftParams) { await editArticleDataAPI({ id, ...values, content: data.content, tagIds: tagIds.join(','), - isDraft: isDraft ? 1 : 0, config: { status: values.status, password: values.password } } as any) + message.success("🎉 编辑成功") + } else { + if (!isDraftParams) { + await addArticleDataAPI({ + id, + ...values, + content: data.content, + tagIds: tagIds.join(','), + isDraft: isDraft ? 1 : 0, + isDel: 0, + isEncrypt: 0, + config: { + status: values.status, + password: values.password + }, + createTime: values.createTime.toString() + }) + + isDraft ? message.success("🎉 保存为草稿成功") : message.success("🎉 发布成功") + } else { + // 修改草稿状态为发布文章 + await editArticleDataAPI({ + id, + ...values, + content: data.content, + tagIds: tagIds.join(','), + isDraft: isDraft ? 1 : 0, + config: { + status: values.status, + password: values.password + } + } as any) + } } + } catch (error) { + setBtnLoading(false) } // 关闭弹框 @@ -176,7 +179,6 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo isDraft ? navigate("/draft") : navigate("/article") // 初始化表单 form.resetFields() - setBtnLoading(false) } diff --git a/src/pages/Create/index.tsx b/src/pages/Create/index.tsx index 436f981..96de887 100644 --- a/src/pages/Create/index.tsx +++ b/src/pages/Create/index.tsx @@ -18,6 +18,8 @@ const CreatePage = () => { const id = +params.get('id')! const isDraftParams = Boolean(params.get('draft')) + const [loading, setLoading] = useState(false) + const [data, setData] = useState
({} as Article) const [content, setContent] = useState(''); const [publishOpen, setPublishOpen] = useState(false) @@ -29,13 +31,18 @@ const CreatePage = () => { // 获取文章数据 const getArticleData = async () => { - const { data } = await getArticleDataAPI(id) - setData(data) - setContent(data.content) + try { + const { data } = await getArticleDataAPI(id) + setData(data) + setContent(data.content) + } catch (error) { + setLoading(false) + } } // 回显数据 useEffect(() => { + setLoading(true) setPublishOpen(false) // 有Id就回显指定的数据 @@ -176,7 +183,7 @@ const CreatePage = () => { - + setContent(value)} /> { const id = +params.get('id')! const navigate = useNavigate() + const [loading, setLoading] = useState(false) + const [content, setContent] = useState("") const [imageList, setImageList] = useState([]) @@ -30,31 +32,42 @@ export default () => { } const onSubmit = async () => { - const data = { - content, - images: JSON.stringify(imageList), - createTime: new Date().getTime().toString() + setLoading(true) + + try { + const data = { + content, + images: JSON.stringify(imageList), + createTime: new Date().getTime().toString() + } + + if (!content.trim().length) { + message.error("请输入内容") + return + } + + if (id) { + await editRecordDataAPI({ id, content: data.content, images: data.images }) + } else { + await addRecordDataAPI(data) + } + + navigate("/record") + } catch (error) { + setLoading(false) } - if (!content.trim().length) { - message.error("请输入内容") - return - } - - if (id) { - await editRecordDataAPI({ id, content: data.content, images: data.images }) - } else { - await addRecordDataAPI(data) - } - - navigate("/record") + setLoading(false) } const getRecordData = async () => { + setLoading(true) + const { data } = await getRecordDataAPI(id) - console.log(data, 222); setContent(data.content) setImageList(JSON.parse(data.images as string)) + + setLoading(false) } // 回显数据 @@ -106,7 +119,7 @@ export default () => { message.error('链接必须以 http:// 或 https:// 开头'); return Promise.reject(); } - + setImageList([...imageList, inputUrl]); return Promise.resolve(); } @@ -120,49 +133,51 @@ export default () => { <> - <Card className={`${titleSty} min-h-[calc(100vh-180px)]`}> - <div className="relative flex w-[90%] xl:w-[800px] mx-auto mt-[50px]"> - <TextArea - rows={10} - maxLength={500} - placeholder="记录此刻!" - value={content} - onChange={(e) => setContent(e.target.value)} - className="w-full p-4 border-2 border-[#eee] dark:border-strokedark text-base rounded-md" - /> + <Spin spinning={loading}> + <Card className={`${titleSty} min-h-[calc(100vh-180px)]`}> + <div className="relative flex w-[90%] xl:w-[800px] mx-auto mt-[50px]"> + <TextArea + rows={10} + maxLength={500} + placeholder="记录此刻!" + value={content} + onChange={(e) => setContent(e.target.value)} + className="w-full p-4 border-2 border-[#eee] dark:border-strokedark text-base rounded-md" + /> - <div className="absolute bottom-4 left-4 flex items-end space-x-3 max-w-[calc(100%-80px)]"> - <div className="flex space-x-2 overflow-x-auto scrollbar-hide"> - {imageList.length > 0 && imageList.map((item, index) => ( - <div key={index} className="group overflow-hidden relative shrink-0"> - <div className="absolute top-0 -right-6 group-hover:right-0 z-10 bg-slate-600 rounded-full cursor-pointer p-1" onClick={() => handleDelImage(item)}> - <RiDeleteBinLine className="text-white" /> + <div className="absolute bottom-4 left-4 flex items-end space-x-3 max-w-[calc(100%-80px)]"> + <div className="flex space-x-2 overflow-x-auto scrollbar-hide"> + {imageList.length > 0 && imageList.map((item, index) => ( + <div key={index} className="group overflow-hidden relative shrink-0"> + <div className="absolute top-0 -right-6 group-hover:right-0 z-10 bg-slate-600 rounded-full cursor-pointer p-1" onClick={() => handleDelImage(item)}> + <RiDeleteBinLine className="text-white" /> + </div> + + <Image + key={index} + src={item} + preview={false} + className='rounded-lg md:!w-[100px] md:!h-[100px] xs:!w-20 xs:!h-20 !w-15 !h-15 object-cover' + /> </div> + ))} + </div> - <Image - key={index} - src={item} - preview={false} - className='rounded-lg md:!w-[100px] md:!h-[100px] xs:!w-20 xs:!h-20 !w-15 !h-15 object-cover' - /> - </div> - ))} + <Dropdown menu={dropdownItems} placement="top"> + <LuImagePlus className="mb-1 text-3xl md:text-4xl text-slate-700 dark:text-white hover:text-primary dark:hover:text-primary cursor-pointer shrink-0" /> + </Dropdown> </div> - - <Dropdown menu={dropdownItems} placement="top"> - <LuImagePlus className="mb-1 text-3xl md:text-4xl text-slate-700 dark:text-white hover:text-primary dark:hover:text-primary cursor-pointer shrink-0" /> - </Dropdown> - </div> - <Button - type="primary" - size="large" - icon={<BiLogoTelegram className="text-xl" />} - className="absolute bottom-4 right-4" - onClick={onSubmit} - /> - </div> - </Card> + <Button + type="primary" + size="large" + icon={<BiLogoTelegram className="text-xl" />} + className="absolute bottom-4 right-4" + onClick={onSubmit} + /> + </div> + </Card> + </Spin> <FileUpload dir="record" diff --git a/src/pages/Dashboard/components/Stats/index.tsx b/src/pages/Dashboard/components/Stats/index.tsx index e524381..47a36a2 100644 --- a/src/pages/Dashboard/components/Stats/index.tsx +++ b/src/pages/Dashboard/components/Stats/index.tsx @@ -5,17 +5,20 @@ import CardDataStats from "@/components/CardDataStats" import { AiOutlineEye, AiOutlineMeh, AiOutlineStock, AiOutlineFieldTime } from "react-icons/ai"; import { useEffect, useState } from "react" import dayjs from 'dayjs'; +import { Spin } from "antd"; export default () => { + const [loading, setLoading] = useState(false) + const [stats, setStats] = useState({ pv: 0, ip: 0, bounce: 0, avgTime: "", }); - + const date = dayjs(new Date()).format("YYYY/MM/DD"); - + const formatTime = (seconds: number) => { // 四舍五入到最接近的整数 const roundedSeconds = Math.round(seconds); @@ -28,49 +31,58 @@ export default () => { // 获取统计数据 const getDataList = async () => { - const siteId = import.meta.env.VITE_BAIDU_TONGJI_SITE_ID; - const token = import.meta.env.VITE_BAIDU_TONGJI_ACCESS_TOKEN; + setLoading(true) - const response = await fetch(`/baidu/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${date}&end_date=${date}&metrics=pv_count%2Cip_count%2Cbounce_ratio%2Cavg_visit_time&method=overview%2FgetTimeTrendRpt`); - const data = await response.json(); - const { result } = data; + try { + const siteId = import.meta.env.VITE_BAIDU_TONGJI_SITE_ID; + const token = import.meta.env.VITE_BAIDU_TONGJI_ACCESS_TOKEN; - let pv = 0; - let ip = 0; - let bounce = 0; - let avgTime = 0; - let count = 0 + const response = await fetch(`/baidu/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${date}&end_date=${date}&metrics=pv_count%2Cip_count%2Cbounce_ratio%2Cavg_visit_time&method=overview%2FgetTimeTrendRpt`); + const data = await response.json(); + const { result } = data; - result.items[1].forEach((item: number[]) => { - if (!Number(item[0])) return; + let pv = 0; + let ip = 0; + let bounce = 0; + let avgTime = 0; + let count = 0 - // 检查并累加 pv - if (!isNaN(Number(item[0]))) { - pv += Number(item[0]); - } + result.items[1].forEach((item: number[]) => { + if (!Number(item[0])) return; - // 检查并累加 ip - if (!isNaN(Number(item[1]))) { - ip += Number(item[1]); - } + // 检查并累加 pv + if (!isNaN(Number(item[0]))) { + pv += Number(item[0]); + } - // 检查并累加 bounce - if (!isNaN(Number(item[2]))) { - bounce += Number(item[2]); - } + // 检查并累加 ip + if (!isNaN(Number(item[1]))) { + ip += Number(item[1]); + } - // 检查并累加 avgTime - if (!isNaN(Number(item[3]))) { - avgTime += Number(item[3]); - } + // 检查并累加 bounce + if (!isNaN(Number(item[2]))) { + bounce += Number(item[2]); + } - // 只有第三个和第四个数据都有值时才增加 count - if (!isNaN(Number(item[2])) && !isNaN(Number(item[3]))) { - count++; - } - }); + // 检查并累加 avgTime + if (!isNaN(Number(item[3]))) { + avgTime += Number(item[3]); + } - setStats({ pv, ip, bounce: (bounce / count) || 0, avgTime: formatTime(avgTime / count) || "00:00:00" }) + // 只有第三个和第四个数据都有值时才增加 count + if (!isNaN(Number(item[2])) && !isNaN(Number(item[3]))) { + count++; + } + }); + + setStats({ pv, ip, bounce: (bounce / count) || 0, avgTime: formatTime(avgTime / count) || "00:00:00" }) + + } catch (error) { + setLoading(false) + } + + setLoading(false) }; useEffect(() => { @@ -78,7 +90,7 @@ export default () => { }, []); return ( - <> + <Spin spinning={loading}> {/* 基本数据 */} <div className="mt-2 grid grid-cols-1 gap-2 md:grid-cols-2 xl:grid-cols-4"> <CardDataStats title="今日访客" total={stats.pv + ''} rate="0.43%" levelUp> @@ -104,6 +116,6 @@ export default () => { {/* <ChartTwo /> <ChatCard /> */} </div> - </> + </Spin> ) } \ No newline at end of file diff --git a/src/pages/Decycle/index.tsx b/src/pages/Decycle/index.tsx index a470c8c..9520771 100644 --- a/src/pages/Decycle/index.tsx +++ b/src/pages/Decycle/index.tsx @@ -1,13 +1,13 @@ import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Table, Button, Tag, notification, Card, Popconfirm, Form } from 'antd'; +import { Table, Button, Tag, notification, Card, Popconfirm, Form, Spin } from 'antd'; import { titleSty } from '@/styles/sty' import Title from '@/components/Title'; import { delArticleDataAPI, getArticleListAPI, reductionArticleDataAPI } from '@/api/Article'; import type { Tag as ArticleTag } from '@/types/app/tag'; import type { Cate } from '@/types/app/cate'; -import type { Article, Config } from '@/types/app/article'; +import type { Article } from '@/types/app/article'; import { useWebStore } from '@/stores'; import dayjs from 'dayjs'; @@ -23,33 +23,46 @@ export default () => { const [form] = Form.useForm(); const getArticleList = async () => { - setLoading(true); - const { data } = await getArticleListAPI({ query: { isDel: 1 } }); - setArticleList(data as Article[]); + try { + const { data } = await getArticleListAPI({ query: { isDel: 1 } }); + setArticleList(data as Article[]); + } catch (error) { + setLoading(false); + } + setLoading(false); }; useEffect(() => { + setLoading(true); getArticleList() }, []); const delArticleData = async (id: number) => { setLoading(true); - // 严格删除:彻底从数据库删除,无法恢复 - await delArticleDataAPI(id); - await getArticleList(); - form.resetFields() - setCurrent(1) - notification.success({ message: '🎉 删除文章成功' }) - - setLoading(false); + try { + // 严格删除:彻底从数据库删除,无法恢复 + await delArticleDataAPI(id); + await getArticleList(); + form.resetFields() + setCurrent(1) + notification.success({ message: '🎉 删除文章成功' }) + } catch (error) { + setLoading(false); + } }; const reductionArticleData = async (id: number) => { - await reductionArticleDataAPI(id) - navigate("/article") - notification.success({ message: '🎉 还原文章成功' }) + setLoading(true); + + try { + await reductionArticleDataAPI(id) + navigate("/article") + notification.success({ message: '🎉 还原文章成功' }) + } catch (error) { + setLoading(false); + } } // 标签颜色 diff --git a/src/pages/Draft/index.tsx b/src/pages/Draft/index.tsx index 49dffe0..024103c 100644 --- a/src/pages/Draft/index.tsx +++ b/src/pages/Draft/index.tsx @@ -21,26 +21,32 @@ export default () => { const [form] = Form.useForm(); const getArticleList = async () => { - setLoading(true); - const { data } = await getArticleListAPI({ query: { isDraft: 1 } }); - setArticleList(data as Article[]); - setLoading(false); + try { + const { data } = await getArticleListAPI({ query: { isDraft: 1 } }); + setArticleList(data as Article[]); + } catch (error) { + setLoading(false); + } + setLoading(false) }; useEffect(() => { + setLoading(true) getArticleList() }, []); const delArticleData = async (id: number) => { setLoading(true); - await delArticleDataAPI(id); - await getArticleList(); - form.resetFields() - setCurrent(1) - notification.success({ message: '🎉 删除文章成功' }) - - setLoading(false); + try { + await delArticleDataAPI(id); + await getArticleList(); + form.resetFields() + setCurrent(1) + notification.success({ message: '🎉 删除文章成功' }) + } catch (error) { + setLoading(false); + } }; // 标签颜色 diff --git a/src/pages/File/index.tsx b/src/pages/File/index.tsx index 86b19fa..91c10bd 100644 --- a/src/pages/File/index.tsx +++ b/src/pages/File/index.tsx @@ -34,9 +34,13 @@ export default () => { // 获取目录列表 const getDirList = async () => { - setLoading(true) - const { data } = await getDirListAPI() - setDirList(data) + try { + const { data } = await getDirListAPI() + setDirList(data) + } catch (error) { + setLoading(false) + } + setLoading(false) } @@ -54,13 +58,16 @@ export default () => { const onDeleteImage = async (data: File) => { setLoading(true) - await delFileDataAPI(data.url) - message.success("🎉 删除图片成功") - getFileList(dirName) - setFile({} as File) - - setOpenFileInfoDrawer(false) - setOpenFilePreviewDrawer(false) + try { + await delFileDataAPI(data.url) + message.success("🎉 删除图片成功") + getFileList(dirName) + setFile({} as File) + setOpenFileInfoDrawer(false) + setOpenFilePreviewDrawer(false) + } catch (error) { + setLoading(false) + } } // 下载图片 diff --git a/src/pages/Footprint/index.tsx b/src/pages/Footprint/index.tsx index b08ab50..ec40211 100644 --- a/src/pages/Footprint/index.tsx +++ b/src/pages/Footprint/index.tsx @@ -12,6 +12,7 @@ import axios from 'axios'; const FootprintPage = () => { const [loading, setLoading] = useState<boolean>(false); const [btnLoading, setBtnLoading] = useState(false) + const [modalLoading, setModalLoading] = useState(false) const [footprintList, setFootprintList] = useState<Footprint[]>([]); const [isModelOpen, setIsModelOpen] = useState(false); @@ -86,13 +87,18 @@ const FootprintPage = () => { const { RangePicker } = DatePicker; const getFootprintList = async () => { - setLoading(true); - const { data } = await getFootprintListAPI(); - setFootprintList(data as Footprint[]); + try { + const { data } = await getFootprintListAPI(); + setFootprintList(data as Footprint[]); + } catch (error) { + setLoading(false); + } + setLoading(false); }; useEffect(() => { + setLoading(true); getFootprintList(); }, []); @@ -105,10 +111,14 @@ const FootprintPage = () => { const delFootprintData = async (id: number) => { setLoading(true); - await delFootprintDataAPI(id); - notification.success({ message: '🎉 删除足迹成功' }); - getFootprintList(); - setLoading(false); + + try { + await delFootprintDataAPI(id); + notification.success({ message: '🎉 删除足迹成功' }); + getFootprintList(); + } catch (error) { + setLoading(false); + } }; const addFootprintData = () => { @@ -119,60 +129,78 @@ const FootprintPage = () => { }; const editFootprintData = async (id: number) => { - setIsMethod("edit"); - setLoading(true); - setIsModelOpen(true); + setModalLoading(true); - const { data } = await getFootprintDataAPI(id); + try { + setIsMethod("edit"); + setIsModelOpen(true); - data.images = (data.images as string[]).join("\n") - data.createTime = dayjs(+data.createTime) + const { data } = await getFootprintDataAPI(id); - setFootprint(data); - form.setFieldsValue(data); - setLoading(false); + data.images = (data.images as string[]).join("\n") + data.createTime = dayjs(+data.createTime) + + setFootprint(data); + form.setFieldsValue(data); + } catch (error) { + setModalLoading(false); + } + + setModalLoading(false); }; const onSubmit = async () => { setBtnLoading(true) - form.validateFields().then(async (values: Footprint) => { - values.createTime = values.createTime.valueOf() - values.images = values.images ? (values.images as string).split("\n") : [] + try { + form.validateFields().then(async (values: Footprint) => { + values.createTime = values.createTime.valueOf() + values.images = values.images ? (values.images as string).split("\n") : [] - if (isMethod === "edit") { - await editFootprintDataAPI({ ...footprint, ...values }); - message.success('🎉 修改足迹成功'); - } else { - await addFootprintDataAPI({ ...footprint, ...values }); - message.success('🎉 新增足迹成功'); - } + if (isMethod === "edit") { + await editFootprintDataAPI({ ...footprint, ...values }); + message.success('🎉 修改足迹成功'); + } else { + await addFootprintDataAPI({ ...footprint, ...values }); + message.success('🎉 新增足迹成功'); + } - reset() - getFootprintList(); - }); - - setBtnLoading(false) + reset() + getFootprintList(); + }); + } catch (error) { + setBtnLoading(false) + } }; const closeModel = () => reset(); const onFilterSubmit = async (values: FilterForm) => { - const query: FilterData = { - key: values.address, - startDate: values.createTime && values.createTime[0].valueOf() + '', - endDate: values.createTime && values.createTime[1].valueOf() + '' + setLoading(true) + + try { + const query: FilterData = { + key: values.address, + startDate: values.createTime && values.createTime[0].valueOf() + '', + endDate: values.createTime && values.createTime[1].valueOf() + '' + } + + const { data } = await getFootprintListAPI({ query }); + setFootprintList(data); + } catch (error) { + setLoading(false) } - const { data } = await getFootprintListAPI({ query }); - setFootprintList(data as Footprint[]); + setLoading(false) } // 通过详细地址获取纬度 const getGeocode = async () => { - const address = form.getFieldValue("address") - + setModalLoading(true) + try { + const address = form.getFieldValue("address") + const { data } = await axios.get('https://restapi.amap.com/v3/geocode/geo', { params: { address, @@ -187,16 +215,17 @@ const FootprintPage = () => { // 立即触发校验 form.validateFields(['position']); + setModalLoading(false) + return data.geocodes[0].location; } else { message.warning('未找到该地址的经纬度'); - return ''; } } catch (error) { - console.error('获取地理编码时出错:', error); - message.error('获取地理编码时出错'); - return ''; + setModalLoading(false) } + + }; return ( @@ -237,7 +266,7 @@ const FootprintPage = () => { /> </Card> - <Modal title={isMethod === "edit" ? "编辑足迹" : "新增足迹"} open={isModelOpen} onCancel={closeModel} destroyOnClose footer={null}> + <Modal loading={modalLoading} title={isMethod === "edit" ? "编辑足迹" : "新增足迹"} open={isModelOpen} onCancel={closeModel} destroyOnClose footer={null}> <Form form={form} layout="vertical" initialValues={footprint} size='large' preserve={false} className='mt-6'> <Form.Item label="标题" name="title" rules={[{ required: true, message: '标题不能为空' }]}> <Input placeholder="请输入标题" /> diff --git a/src/pages/Iterative/index.tsx b/src/pages/Iterative/index.tsx index c68018c..89ef16b 100644 --- a/src/pages/Iterative/index.tsx +++ b/src/pages/Iterative/index.tsx @@ -1,4 +1,4 @@ -import { Card, Select, Timeline, TimelineItemProps } from 'antd'; +import { Card, Select, Spin, Timeline, TimelineItemProps } from 'antd'; import { useEffect, useState } from 'react'; import GitHubCalendar from 'react-github-calendar'; import Title from '@/components/Title'; @@ -12,6 +12,8 @@ interface Commit { } const Home = () => { + const [loading, setLoading] = useState<boolean>(false) + const [year, setYear] = useState<number>(new Date().getFullYear()) const [yearList, setYearList] = useState<{ value: number, label: string }[]>([]) @@ -21,32 +23,40 @@ const Home = () => { // 从github获取最近10次迭代记录 const getCommitData = async (project: string) => { - const res = await fetch(`https://api.github.com/repos/LiuYuYang01/${project}/commits?per_page=10`) - const data = await res.json() - const result = data?.map((item: Commit) => ( - { - label: dayjs(item.commit.author.date).format("YYYY-MM-DD HH:mm:ss"), - children: item.commit.message - } - )) + try { + const res = await fetch(`https://api.github.com/repos/LiuYuYang01/${project}/commits?per_page=10`) + const data = await res.json() + const result = data?.map((item: Commit) => ( + { + label: dayjs(item.commit.author.date).format("YYYY-MM-DD HH:mm:ss"), + children: item.commit.message + } + )) - switch (project) { - case "ThriveX-Blog": - sessionStorage.setItem('blog_project_iterative', JSON.stringify(result)) - setBlog_IterativeRecording(result) - break; - case "ThriveX-Admin": - sessionStorage.setItem('admin_project_iterative', JSON.stringify(result)) - setAdmin_IterativeRecording(result) - break; - case "ThriveX-Server": - sessionStorage.setItem('server_project_iterative', JSON.stringify(result)) - setServer_IterativeRecording(result) - break; + switch (project) { + case "ThriveX-Blog": + sessionStorage.setItem('blog_project_iterative', JSON.stringify(result)) + setBlog_IterativeRecording(result) + break; + case "ThriveX-Admin": + sessionStorage.setItem('admin_project_iterative', JSON.stringify(result)) + setAdmin_IterativeRecording(result) + break; + case "ThriveX-Server": + sessionStorage.setItem('server_project_iterative', JSON.stringify(result)) + setServer_IterativeRecording(result) + break; + } + } catch (error) { + setLoading(false) } + + setLoading(false) } useEffect(() => { + setLoading(true) + // 获取当前年份 const currentYear = dayjs().year(); // 生成最近10年的年份数组 @@ -62,48 +72,52 @@ const Home = () => { const server_project_iterative = JSON.parse(sessionStorage.getItem('server_project_iterative') || '[]') server_project_iterative.length ? setServer_IterativeRecording(server_project_iterative) : getCommitData("ThriveX-Server") + + setLoading(false) }, []) return ( <> <Title value='项目迭代记录'> - -
-
- 年份切换: + + +
+
+ 年份切换: - +
+ +
- -
+
+
+
+

ThriveX-Blog

+ +
-
-
-
-

ThriveX-Blog

- -
+
+

ThriveX-Admin

+ +
-
-

ThriveX-Admin

- -
- -
-

ThriveX-Server

- +
+

ThriveX-Server

+ +
-
- + + ); }; diff --git a/src/pages/Login/index.tsx b/src/pages/Login/index.tsx index 6e449d4..66b51b9 100644 --- a/src/pages/Login/index.tsx +++ b/src/pages/Login/index.tsx @@ -7,6 +7,8 @@ import { loginDataAPI } from '@/api/User'; import { useUserStore } from '@/stores'; const LoginPage = () => { + const [loading, setLoading] = useState(false) + const [form] = useForm(); const [isPassVisible, setIsPassVisible] = useState(false); const store = useUserStore(); @@ -15,20 +17,28 @@ const LoginPage = () => { const returnUrl = new URLSearchParams(location.search).get('returnUrl') || '/'; const onSubmit = async () => { - const values = await form.validateFields(); - const { data } = await loginDataAPI(values); + setLoading(true) - // 将用户信息和token保存起来 - store.setToken(data.token); - store.setUser(data.user); - store.setRole(data.role) + try { + const values = await form.validateFields(); + const { data } = await loginDataAPI(values); - notification.success({ - message: '🎉 登录成功', - description: `Hello ${data.user.name} 欢迎回来`, - }); + // 将用户信息和token保存起来 + store.setToken(data.token); + store.setUser(data.user); + store.setRole(data.role) - navigate(returnUrl); + notification.success({ + message: '🎉 登录成功', + description: `Hello ${data.user.name} 欢迎回来`, + }); + + navigate(returnUrl); + } catch (error) { + setLoading(false) + } + + setLoading(false) }; return ( @@ -70,7 +80,7 @@ const LoginPage = () => { - +
diff --git a/src/pages/Oss/index.tsx b/src/pages/Oss/index.tsx index d292813..cee902f 100644 --- a/src/pages/Oss/index.tsx +++ b/src/pages/Oss/index.tsx @@ -9,7 +9,9 @@ import { titleSty } from '@/styles/sty'; const StoragePage = () => { const [loading, setLoading] = useState(false); const [btnLoading, setBtnLoading] = useState(false); + const [modalLoading, setModalLoading] = useState(false) const [isModalOpen, setIsModalOpen] = useState(false); + const [oss, setOss] = useState({} as Oss); const [ossList, setOssList] = useState([]); const [platformList, setPlatformList] = useState<{ label: string, value: string, disabled: boolean }[]>([]); @@ -51,9 +53,9 @@ const StoragePage = () => { render: (_, record: Oss) => (
{record.isEnable ? ( - + ) : ( - + )} @@ -83,44 +85,71 @@ const StoragePage = () => { }; const getOssList = async () => { - setLoading(true); - const { data } = await getOssListAPI(); - setOssList(data); + try { + const { data } = await getOssListAPI(); + setOssList(data); + } catch (error) { + setLoading(false) + } + setLoading(false); }; useEffect(() => { + setLoading(true); getOssList(); getOssPlatformList() }, []); - const handleEnable = async (id: number) => { - await enableOssDataAPI(id); - message.success('启用成功'); - getOssList(); + const enableOssData = async (id: number) => { + try { + await enableOssDataAPI(id); + await getOssList(); + message.success('启用成功'); + } catch (error) { + setLoading(false) + } }; - const handleDisable = async (id: number) => { - await disableOssDataAPI(id); - message.success('禁用成功'); - getOssList(); + const disableOssData = async (id: number) => { + try { + await disableOssDataAPI(id); + await getOssList(); + message.success('禁用成功'); + } catch (error) { + setLoading(false) + } }; const editOssData = async (record: Oss) => { - setOss(record); - const { data } = await getOssDataAPI(record.id) - form.setFieldsValue(data); - setIsModalOpen(true); + setModalLoading(true) + + try { + setIsModalOpen(true); + + const { data } = await getOssDataAPI(record.id) + setOss(data); + form.setFieldsValue(data); + } catch (error) { + setModalLoading(false) + } + + setModalLoading(false) }; const delOssData = async (id: number) => { setLoading(true); - await delOssDataAPI(id); - message.success('🎉 删除存储配置成功'); - getOssList(); + + try { + await delOssDataAPI(id); + await getOssList(); + message.success('🎉 删除存储配置成功'); + } catch (error) { + setLoading(false) + } }; - const handleAdd = () => { + const addOssData = () => { setOss({} as Oss); form.resetFields(); form.setFieldsValue({}); @@ -151,20 +180,22 @@ const StoragePage = () => { form.resetFields(); setBtnLoading(false); } catch (error) { - console.error('表单验证失败:', error); setBtnLoading(false); } + + setBtnLoading(false) }; return ( <> - <Button type="primary" size='large' onClick={handleAdd}>新增配置</Button> + <Button type="primary" size='large' onClick={addOssData}>新增配置</Button> { position: ['bottomCenter'], pageSize: 8 }} - loading={loading} />