gongxiangp2/components/UpdateLogModal.tsx
chenpei 0ce59be34e 备份:组织架构设计方案讨论前的代码快照
- 包含所有当前修改和新功能
- 准备开始组织架构优化实施方案
2025-12-30 13:20:26 +08:00

577 lines
23 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { useEffect, useState } from 'react'
// 更新日志配置 - 每次有新功能或优化时更新这个版本号
const CURRENT_VERSION = '2.2.4'
const STORAGE_KEY = 'update_log_viewed_version_v224'
interface UpdateItem {
type: 'feature' | 'improvement' | 'fix' // 新功能、优化、修复
title: string
description: string
}
interface UpdateLog {
version: string
date: string
title: string
items: UpdateItem[]
}
// 更新日志内容 - 通俗易懂,面向客户
// 注意:只有经过测试验证的功能才会添加到更新记录中
const UPDATE_LOGS: UpdateLog[] = [
{
version: '2.2.4',
date: '2025-12-29',
title: '系统更新',
items: [
{
type: 'feature',
title: '性能监控面板',
description:
'在"公网/内网"按钮上新增性能监控功能,鼠标悬停即可查看系统实时性能。显示CPU使用率、内存使用情况、上传队列和转码队列状态,转码队列还会显示任务详情(文件名、类型、上传人、进度等),方便了解系统运行状态。'
},
{
type: 'feature',
title: '标准模型素材类型',
description:
'新增"标准模型"素材类型,支持上传标准模型素材。标准模型素材文件可选,但必须上传预览图,支持后续添加SKU进行扩展。'
},
{
type: 'feature',
title: '统一批量上传功能',
description:
'统一了所有素材类型的批量上传逻辑,无论是通过"选择文件"按钮还是拖拽文件,都使用相同的批量上传流程。支持音乐、视频、3D场景、品牌VI等多种素材类型的批量上传,每个文件可独立设置SPU型号,上传进度清晰可见。'
},
{
type: 'improvement',
title: '上传体验大幅提升',
description:
'所有素材类型的上传流程优化,上传完成后立即关闭上传弹窗,不再等待后台处理(如视频转码)。转码等后台任务在后台异步进行,首页素材卡片会显示转码状态和进度,上传和转码完全分离,体验更流畅。'
},
{
type: 'improvement',
title: '上传进度显示优化',
description:
'修复了上传弹窗中进度条重复显示的问题,现在单文件上传只显示一个进度条,批量上传显示总进度和当前文件进度,界面更清晰。'
},
{
type: 'improvement',
title: '转码任务自动清理',
description:
'视频转码任务入队失败时,系统会自动清理源视频文件,避免产生大体积垃圾文件占用存储空间。'
},
{
type: 'fix',
title: '性能监控数据更准确',
description:
'修复了性能监控中CPU使用率和内存统计不准确的问题,现在使用更精确的计算方法,数据与系统实际状态一致。修复了上传队列显示已完成任务的问题,现在只显示真正进行中的上传任务。'
}
]
},
{
version: '2.2.32',
date: '2025-12-19',
title: '系统更新',
items: [
{
type: 'feature',
title: '标准模型 SKU 功能',
description:
'新增标准模型素材类型,支持以产品型号(SPU)为基准创建模型合集。每个标准模型可添加多个 SKU(如不同颜色、尺寸的款式),支持单选、多选或全选下载。上传时只需填写 SPU 型号和预览图,SKU 可后续添加。详情页右侧显示 SKU 列表,支持拖拽上传、排序调整,操作更便捷。'
},
{
type: 'improvement',
title: '上传超大原图自动优化',
description:
'上传预览图时,系统会自动处理超大原图(如相机拍摄的照片)。自动调整到合适大小并压缩,上传更快,加载更流畅,显示效果不变。'
}
]
},
{
version: '2.2.31',
date: '2025-12-18',
title: '系统更新',
items: [
{
type: 'fix',
title: '模特类素材支持正常下载',
description:
'修复模特类素材卡片下载按钮可点但无法下载的问题,现在会自动将模特素材的展示图打包成压缩包,老数据也会补齐可下载文件。'
},
{
type: 'fix',
title: '首页按素材类型筛选后返回不再错乱',
description:
'修复在首页选择“模特”等素材类型后进入详情再返回时,后续瀑布流会混入其他类型素材的问题,现在返回后会完整恢复原来的筛选条件和浏览位置。'
}
]
},
{
version: '2.2.3',
date: '2025-12-17',
title: '系统更新',
items: [
{
type: 'feature',
title: '新增"提交反馈"入口',
description:
'在头像下拉菜单中新增"提交反馈"入口,点击可直接跳转到钉钉文档提交功能建议、优化意见或Bug反馈,帮助我们持续改进系统。'
},
{
type: 'feature',
title: '首页筛选项可折叠收起',
description:
'首页筛选区域新增折叠功能,默认收起,点击可展开。收起时显示已选筛选数量,界面更简洁,浏览素材更专注。'
},
{
type: 'feature',
title: '新增产品类别筛选',
description: '首页新增"产品类别"筛选项,支持按书桌、书架、椅子等产品类型筛选素材,查找更精准。'
},
{
type: 'fix',
title: '详情页返回后不再跳到顶部',
description: '修复从素材详情页返回首页后自动跳到顶部的问题,现在会保持原来的浏览位置。'
},
{
type: 'fix',
title: '搜索输入不再频繁刷新',
description: '修复搜索栏输入一个字就刷新页面的问题,现在输入完成后才会触发搜索,体验更流畅。'
},
{
type: 'fix',
title: '滚动后素材预览图正常显示',
description: '修复向下滚动一段距离后部分素材卡片预览图不显示的问题,现在所有卡片都能正常加载预览图。'
}
]
},
{
version: '2.2.2',
date: '2025-12-10',
title: '系统更新',
items: [
{
type: 'fix',
title: '瀑布流返回定位更精准',
description: '修复浏览多页后进入素材详情返回会跳到错误位置或顶部的问题,返回时自动补拉数据并定位到原卡片。'
},
{
type: 'improvement',
title: '瀑布流单一模式与筛选显示优化',
description: '首页固定使用瀑布流布局,移除分页切换;“当前筛选”不再展示素材类型,筛选提示更简洁。'
},
{
type: 'feature',
title: '排序支持正/倒序切换',
description: '“最新上传 / 下载最多”均可切换正序或倒序,满足不同浏览习惯。'
},
{
type: 'improvement',
title: '默认标签改为“3D场景”',
description: '首页默认展示 3D 场景素材,方便快速浏览核心内容。'
}
]
},
{
version: '2.2.1',
date: '2025-12-09',
title: '系统更新',
items: [
{
type: 'feature',
title: '网络诊断功能',
description: '新增网络诊断功能,支持下载和上传测速,自动检测存储服务连通性,结果可复制分享,方便排查网络问题。'
},
{
type: 'improvement',
title: '下载体验大幅提升',
description: '大文件下载支持断点续传,下载更稳定、速度更快。下载后下载数立即更新,无需刷新页面即可看到最新数据,排行榜面板也会自动刷新。'
},
{
type: 'improvement',
title: '收藏功能体验优化',
description: '收藏/取消收藏操作后显示气泡提示,操作反馈更清晰。收藏状态在所有素材列表中正确显示,方便快速识别已收藏内容。'
},
{
type: 'improvement',
title: '素材卡片头像显示优化',
description: '作者头像尺寸增大,改为圆角方形样式,显示更清晰。优化显示逻辑,头像完整显示不被裁切,同时保持卡片高度不变。'
},
{
type: 'improvement',
title: '个人中心卡片更清晰',
description: '个人中心改为上下大卡片,分开展示"我的素材""我的收藏",信息一目了然。'
},
{
type: 'improvement',
title: '榜单悬浮窗体验优化',
description: '支持拖动、关闭后出现可拖动的迷你按钮可再打开,位置会记忆。拖拽无延迟,拖动更流畅。'
},
{
type: 'improvement',
title: '头像加载更稳定',
description: '优化头像加载与处理,解决头像不显示/加载慢的问题,统一压缩为 WebP 格式,优先加载。'
},
{
type: 'improvement',
title: '转码任务自动恢复',
description: '部署中断后自动恢复转码任务,清理残留文件,避免存储浪费。恢复时保持队列顺序,确保转码任务按顺序执行。'
},
{
type: 'fix',
title: '登录退出后能正常回到登录页',
description: '修正退出后偶尔跳到 localhost 的问题,现在会正确返回登录页。'
}
]
},
{
version: '2.2.0',
date: '2025-12-08',
title: '系统更新',
items: [
{
type: 'feature',
title: '个人中心上线',
description: '新增“我的素材 / 我的收藏”两个入口,卡片支持预览与视频弹窗,常用信息更聚合。'
},
{
type: 'feature',
title: '收藏(书签)按钮',
description: '卡片新增“收藏/取消收藏”书签按钮,和点赞清晰区分;收藏列表可在个人中心查看。'
},
{
type: 'feature',
title: '回收站与批量操作(管理员)',
description: '删除默认进入回收站;支持批量恢复与永久删除,关键操作留痕,误删可挽回。'
},
{
type: 'feature',
title: '头像上传与即时刷新',
description: '头像选择-预览-上传一体化,提交后标题栏头像即时更新,无需整页刷新。'
},
{
type: 'feature',
title: '一键复制分享链接',
description: '卡片操作区支持复制分享链接,便于把素材快速发给同事协作。'
},
{
type: 'improvement',
title: '收藏按钮样式与反馈优化',
description: '采用书签样式,未收藏/已收藏状态对比明显;悬停与点击反馈更清晰。'
},
{
type: 'improvement',
title: '转码失败一键重试',
description: '在卡片上即可重试转码,结合实时进度提示,处理更直观。'
},
{
type: 'improvement',
title: '预览视频编码与清晰度升级',
description: '预览视频改用 H.265 (HEVC) 编码,并提升分辨率与质量;画质更清晰。由于分辨率与质量目标提升,网络带宽占用与转码耗时会相应增加(弱网环境建议暂停自动播放)。'
},
{
type: 'fix',
title: '首页卡片稳定性修复',
description: '修复极端情况下预览区不渲染的问题,提升卡片加载稳定性。'
}
]
},
{
version: '2.1.6',
date: '2025-12-06',
title: '系统更新',
items: [
{
type: 'feature',
title: '素材类型标签',
description: '现在每个素材卡片的右上角都会显示素材类型标签(如"3DMAX"、"视频"等),不同颜色区分,让您一眼就能看出是什么类型的素材。'
},
{
type: 'feature',
title: '素材ID快速复制',
description: '素材卡片底部现在会显示完整的素材ID,点击ID就能一键复制到剪贴板,再也不用手动选择复制了!复制成功后会显示提示,非常方便。'
},
{
type: 'feature',
title: '视频素材卡片预览',
description: '视频素材在首页卡片上会自动播放10秒预览片段,转码完成后会显示预览视频而不是静态封面图。还会显示视频时长和转码进度,让您实时了解处理状态。'
},
{
type: 'improvement',
title: '视频转码速度大幅提升',
description: '优化了存储服务连接方式,视频转码速度更快了!之前转码可能会卡住的问题已经解决,现在转码过程更加稳定可靠。'
},
{
type: 'feature',
title: '新增"更新记录"菜单',
description: '在头像下拉菜单中新增了"更新记录"入口,您可以随时查看系统所有的历史更新,了解系统都做了哪些改进。'
},
{
type: 'improvement',
title: '优化复制提示位置',
description: '复制素材ID时的提示消息现在显示在页面顶部居中位置,不会再和标题栏重叠了,提示更加清晰明显。'
}
]
},
{
version: '2.1.5',
date: '2025-12-06',
title: '系统更新',
items: [
{
type: 'feature',
title: '视频转码实时进度显示',
description: '现在上传视频后,可以实时看到转码进度了!进度条会准确显示当前转码状态,让您清楚知道视频处理到哪一步了。'
},
{
type: 'improvement',
title: '视频上传稳定性大幅提升',
description: '优化了视频上传机制,即使网络不稳定也能可靠完成上传。系统会自动重试,确保您的视频素材不会丢失。'
},
{
type: 'improvement',
title: '视频预览播放更流畅',
description: '优化了视频预览播放体验,加载速度更快,播放更流畅。现在可以更顺畅地查看和预览视频素材了。'
},
{
type: 'fix',
title: '修复视频转码卡顿问题',
description: '修复了视频转码过程中可能出现的卡顿问题,现在转码过程更加稳定可靠,不会中途失败。'
},
{
type: 'feature',
title: '更新日志弹窗',
description: '新增了更新日志功能,每次系统有新功能或优化时,会自动弹出更新说明,让您及时了解系统改进。'
}
]
}
]
interface UpdateLogModalProps {
isOpen: boolean
onClose: () => void
updateLog?: UpdateLog // 可选,如果不传则显示所有历史记录
showAllHistory?: boolean // 是否显示所有历史记录
}
function UpdateLogModal({ isOpen, onClose, updateLog, showAllHistory = false }: UpdateLogModalProps) {
useEffect(() => {
if (isOpen) {
// 阻止背景滚动
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = 'unset'
}
return () => {
document.body.style.overflow = 'unset'
}
}, [isOpen])
if (!isOpen) return null
// 如果showAllHistory为true,显示所有历史记录;否则只显示指定的updateLog
const logsToShow = showAllHistory ? UPDATE_LOGS : (updateLog ? [updateLog] : [])
// 如果没有可显示的内容,不渲染弹窗
if (logsToShow.length === 0) return null
const getTypeIcon = (type: string) => {
switch (type) {
case 'feature':
return '✨'
case 'improvement':
return '🚀'
case 'fix':
return '🔧'
default:
return '📝'
}
}
const getTypeColor = (type: string) => {
switch (type) {
case 'feature':
return 'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800'
case 'improvement':
return 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800'
case 'fix':
return 'bg-orange-50 dark:bg-orange-900/20 border-orange-200 dark:border-orange-800'
default:
return 'bg-gray-50 dark:bg-gray-800 border-gray-200 dark:border-gray-700'
}
}
return (
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
{/* 背景遮罩 */}
<div
className="absolute inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity"
onClick={onClose}
/>
{/* 弹窗内容 */}
<div className="relative w-full max-w-2xl max-h-[85vh] bg-white dark:bg-gray-800 rounded-2xl shadow-apple-lg overflow-hidden transform transition-all flex flex-col">
{/* 头部 */}
<div className="flex items-center justify-between px-6 py-5 border-b border-gray-200 dark:border-gray-700 bg-gradient-to-r from-gray-50 to-white dark:from-gray-800 dark:to-gray-900 flex-shrink-0">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center">
<svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z" />
</svg>
</div>
<div>
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
{showAllHistory ? '更新记录' : updateLog?.title || '系统更新'}
</h2>
<p className="text-sm text-gray-500 dark:text-gray-400">
{showAllHistory ? '查看所有历史更新' : `版本 ${updateLog?.version || ''} · ${updateLog?.date || ''}`}
</p>
</div>
</div>
<button
onClick={onClose}
className="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
aria-label="关闭"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{/* 内容区域 */}
<div className="px-6 py-6 overflow-y-auto flex-1 min-h-0">
<div className="space-y-6">
{logsToShow.map((log, logIndex) => (
<div key={logIndex} className="space-y-4">
{/* 版本标题(仅在显示所有历史时显示) */}
{showAllHistory && (
<div className="sticky top-0 bg-white dark:bg-gray-800 pb-2 border-b border-gray-200 dark:border-gray-700 z-10 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
版本 {log.version}
</h3>
<p className="text-xs text-gray-500 dark:text-gray-400">
{log.date}
</p>
</div>
)}
{/* 更新项列表 */}
<div className="space-y-4">
{log.items.map((item, itemIndex) => (
<div
key={itemIndex}
className={`p-4 rounded-xl border ${getTypeColor(item.type)} transition-all hover:shadow-md`}
>
<div className="flex items-start gap-3">
<span className="text-2xl flex-shrink-0">{getTypeIcon(item.type)}</span>
<div className="flex-1 min-w-0">
<h3 className="font-semibold text-gray-900 dark:text-white mb-1.5">
{item.title}
</h3>
<p className="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">
{item.description}
</p>
</div>
</div>
</div>
))}
</div>
</div>
))}
</div>
</div>
{/* 底部按钮 */}
<div className="px-6 py-5 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900/50 flex-shrink-0">
<button
onClick={onClose}
className="w-full py-3 px-6 bg-gray-900 dark:bg-gray-700 text-white rounded-xl font-medium hover:bg-gray-800 dark:hover:bg-gray-600 active:scale-[0.98] transition-all duration-200 shadow-apple hover:shadow-apple-lg"
>
知道了
</button>
</div>
</div>
</div>
)
}
// Hook: 检查是否需要显示更新弹窗
export function useUpdateLog() {
const [showModal, setShowModal] = useState(false)
const [currentLog, setCurrentLog] = useState<UpdateLog | null>(null)
const [showAllHistory, setShowAllHistory] = useState(false)
useEffect(() => {
// 监听自定义事件,用于手动触发显示更新日志
const handleShowUpdateLog = (event: CustomEvent) => {
if (event.detail?.log) {
setCurrentLog(event.detail.log)
setShowAllHistory(false)
setShowModal(true)
} else if (event.detail?.showAll) {
setCurrentLog(null)
setShowAllHistory(true)
setShowModal(true)
}
}
window.addEventListener('showUpdateLog', handleShowUpdateLog as EventListener)
// 检查是否已查看过当前版本(仅在首次加载时自动弹出)
// 注意:只有经过测试验证的功能更新才会添加到UPDATE_LOGS中
const viewedVersion = localStorage.getItem(STORAGE_KEY)
if (viewedVersion !== CURRENT_VERSION) {
// 找到当前版本的更新日志
const log = UPDATE_LOGS.find(log => log.version === CURRENT_VERSION)
if (log) {
setCurrentLog(log)
setShowAllHistory(false)
setShowModal(true)
}
}
return () => {
window.removeEventListener('showUpdateLog', handleShowUpdateLog as EventListener)
}
}, [])
const handleClose = () => {
setShowModal(false)
// 如果显示的是当前版本,标记已查看
if (!showAllHistory && currentLog?.version === CURRENT_VERSION) {
localStorage.setItem(STORAGE_KEY, CURRENT_VERSION)
}
}
return {
showModal,
currentLog,
showAllHistory,
handleClose,
}
}
// 更新日志管理器 - 用于手动触发显示更新日志
export function showUpdateLog(version?: string) {
if (version === 'all' || version === undefined) {
// 显示所有历史记录
const event = new CustomEvent('showUpdateLog', { detail: { showAll: true } })
window.dispatchEvent(event)
} else {
// 显示指定版本
const log = UPDATE_LOGS.find(log => log.version === version)
if (log) {
const event = new CustomEvent('showUpdateLog', { detail: { log } })
window.dispatchEvent(event)
}
}
}
export default UpdateLogModal