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:
@@ -10,7 +10,8 @@ import {
|
||||
PlayCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { Button, Checkbox, Dropdown, Menu, Spin } from 'antd';
|
||||
import React, { FC, useCallback } from 'react';
|
||||
import React, { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { useIsMobile } from '@/hooks/useIsMobile';
|
||||
import '../index.css';
|
||||
|
||||
interface GridViewProps {
|
||||
@@ -38,7 +39,29 @@ const GridView: FC<GridViewProps> = ({
|
||||
loadingMore,
|
||||
onScroll,
|
||||
}) => {
|
||||
const isMobile = useIsMobile();
|
||||
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => setWindowWidth(window.innerWidth);
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
}, []);
|
||||
|
||||
const getImageSize = useCallback(() => {
|
||||
if (isMobile) {
|
||||
// Mobile: 3 columns for small, 2 columns for large
|
||||
const padding = 16; // page padding
|
||||
const gap = 8; // grid gap
|
||||
if (viewMode === 'large') {
|
||||
const size = (windowWidth - padding * 2 - gap) / 2;
|
||||
return { width: size, height: size };
|
||||
}
|
||||
// default small
|
||||
const size = (windowWidth - padding * 2 - gap * 2) / 3;
|
||||
return { width: size, height: size };
|
||||
}
|
||||
|
||||
switch (viewMode) {
|
||||
case 'small':
|
||||
return { width: 150, height: 150 };
|
||||
@@ -47,7 +70,7 @@ const GridView: FC<GridViewProps> = ({
|
||||
default:
|
||||
return { width: 150, height: 150 };
|
||||
}
|
||||
}, [viewMode]);
|
||||
}, [viewMode, isMobile, windowWidth]);
|
||||
|
||||
const imageSize = getImageSize();
|
||||
|
||||
@@ -103,9 +126,19 @@ const GridView: FC<GridViewProps> = ({
|
||||
<div
|
||||
className={viewMode === 'small' ? 'small-grid-view' : 'large-grid-view'}
|
||||
onScroll={onScroll}
|
||||
style={isMobile ? {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: viewMode === 'large' ? 'repeat(2, 1fr)' : 'repeat(3, 1fr)',
|
||||
gap: '8px',
|
||||
paddingBottom: '20px'
|
||||
} : {}}
|
||||
>
|
||||
{imageList.map((item: ImageItem, index: number) => (
|
||||
<div key={item.instanceId} className="image-card">
|
||||
<div
|
||||
key={item.instanceId}
|
||||
className="image-card"
|
||||
style={isMobile ? { width: '100%', margin: 0 } : {}}
|
||||
>
|
||||
{batchMode && (
|
||||
<Checkbox
|
||||
className="image-checkbox"
|
||||
@@ -116,7 +149,7 @@ const GridView: FC<GridViewProps> = ({
|
||||
<div
|
||||
className="image-wrapper"
|
||||
style={{
|
||||
width: imageSize.width,
|
||||
width: isMobile ? '100%' : imageSize.width,
|
||||
height: imageSize.height,
|
||||
backgroundImage: `url(${getImageUrl(item, false)})`,
|
||||
backgroundSize: 'cover',
|
||||
@@ -130,7 +163,7 @@ const GridView: FC<GridViewProps> = ({
|
||||
onClick={() => !batchMode && onPreview(index)}
|
||||
>
|
||||
{(item.duration || item.thumbnailInstanceId) && (
|
||||
<PlayCircleOutlined style={{ fontSize: '32px', color: 'rgba(255,255,255,0.8)' }} />
|
||||
<PlayCircleOutlined style={{ fontSize: isMobile ? '24px' : '32px', color: 'rgba(255,255,255,0.8)' }} />
|
||||
)}
|
||||
{item.duration && (
|
||||
<span
|
||||
@@ -154,7 +187,7 @@ const GridView: FC<GridViewProps> = ({
|
||||
{item.imageName}
|
||||
</div>
|
||||
<Dropdown overlay={getImageMenu(item)} trigger={['click']}>
|
||||
<Button type="text" icon={<MoreOutlined />} />
|
||||
<Button type="text" icon={<MoreOutlined />} size={isMobile ? "small" : "middle"} />
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user