优化:按钮 Loading 效果 优化用户体验

This commit is contained in:
宇阳
2024-11-22 14:40:15 +08:00
parent eee0761473
commit afc74983ad
14 changed files with 89 additions and 69 deletions

View File

@@ -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>

View File

@@ -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>
</>

View File

@@ -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>

View File

@@ -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>
</>
);

View File

@@ -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>

View File

@@ -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 (

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"

View File

@@ -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>

View File

@@ -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>
</>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>