优化:按钮 Loading 效果 优化用户体验
This commit is contained in:
@@ -8,6 +8,8 @@ import "./index.scss"
|
||||
|
||||
const CatePage = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false)
|
||||
|
||||
const [isModelOpen, setIsModelOpen] = useState(false);
|
||||
const [cate, setCate] = useState<Cate>({} as Cate);
|
||||
const [list, setList] = useState<Cate[]>([]);
|
||||
@@ -21,6 +23,11 @@ const CatePage = () => {
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getCateList();
|
||||
}, []);
|
||||
|
||||
const addCateData = (id: number) => {
|
||||
setIsMethod("create")
|
||||
setIsModelOpen(true);
|
||||
@@ -52,6 +59,8 @@ const CatePage = () => {
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Cate) => {
|
||||
if (values.type === "cate") values.url = '/'
|
||||
|
||||
@@ -71,6 +80,8 @@ const CatePage = () => {
|
||||
getCateList();
|
||||
setIsMethod("create")
|
||||
})
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
const closeModel = () => {
|
||||
@@ -119,11 +130,6 @@ const CatePage = () => {
|
||||
})
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getCateList();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title value="分类管理">
|
||||
@@ -169,9 +175,8 @@ const CatePage = () => {
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item className='!mb-0 flex justify-end'>
|
||||
<Button onClick={closeModel}>取消</Button>
|
||||
<Button type="primary" onClick={submit} className='ml-2'>确定</Button>
|
||||
<Form.Item className='!mb-0 w-full'>
|
||||
<Button type="primary" onClick={submit} loading={btnLoading} className='w-full ml-2'>新增分类</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -31,6 +31,8 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo
|
||||
const [params] = useSearchParams()
|
||||
const id = +params.get('id')!
|
||||
|
||||
const [btnLoading, setBtnLoading] = useState(false)
|
||||
|
||||
const [form] = Form.useForm()
|
||||
const navigate = useNavigate()
|
||||
|
||||
@@ -53,7 +55,6 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo
|
||||
|
||||
form.setFieldsValue({
|
||||
...data,
|
||||
top: data.config.top === 1,
|
||||
status: data.config.status,
|
||||
password: data.config.password,
|
||||
cateIds,
|
||||
@@ -83,6 +84,8 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo
|
||||
};
|
||||
|
||||
const onSubmit: FormProps<FieldType>['onFinish'] = async (values) => {
|
||||
setBtnLoading(true)
|
||||
|
||||
// 如果是文章标签,则先判断是否存在,如果不存在则添加
|
||||
let tagIds: number[] = []
|
||||
for (const item of (values.tagIds ? values.tagIds : [])) {
|
||||
@@ -145,6 +148,8 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo
|
||||
navigate("/article")
|
||||
// 初始化表单
|
||||
form.resetFields()
|
||||
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
// 初始表单数据
|
||||
@@ -222,7 +227,7 @@ const PublishForm = ({ data, closeModel }: { data: Article, closeModel: () => vo
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="w-full">{id ? "编辑文章" : "发布文章"}</Button>
|
||||
<Button type="primary" htmlType="submit" loading={btnLoading} className="w-full">{id ? "编辑文章" : "发布文章"}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</>
|
||||
|
||||
@@ -8,6 +8,8 @@ import dayjs from 'dayjs';
|
||||
|
||||
const FootprintPage = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false)
|
||||
|
||||
const [footprintList, setFootprintList] = useState<Footprint[]>([]);
|
||||
const [isModelOpen, setIsModelOpen] = useState(false);
|
||||
const [footprint, setFootprint] = useState<Footprint>({} as Footprint);
|
||||
@@ -129,6 +131,8 @@ const FootprintPage = () => {
|
||||
};
|
||||
|
||||
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") : []
|
||||
@@ -144,6 +148,8 @@ const FootprintPage = () => {
|
||||
reset()
|
||||
getFootprintList();
|
||||
});
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
const closeModel = () => reset();
|
||||
@@ -229,9 +235,8 @@ const FootprintPage = () => {
|
||||
<DatePicker showTime placeholder='请选择时间' className='w-full' />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item className='!mb-0 flex justify-end'>
|
||||
<Button onClick={closeModel}>取消</Button>
|
||||
<Button type="primary" onClick={onSubmit} className='ml-2'>确定</Button>
|
||||
<Form.Item className='!mb-0 w-full'>
|
||||
<Button type="primary" onClick={onSubmit} loading={btnLoading} className='w-full ml-2'>新增足迹</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -10,6 +10,8 @@ import "./index.scss"
|
||||
const RolePage = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [bindingLoading, setBindingLoading] = useState<boolean>(false);
|
||||
const [addLoading, setAddLoading] = useState(false)
|
||||
|
||||
const [id, setId] = useState(0)
|
||||
const [role, setRole] = useState<Role>({} as Role);
|
||||
const [roleList, setRoleList] = useState<Role[]>([]);
|
||||
@@ -88,6 +90,8 @@ const RolePage = () => {
|
||||
|
||||
const onSubmit = async () => {
|
||||
setLoading(true);
|
||||
setAddLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Role) => {
|
||||
if (role.id) {
|
||||
await editRoleDataAPI({ ...role, ...values });
|
||||
@@ -102,6 +106,8 @@ const RolePage = () => {
|
||||
form.setFieldsValue({ name: '', description: '' })
|
||||
setRole({} as Role);
|
||||
});
|
||||
|
||||
setAddLoading(false)
|
||||
};
|
||||
|
||||
const onChange: any = (list: number[]) => {
|
||||
@@ -151,7 +157,7 @@ const RolePage = () => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="w-full">{role.id ? '编辑角色' : '新增角色'}</Button>
|
||||
<Button type="primary" htmlType="submit" loading={addLoading} className="w-full">{role.id ? '编辑角色' : '新增角色'}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
@@ -186,7 +192,7 @@ const RolePage = () => {
|
||||
</Spin>
|
||||
</div>
|
||||
|
||||
<Button type='primary' className='w-full mt-2' onClick={onBindingRouteSubmit}>保存</Button>
|
||||
<Button type='primary' className='w-full mt-2' loading={bindingLoading} onClick={onBindingRouteSubmit}>保存</Button>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -7,6 +7,8 @@ import { ColumnsType } from 'antd/es/table';
|
||||
|
||||
const RoutePage = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false)
|
||||
|
||||
const [route, setRoute] = useState<Route>({} as Route);
|
||||
const [list, setList] = useState<Route[]>([]);
|
||||
|
||||
@@ -53,6 +55,8 @@ const RoutePage = () => {
|
||||
|
||||
const onSubmit = async () => {
|
||||
setLoading(true);
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Route) => {
|
||||
|
||||
if (route.id) {
|
||||
@@ -68,6 +72,8 @@ const RoutePage = () => {
|
||||
form.setFieldsValue({ path: '', description: '' })
|
||||
setRoute({} as Route);
|
||||
});
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -93,7 +99,7 @@ const RoutePage = () => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="w-full">{route.id ? '编辑路由' : '新增路由'}</Button>
|
||||
<Button type="primary" htmlType="submit" loading={btnLoading} className="w-full">{route.id ? '编辑路由' : '新增路由'}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
@@ -17,19 +17,22 @@ const UserPage = () => {
|
||||
const store = useUserStore();
|
||||
|
||||
const getUserData = async () => {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getUserDataAPI(store.user?.id);
|
||||
store.setUser(data);
|
||||
form.setFieldsValue(data);
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getUserData();
|
||||
}, []);
|
||||
|
||||
const onSubmit = async (values: UserForm) => {
|
||||
setLoading(false)
|
||||
setLoading(true)
|
||||
|
||||
await editUserDataAPI({
|
||||
id: store.user.id, ...values,
|
||||
role: undefined
|
||||
@@ -37,6 +40,8 @@ const UserPage = () => {
|
||||
message.success("🎉 修改用户信息成功");
|
||||
store.setUser(values as User);
|
||||
getUserData();
|
||||
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,12 +2,15 @@ import { Form, Input, Button, notification, Modal } from 'antd';
|
||||
import { useUserStore } from '@/stores';
|
||||
import { editAdminPassAPI } from '@/api/User';
|
||||
import { EditUser } from '@/types/app/user'
|
||||
import { useState } from 'react';
|
||||
|
||||
const { confirm } = Modal;
|
||||
|
||||
const SystemPage = () => {
|
||||
const store = useUserStore();
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const [form] = Form.useForm<EditUser>();
|
||||
|
||||
const initialValues: EditUser = {
|
||||
@@ -33,6 +36,8 @@ const SystemPage = () => {
|
||||
|
||||
const handleSubmit = async (values: EditUser) => {
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
await editAdminPassAPI(values);
|
||||
confirm({
|
||||
title: '提示',
|
||||
@@ -43,7 +48,11 @@ const SystemPage = () => {
|
||||
},
|
||||
cancelButtonProps: { style: { display: 'none' } }
|
||||
});
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
|
||||
notification.error({
|
||||
message: '错误',
|
||||
description: '修改密码失败,请重试:' + error
|
||||
@@ -88,7 +97,7 @@ const SystemPage = () => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="w-full">
|
||||
<Button type="primary" htmlType="submit" loading={loading} className="w-full">
|
||||
保存
|
||||
</Button>
|
||||
</Form.Item>
|
||||
|
||||
@@ -7,6 +7,7 @@ import FileUpload from '@/components/FileUpload';
|
||||
|
||||
const ThemePage = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
const [swiperText, setSwiperText] = useState<string>('');
|
||||
const [social, setSocial] = useState<string>('');
|
||||
@@ -23,15 +24,15 @@ const ThemePage = () => {
|
||||
|
||||
const getLayoutData = async () => {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getThemeDataAPI();
|
||||
setTheme(data);
|
||||
console.log(data);
|
||||
|
||||
|
||||
setSwiperText(data.swiperText ? JSON.parse(data.swiperText).join('\n') : '');
|
||||
setSocial(data.social ? JSON.parse(data.social).join("\n") : '');
|
||||
setCover(data.covers ? JSON.parse(data.covers).join("\n") : '');
|
||||
setRecoArticle(data.recoArticle ? JSON.parse(data.recoArticle).join("\n") : '');
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
@@ -55,6 +56,7 @@ const ThemePage = () => {
|
||||
message: '成功',
|
||||
description: '🎉 修改主题成功',
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
@@ -194,7 +196,7 @@ const ThemePage = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button type="primary" size="large" className="w-full mt-4" onClick={editLayoutData}>修改布局</Button>
|
||||
<Button type="primary" size="large" className="w-full mt-4" loading={loading} onClick={editLayoutData}>修改布局</Button>
|
||||
</div>
|
||||
</Spin>
|
||||
|
||||
|
||||
@@ -65,22 +65,6 @@ const WebPage = () => {
|
||||
<Input placeholder="https://liuyuyang.net/favicon.ico" />
|
||||
</Form.Item>
|
||||
|
||||
{/* <Form.Item
|
||||
label="光亮主题LOGO"
|
||||
name="lightLogo"
|
||||
rules={[{ required: true, message: '网站LOGO不能为空' }]}
|
||||
>
|
||||
<Input placeholder="https://liuyuyang.net/logo.png" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="暗黑主题LOGO"
|
||||
name="darkLogo"
|
||||
rules={[{ required: true, message: '网站LOGO不能为空' }]}
|
||||
>
|
||||
<Input placeholder="https://liuyuyang.net/logo.png" />
|
||||
</Form.Item> */}
|
||||
|
||||
<Form.Item
|
||||
label="网站描述"
|
||||
name="description"
|
||||
@@ -97,28 +81,6 @@ const WebPage = () => {
|
||||
<Input placeholder="Java,前端,Python" />
|
||||
</Form.Item>
|
||||
|
||||
{/* <Form.Item
|
||||
label="随机文章封面"
|
||||
name="covers"
|
||||
rules={[{ required: true, message: '网站随机封面不能为空' }]}
|
||||
>
|
||||
<Input.TextArea
|
||||
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||
placeholder="随机文章封面"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="社交网站"
|
||||
name="social"
|
||||
rules={[{ required: true, message: '社交网站不能为空' }]}
|
||||
>
|
||||
<Input.TextArea
|
||||
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||
placeholder="社交账号"
|
||||
/>
|
||||
</Form.Item> */}
|
||||
|
||||
<Form.Item
|
||||
label="底部信息"
|
||||
name="footer"
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Card } from 'antd';
|
||||
import Title from '@/components/Title';
|
||||
import System from './components/System'
|
||||
import Web from './components/Web'
|
||||
import Layout from './components/Theme'
|
||||
import Theme from './components/Theme'
|
||||
import My from './components/My'
|
||||
// import Other from './components/Other'
|
||||
|
||||
@@ -80,7 +80,7 @@ const SetupPage = () => {
|
||||
<div className='w-full md:w-[80%] px-0 md:px-8'>
|
||||
{active === "system" && <System />}
|
||||
{active === "web" && <Web />}
|
||||
{active === "layout" && <Layout />}
|
||||
{active === "layout" && <Theme />}
|
||||
{active === "my" && <My />}
|
||||
{/* {active === "other" && <Other />} */}
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,8 @@ import FileUpload from '@/components/FileUpload';
|
||||
|
||||
const SwiperPage = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false)
|
||||
|
||||
const [swiper, setSwiper] = useState<Swiper>({} as Swiper);
|
||||
const [list, setList] = useState<Swiper[]>([]);
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
@@ -62,7 +64,8 @@ const SwiperPage = () => {
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
setLoading(true);
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Swiper) => {
|
||||
if (swiper.id) {
|
||||
await editSwiperDataAPI({ ...swiper, ...values });
|
||||
@@ -77,6 +80,8 @@ const SwiperPage = () => {
|
||||
form.resetFields();
|
||||
setSwiper({} as Swiper);
|
||||
})
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
const handleTabChange = (key: string) => {
|
||||
@@ -141,7 +146,7 @@ const SwiperPage = () => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="w-full">{swiper.id ? '编辑轮播图' : '新增轮播图'}</Button>
|
||||
<Button type="primary" htmlType="submit" loading={btnLoading} className="w-full">{swiper.id ? '编辑轮播图' : '新增轮播图'}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ColumnsType } from 'antd/es/table';
|
||||
|
||||
const TagPage = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const [tag, setTag] = useState<Tag>({} as Tag);
|
||||
const [list, setList] = useState<Tag[]>([]);
|
||||
|
||||
@@ -87,7 +88,7 @@ const TagPage = () => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="w-full">{tag.id ? '编辑标签' : '新增标签'}</Button>
|
||||
<Button type="primary" htmlType="submit" loading={loading} className="w-full">{tag.id ? '编辑标签' : '新增标签'}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
@@ -14,6 +14,7 @@ import dayjs from 'dayjs';
|
||||
|
||||
const UserPage = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false)
|
||||
|
||||
const [userList, setUserList] = useState<User[]>([]);
|
||||
const [roleList, setRoleList] = useState<Role[]>([]);
|
||||
@@ -143,6 +144,8 @@ const UserPage = () => {
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
userForm.validateFields().then(async (values: User) => {
|
||||
if (user.id) {
|
||||
await editUserDataAPI({ ...user, ...values });
|
||||
@@ -154,6 +157,8 @@ const UserPage = () => {
|
||||
setDrawerVisible(false);
|
||||
getUserList();
|
||||
})
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
const [filterForm] = Form.useForm();
|
||||
@@ -272,7 +277,7 @@ const UserPage = () => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="w-full">{user.id ? "编辑用户" : "创建用户"}</Button>
|
||||
<Button type="primary" htmlType="submit" loading={btnLoading} className="w-full">{user.id ? "编辑用户" : "创建用户"}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Drawer>
|
||||
|
||||
@@ -9,6 +9,8 @@ import './index.scss';
|
||||
|
||||
const LinkPage = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false)
|
||||
|
||||
const [tab, setTab] = useState<string>('list');
|
||||
const [list, setList] = useState<Web[]>([]);
|
||||
const [listTemp, setListTemp] = useState<Web[]>([]);
|
||||
@@ -72,9 +74,9 @@ const LinkPage = () => {
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
form.validateFields().then(async (values: Web) => {
|
||||
setLoading(true);
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Web) => {
|
||||
if (isMethod === "edit") {
|
||||
await editLinkDataAPI({ ...link, ...values });
|
||||
message.success('🎉 编辑网站成功');
|
||||
@@ -87,6 +89,8 @@ const LinkPage = () => {
|
||||
setTab('list');
|
||||
reset()
|
||||
});
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
const { Option } = Select;
|
||||
@@ -190,7 +194,7 @@ const LinkPage = () => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className='w-full'>{isMethod === "edit" ? '编辑网站' : '新增网站'}</Button>
|
||||
<Button type="primary" htmlType="submit" loading={btnLoading} className='w-full'>{isMethod === "edit" ? '编辑网站' : '新增网站'}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user