feat: 实现时间线拖拽排序功能及PWA支持
Some checks failed
test/timeline-frontend/pipeline/head Something is wrong with the build of this commit
Some checks failed
test/timeline-frontend/pipeline/head Something is wrong with the build of this commit
新增时间线节点的拖拽排序功能,使用dnd-kit库实现可排序网格布局。添加PWA支持,包括Service Worker注册和manifest配置。优化移动端适配,改进批量操作工具栏和撤销/重做功能。 重构用户登录和注册页面,修复登录跳转逻辑。调整画廊视图在不同设备上的显示效果。新增协作成员管理功能,支持批量修改权限。 修复请求错误处理中的跳转逻辑问题,避免重复跳转登录页。优化样式表,增强时间线卡片和图片展示的响应式布局。 新增多个API接口支持批量操作,包括排序、删除和时间修改。引入useBatchSelection和useHistory自定义Hook管理状态。添加UndoRedoToolbar组件提供撤销/重做功能。 实现Service Worker离线缓存策略,支持静态资源和API请求的缓存。新增PWA工具函数处理安装提示和更新检测。优化移动端交互,调整组件布局和操作按钮。
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Footer } from '@/components';
|
||||
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
|
||||
import { loginUser } from '@/services/user/api';
|
||||
import { CommonResponse } from '@/types/common';
|
||||
import {
|
||||
AlipayCircleOutlined,
|
||||
LockOutlined,
|
||||
@@ -14,14 +15,19 @@ import {
|
||||
ProFormCheckbox,
|
||||
ProFormText,
|
||||
} from '@ant-design/pro-components';
|
||||
import { FormattedMessage, Helmet, SelectLang, useIntl, useModel, history, useRequest } from '@umijs/max';
|
||||
import { Alert, message, Tabs } from 'antd';
|
||||
import {
|
||||
FormattedMessage,
|
||||
Helmet,
|
||||
history,
|
||||
SelectLang,
|
||||
useIntl,
|
||||
useModel,
|
||||
useRequest,
|
||||
} from '@umijs/max';
|
||||
import { Alert, message } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import React, { useState } from 'react';
|
||||
import { flushSync } from 'react-dom';
|
||||
import Settings from '../../../../config/defaultSettings';
|
||||
import { loginUser } from '@/services/user/api';
|
||||
import { CommonResponse } from '@/types/common';
|
||||
|
||||
const useStyles = createStyles(({ token }) => {
|
||||
return {
|
||||
@@ -103,33 +109,35 @@ const Login: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
// 使用元组参数签名以匹配 useRequest 重载,避免被分页重载推断
|
||||
const { loading: submitting, run: login } = useRequest<CommonResponse<UserLoginResult>, [UserLoginParams]>(
|
||||
(params: UserLoginParams): Promise<CommonResponse<UserLoginResult>> => loginUser(params),
|
||||
{
|
||||
manual: true,
|
||||
formatResult: (res) => res,
|
||||
onSuccess: async (response: CommonResponse<UserLoginResult>, params: [UserLoginParams]) => {
|
||||
console.log('登录成功 - response:', response, 'params:', params);
|
||||
const [loginParams] = params;
|
||||
const logStatus = { type: loginParams.loginType };
|
||||
if (response.code === 200) {
|
||||
const defaultLoginSuccessMessage = intl.formatMessage({
|
||||
id: 'pages.login.success',
|
||||
defaultMessage: '登录成功!',
|
||||
});
|
||||
message.success(defaultLoginSuccessMessage);
|
||||
// await fetchUserInfo();
|
||||
localStorage.setItem('timeline_user', JSON.stringify(response.data))
|
||||
const urlParams = new URL(window.location.href).searchParams;
|
||||
window.location.href = urlParams.get('redirect')?.split('?redirect=')[1] || '/';
|
||||
return;
|
||||
}
|
||||
console.log(response.message);
|
||||
// 如果失败去设置用户错误信息
|
||||
setUserLoginState(response.message as any);
|
||||
const { loading: submitting, run: login } = useRequest<
|
||||
CommonResponse<UserLoginResult>,
|
||||
[UserLoginParams]
|
||||
>((params: UserLoginParams): Promise<CommonResponse<UserLoginResult>> => loginUser(params), {
|
||||
manual: true,
|
||||
formatResult: (res) => res,
|
||||
onSuccess: async (response: CommonResponse<UserLoginResult>, params: [UserLoginParams]) => {
|
||||
console.log('登录成功 - response:', response, 'params:', params);
|
||||
const [loginParams] = params;
|
||||
const logStatus = { type: loginParams.loginType };
|
||||
if (response.code === 200) {
|
||||
const defaultLoginSuccessMessage = intl.formatMessage({
|
||||
id: 'pages.login.success',
|
||||
defaultMessage: '登录成功!',
|
||||
});
|
||||
message.success(defaultLoginSuccessMessage);
|
||||
// await fetchUserInfo();
|
||||
localStorage.setItem('timeline_user', JSON.stringify(response.data));
|
||||
const urlParams = new URL(window.location.href).searchParams;
|
||||
// 修复:直接使用 redirect 参数,如果不存在则跳转到首页
|
||||
const redirect = urlParams.get('redirect');
|
||||
window.location.href = redirect || '/';
|
||||
return;
|
||||
}
|
||||
console.log(response.message);
|
||||
// 如果失败去设置用户错误信息
|
||||
setUserLoginState(response.message as any);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
const handleSubmit = async (values: API.LoginParams) => {
|
||||
await login(values as UserLoginParams);
|
||||
@@ -174,9 +182,9 @@ const Login: React.FC = () => {
|
||||
/>,
|
||||
<ActionIcons key="icons" />,
|
||||
]}*/
|
||||
onFinish={async (values) => {
|
||||
await login({ ...values, loginType: type } as UserLoginParams);
|
||||
}}
|
||||
onFinish={async (values) => {
|
||||
await login({ ...values, loginType: type } as UserLoginParams);
|
||||
}}
|
||||
>
|
||||
{/*<Tabs
|
||||
activeKey={type}
|
||||
|
||||
@@ -3,11 +3,15 @@ import { createStyles } from 'antd-style';
|
||||
const useStyles = createStyles(() => {
|
||||
return {
|
||||
registerResult: {
|
||||
width: '800px',
|
||||
width: '100%',
|
||||
maxWidth: '800px',
|
||||
minHeight: '400px',
|
||||
margin: 'auto',
|
||||
padding: '80px',
|
||||
padding: '40px 20px',
|
||||
background: 'none',
|
||||
'@media screen and (min-width: 768px)': {
|
||||
padding: '80px',
|
||||
},
|
||||
},
|
||||
anticon: {
|
||||
fontSize: '64px',
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { registerUser } from '@/services/user/api';
|
||||
import { CommonResponse } from '@/types/common';
|
||||
import { history, Link, useRequest } from '@umijs/max';
|
||||
import { Button, Col, Form, Input, message, Popover, Progress, Row, Select, Space } from 'antd';
|
||||
import { Button, Form, Input, message, Popover, Progress, Select, Space } from 'antd';
|
||||
import type { Store } from 'antd/es/form/interface';
|
||||
import type { FC } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { StateType } from './service';
|
||||
import { fakeRegister } from './service';
|
||||
import useStyles from './style.style';
|
||||
import { registerUser } from '@/services/user/api';
|
||||
import { CommonResponse } from '@/types/common';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { Option } = Select;
|
||||
@@ -23,6 +21,7 @@ const passwordProgressMap: {
|
||||
};
|
||||
const Register: FC = () => {
|
||||
const { styles } = useStyles();
|
||||
const isMobile = useIsMobile();
|
||||
const [count, setCount]: [number, any] = useState(0);
|
||||
const [open, setVisible]: [boolean, any] = useState(false);
|
||||
const [prefix, setPrefix]: [string, any] = useState('86');
|
||||
@@ -95,7 +94,7 @@ const Register: FC = () => {
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
const onFinish = (values: Store) => {
|
||||
// 将表单数据映射为后端需要的格式
|
||||
const registerParams = {
|
||||
@@ -202,7 +201,7 @@ const Register: FC = () => {
|
||||
overlayStyle={{
|
||||
width: 240,
|
||||
}}
|
||||
placement="right"
|
||||
placement={isMobile ? 'top' : 'right'}
|
||||
open={open}
|
||||
>
|
||||
<FormItem
|
||||
|
||||
Reference in New Issue
Block a user