feat: 支持视频上传、预览及移动端适配
Some checks failed
test/timeline-frontend/pipeline/head There was a failure building this commit

1. 功能增强:
- 支持视频文件的上传、存储及缩略图自动生成
- 新增视频播放组件,支持在画廊和时间线中预览视频
- 引入 STOMP 协议支持 WebSocket 实时通知功能
- 增加分享页面(SSR 友好),支持通过 shareId 访问公开内容

2. 移动端优化:
- 新增 BottomNav 底部导航组件,优化移动端交互体验
- 引入 useIsMobile 钩子,实现响应式布局切换
- 优化时间线卡片在小屏幕下的显示效果

3. 架构与组件:
- 新增 ClientOnly 组件解决 SSR 激活不一致问题
- 新增 ResponsiveGrid 响应式网格布局组件
- 完善 Nginx 配置,增加 MinIO 对象存储代理
- 优化图片懒加载组件 TimelineImage,支持低分辨率占位图
This commit is contained in:
2026-02-12 16:55:05 +08:00
parent 336208b7ce
commit cd752d97d8
39 changed files with 1729 additions and 537 deletions

View File

@@ -8,6 +8,7 @@ import React, { useState } from 'react';
import { queryStoryItemImages, removeStoryItem } from '../../service';
import TimelineItemDrawer from '../TimelineItemDrawer';
import useStyles from './index.style';
import ResponsiveGrid from '@/components/ResponsiveGrid';
// 格式化时间数组为易读格式
const formatTimeArray = (time: string | number[] | undefined): string => {
@@ -29,7 +30,7 @@ const TimelineItem: React.FC<{
refresh: () => void;
disableEdit?: boolean;
}> = ({ item, handleOption, refresh, disableEdit }) => {
const { styles } = useStyles();
const { styles, cx, isMobile } = useStyles();
const intl = useIntl();
const [expanded, setExpanded] = useState(false);
const [showActions, setShowActions] = useState(false);
@@ -98,7 +99,7 @@ const TimelineItem: React.FC<{
}}
extra={
<div className={styles.actions}>
{showActions && !disableEdit && (
{(showActions || isMobile) && !disableEdit && (
<>
<Button
type="text"
@@ -158,14 +159,16 @@ const TimelineItem: React.FC<{
</div>
{imagesList && imagesList.length > 0 && (
<div className="timeline-images-grid">
{imagesList.map((imageInstanceId, index) => (
<TimelineImage
key={imageInstanceId + index}
title={imageInstanceId}
imageInstanceId={imageInstanceId}
className={styles.timelineImage}
/>
))}
<ResponsiveGrid>
{imagesList.map((imageInstanceId, index) => (
<TimelineImage
key={imageInstanceId + index}
title={imageInstanceId}
imageInstanceId={imageInstanceId}
className={styles.timelineImage}
/>
))}
</ResponsiveGrid>
</div>
)}
{item.subItems && item.subItems.length > 0 && (