feat: 三栏比例缩放 + SeedanceContent视频上传 + 本地存储基建 (0.0.22)
三栏布局 - ResizeObserver 等比例分配替代固定默认值恢复 - 修复拖拽+窗口调整竞态卡死(needsRecalcRef 延迟补算) - containerRef.current 动态读取 DOM 替代闭包 el Seedance2Content - 从占位文本重构为内容编排控件(文本+图片/视频/音频上传) - 根据 spec.image_files/video_files/audio_files 动态渲染上传区域 - 值 JSON 序列化 → 提交时转 ContentItem[](text/image_url/video_url/audio_url) 图片上传兼容视频文件 - buildAccept 根据 file_filter 区分 image/video 前缀 - createMediaBeforeUpload 动态放行 video/* MIME - 公共模块 media-upload-utils.ts 本地存储基建 - sql.js (WASM SQLite) + safeStorage 加密持久化 - 8个IPC文件操作通道 + resolveSafe 路径穿越防护 - <userData>/heixiu-data/ 沙箱 + JWT用户隔离 - 7表DDL + 游标分页 + LRU媒体淘汰 其他 - 修复 errorMessageRef 渲染期写入警告 - 媒体预览回退直接URL(<img>无CORS限制)+ output_type类型补充 - CSP wasm-unsafe-eval + https: CDN媒体源
This commit is contained in:
112
src/pages/settings/sections/DataManageSetting.tsx
Normal file
112
src/pages/settings/sections/DataManageSetting.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
// ============================================================
|
||||
// DataManageSetting — 本地数据管理设置区块
|
||||
//
|
||||
// 功能:
|
||||
// - 展示本地缓存统计(任务/订单/媒体数量)
|
||||
// - [加载历史数据]:各拉首批数据(100 条任务、100 条充值订单、100 条 VIP 订单)
|
||||
// - [清理缓存]:清空当前用户本地数据
|
||||
// - [保存到磁盘]:手动触发加密落盘
|
||||
//
|
||||
// "下一页"逻辑在对应列表页组件中:
|
||||
// - TaskHistory → 滚动到最后一页本地数据时调 fetchMoreTasks()
|
||||
// - OrdersPage → 滚动到最后一页本地数据时调 fetchMoreOrders()
|
||||
// ============================================================
|
||||
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { Card, Button, Typography, App, Divider } from 'antd';
|
||||
import { CloudDownloadOutlined, DeleteOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
initStorage, getStorageStats, clearUserStorage, saveDatabase,
|
||||
} from '@/infrastructure/storage';
|
||||
import { fetchAndSyncTasks, fetchAndSyncRechargeOrders, fetchAndSyncVipOrders } from './data-sync';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
// ---------- 组件 ----------
|
||||
|
||||
export function DataManageSetting() {
|
||||
const { message } = App.useApp();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [stats, setStats] = useState(() => getStorageStats());
|
||||
|
||||
const refreshStats = useCallback(() => setStats(getStorageStats()), []);
|
||||
|
||||
// 一键加载首批数据
|
||||
const loadAll = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await Promise.allSettled([
|
||||
fetchAndSyncTasks(),
|
||||
fetchAndSyncRechargeOrders(),
|
||||
fetchAndSyncVipOrders(),
|
||||
]);
|
||||
refreshStats();
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [refreshStats]);
|
||||
|
||||
// 清理缓存
|
||||
const handleClear = useCallback(() => {
|
||||
clearUserStorage().then(async () => {
|
||||
await initStorage();
|
||||
refreshStats();
|
||||
message.success('本地缓存已清理');
|
||||
});
|
||||
}, [message, refreshStats]);
|
||||
|
||||
// 保存到磁盘
|
||||
const handleSave = useCallback(() => {
|
||||
saveDatabase().then(ok => {
|
||||
message[ok ? 'success' : 'error'](ok ? '数据已保存到磁盘' : '保存失败');
|
||||
});
|
||||
}, [message]);
|
||||
|
||||
useEffect(() => { refreshStats(); }, [refreshStats]);
|
||||
|
||||
return (
|
||||
<Card size="small" title="数据管理" className="rounded-md!">
|
||||
<div className="flex flex-col gap-3">
|
||||
{/* ---- 统计 ---- */}
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text type="secondary" className="text-xs">本地缓存概况</Text>
|
||||
<div className="flex gap-4">
|
||||
<Text className="text-xs">
|
||||
任务:<Text strong>{stats.taskCount}</Text> 条
|
||||
</Text>
|
||||
<Text className="text-xs">
|
||||
订单:<Text strong>{stats.orderCount}</Text> 条
|
||||
</Text>
|
||||
<Text className="text-xs">
|
||||
媒体:<Text strong>{stats.mediaCount}</Text> 个
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider style={{ margin: '4px 0' }} />
|
||||
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
icon={<CloudDownloadOutlined />}
|
||||
onClick={loadAll}
|
||||
loading={loading}
|
||||
block
|
||||
>
|
||||
加载历史数据(每类各拉首批)
|
||||
</Button>
|
||||
|
||||
<Divider style={{ margin: '4px 0' }} />
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button size="small" icon={<ReloadOutlined />} onClick={handleSave}>
|
||||
保存到磁盘
|
||||
</Button>
|
||||
<Button size="small" danger icon={<DeleteOutlined />} onClick={handleClear}>
|
||||
清理缓存
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user