| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>AWS S3 文件夹批量下载工具</title>
- <script src="https://sdk.amazonaws.com/js/aws-sdk-2.938.0.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
- <style>
- * {
- box-sizing: border-box;
- margin: 0;
- padding: 0;
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- }
-
- body {
- background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
- color: #333;
- line-height: 1.6;
- padding: 20px;
- min-height: 100vh;
- }
-
- .container {
- max-width: 1200px;
- margin: 0 auto;
- background-color: rgba(255, 255, 255, 0.95);
- border-radius: 12px;
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
- padding: 30px;
- }
-
- h1 {
- text-align: center;
- margin-bottom: 25px;
- color: #2c3e50;
- font-weight: 600;
- }
-
- .description {
- text-align: center;
- margin-bottom: 30px;
- color: #555;
- font-size: 16px;
- }
-
- .stats {
- display: flex;
- justify-content: space-between;
- margin-bottom: 20px;
- padding: 15px;
- background-color: #f8f9fa;
- border-radius: 8px;
- }
-
- .stat-item {
- text-align: center;
- }
-
- .stat-value {
- font-size: 24px;
- font-weight: bold;
- color: #3498db;
- }
-
- .stat-label {
- font-size: 14px;
- color: #7f8c8d;
- }
-
- .action-buttons {
- display: flex;
- gap: 10px;
- justify-content: center;
- margin-bottom: 20px;
- }
-
- button {
- padding: 12px 20px;
- color: white;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- font-size: 16px;
- font-weight: 500;
- transition: background-color 0.3s, transform 0.2s;
- }
-
- button:hover {
- transform: translateY(-2px);
- }
-
- button:active {
- transform: translateY(0);
- }
-
- button:disabled {
- background-color: #95a5a6;
- cursor: not-allowed;
- transform: none;
- }
-
- .load-btn {
- background-color: #3498db;
- }
-
- .load-btn:hover {
- background-color: #2980b9;
- }
-
- .download-all {
- background-color: #2ecc71;
- }
-
- .download-all:hover {
- background-color: #27ae60;
- }
-
- .download-zip {
- background-color: #9b59b6;
- }
-
- .download-zip:hover {
- background-color: #8e44ad;
- }
-
- .clear {
- background-color: #e74c3c;
- }
-
- .clear:hover {
- background-color: #c0392b;
- }
-
- .folders-container {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- gap: 15px;
- margin-top: 25px;
- }
-
- .folder-card {
- background-color: #f8f9fa;
- border-radius: 8px;
- padding: 15px;
- border-left: 4px solid #3498db;
- box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);
- transition: transform 0.2s;
- }
-
- .folder-card:hover {
- transform: translateY(-5px);
- }
-
- .folder-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 10px;
- }
-
- .folder-name {
- font-weight: 600;
- font-size: 16px;
- color: #2c3e50;
- word-break: break-all;
- }
-
- .folder-status {
- font-size: 12px;
- padding: 3px 8px;
- border-radius: 10px;
- background-color: #ecf0f1;
- }
-
- .status-pending {
- background-color: #f39c12;
- color: white;
- }
-
- .status-loading {
- background-color: #3498db;
- color: white;
- }
-
- .status-ready {
- background-color: #2ecc71;
- color: white;
- }
-
- .status-downloading {
- background-color: #9b59b6;
- color: white;
- }
-
- .status-completed {
- background-color: #27ae60;
- color: white;
- }
-
- .status-error {
- background-color: #e74c3c;
- color: white;
- }
-
- .file-count {
- font-size: 14px;
- color: #7f8c8d;
- margin-bottom: 10px;
- }
-
- .progress-bar {
- height: 6px;
- background-color: #ecf0f1;
- border-radius: 3px;
- margin-top: 8px;
- overflow: hidden;
- }
-
- .progress {
- height: 100%;
- background-color: #2ecc71;
- width: 0%;
- transition: width 0.3s;
- }
-
- .file-list {
- margin-top: 10px;
- max-height: 0;
- overflow: hidden;
- transition: max-height 0.3s ease;
- }
-
- .file-list.expanded {
- max-height: 200px;
- overflow-y: auto;
- }
-
- .file-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 8px 0;
- border-bottom: 1px solid #eee;
- font-size: 14px;
- }
-
- .file-item:last-child {
- border-bottom: none;
- }
-
- .file-name {
- flex: 1;
- word-break: break-all;
- }
-
- .file-size {
- color: #7f8c8d;
- font-size: 12px;
- margin-right: 10px;
- }
-
- .expand-btn {
- background: none;
- border: none;
- color: #3498db;
- cursor: pointer;
- font-size: 12px;
- padding: 5px 10px;
- margin-top: 5px;
- }
-
- .summary {
- margin-top: 20px;
- padding: 15px;
- background-color: #f8f9fa;
- border-radius: 8px;
- text-align: center;
- }
-
- .overall-progress {
- margin-top: 10px;
- }
-
- @media (max-width: 768px) {
- .folders-container {
- grid-template-columns: 1fr;
- }
-
- .stats {
- flex-direction: column;
- gap: 10px;
- }
-
- .action-buttons {
- flex-direction: column;
- }
- }
- </style>
- </head>
- <body>
- <div class="container">
- <h1>AWS S3 文件夹批量下载工具</h1>
- <p class="description">批量下载指定目录中的文件并打包为ZIP</p>
-
- <div class="stats">
- <div class="stat-item">
- <div class="stat-value" id="totalFolders">0</div>
- <div class="stat-label">总文件夹数</div>
- </div>
- <div class="stat-item">
- <div class="stat-value" id="loadedFolders">0</div>
- <div class="stat-label">已加载</div>
- </div>
- <div class="stat-item">
- <div class="stat-value" id="readyFolders">0</div>
- <div class="stat-label">准备下载</div>
- </div>
- <div class="stat-item">
- <div class="stat-value" id="completedFolders">0</div>
- <div class="stat-label">已完成</div>
- </div>
- </div>
-
- <div class="action-buttons">
- <button id="loadFolders" class="load-btn">加载所有文件夹</button>
- <button id="downloadZip" class="download-zip" disabled>打包下载ZIP</button>
- <button id="clearAll" class="clear">清空列表</button>
- </div>
-
- <div class="folders-container" id="foldersContainer">
- <!-- 文件夹卡片将在这里动态生成 -->
- </div>
-
- <div class="summary" id="summary" style="display: none;">
- <div id="summaryText"></div>
- <div class="progress-bar overall-progress">
- <div class="progress" id="overallProgress"></div>
- </div>
- </div>
- </div>
- <script>
- // 您的文件夹数组
- const folders = ["411325201408040121","440104201312168333","440604201604210182","440604201512070039","440305201207071553","411503201201270459","440305201208211554","440114200712210420","421181200905305829","440305201006230060","H10192830","36042320100705006x","445122201001140920","440304200911101831","430702201004080100","441422201507140015","440304201608261810","441523201403146764","440104201504076716","440307201308140020","150422201211302119","350305200910182398","511322201008261122","445381201002020040","440304201101091816","440303201409054513","42122420130806584x","460107201410300425","440881201301096726","610722201212110641","450422201211302119","362322200907013620","44051220171107001X","440306201602225117","440307201409126519","430724201606220113","440306201310090433","411302201312150399","511322200809261312","411622200810091026","610702200911200929","440304200909272041","420116201003150422","410823201310070203","440303201310117764","500234201312302184","442000201402214621","442000201501254634","360735201306230513","411423201212280230","440104201204136529","44010420120116652X","440303201402288528","42102320130828245X","441422201211232631","42130220130426841X","440305201712231239","440305201709281235","440305201802090142","42000201402214621","44158120140208901X ","360731201310017613","430903201207130312","441781201111186996","430621201205050219","445281201407234391","430902201403030136","440305201407099016","440104201712246118","440103201709182719","46902820090622071X","441623201003023410","420103201008124416","421181201008213531","360721200911050059","370212201509262531","44030620151119081","411626200905066531","420801201004044019","440305200902141512","44030620106094333","441324200809181616","430321201005030153","430981200909240254","44030520151214005X","440306201304270518","441501200909275018","810000201001300331","440306200911291017","440306201402061015","43020220140417","441424201210175121","140624198706080534","441622201210056665","440304201704101825","440105201212115425","44030520100106784X","440307201001193128","441623200903025521","440306200909140527","44182720081125610X","440303201404088132","440305201807160170","140105201903120222","321088200910315250","341225200911208210","522425201008120095","44030520170807121X","440106201706223326","445281201202283018","441501201203214090","431122201007290246","44158120100211882X","640221201606255730","360921201401250312","440303201312027340","440304201408050090","440183201410162416","440305201407081553","421023201412251012","440303201305232717","43052120090518017X","441827201006070112","44030620090905002X","450821200909241021","440304200910291821","440306201302193918","450703201211132751","440306201211192012","220102201703285218","430104201002160078","45132320090321511X","420506200910181817","441323201405100013","440304201406090099","43022320130908019X","440104201606306527","440104201510206513","44030620110627071X","440304201106171831","61072120160107262X","430621201411020045","440306201512280913","412824201008124416","440305201708241223","440981201110064612","440305201112311534","440304201205267417","440307201608200339","42088120160704583X","440306201006094333","440305201402120015","451021201003091399","440511201411174750","440113201503062116","411330200911181833","440306200911271315","440304201205150059","500116201112254351","44528120120718043x","360924201402152828","421281201310080720","450481201312201640","440304201206297618","440307201703220514","620702201310141210","430581201312210477","440515201403081939","430626201503160493","440823201406284914","431022201312050016","44030420140701635X","440307201401281821","445222201404092922","440306201402184568","440307201011162819","441702200410231726","430527200409116361","350824201402054614","44030420131008185X","361128201607072090","510824200811185063","440282200906022200","440305201006180032","440104201704116938","440103201508217815","44030620160514091X","430421201010050592","440305201005081518","442000201501254645","440304201209171818","440306201906213692","440513201004211609","440513201008055084","440511201304296744","440514200405200822","430481201602270229","440303200810068546","441302201211082038","360722201210162112","370283201308061552","441502201306061126","445224201209195160","44522420130321572X","360982201407026816","440104201504176514","430528201310220231","440305201312207811","440303201604298118","445281201209030830","620622201007295217","511324200911243551","430722201001160178","429004200403151355","440305201304051589","440233200809268017","440304201611031813","511011200910065062","421381201410289594","411622201503206510","44030620151119081X","340506201510100517","440604201508210078","440604201409070022","440604201608240194","431025201407220224","430223201408230106","50010120140112062X","440823201508132014","440305200901053414","230306200911094057","440305201005063416","620102201006175341","421024201001060824","440514201403174944","440303200908262726","43062601503160493","440104201204056713","445222201609115235","44060420161206017X","440604201604130019","440604201708210320","440514201412212359","411328201306280019","440306201212053911","420321201208120018","42900420040315","230183200910011311","411421200910280230","610125201004203516","430523201008120238","431102200901080016","340104200905039010","220102200811273316","430722201109200231","341003201205182610","511381201202223496","18923782659","440306201402011018","440307201606270050","440305201109211532","421081201203152150","441622201112087417","440304200908274627","621124200907122372","440981200912054630","44030420160715006X","23011020190710082X","421125201506070026","441427201409201517","440306201409193547","44030320140131451X","210204201003037033","445281200909171074","440304201005316317","440305200412151224","440103201805252422","440304201407017619","440304201310167610","440304201211281848","420822200311113720","430102201501120094","440103201606057413","440513200911033039","450923200912257479","440305201603241534","440511201105116210","440304201510221845","440304201510301861","440606201503270330","440304201703110041","371521201612040025","440303201405088521","440305201309278221","411102201006120099","440303200909164511","441424201007260320","441223200911252626","411622201606131515","421124201607031011","CAN440118050505","440304200912257133","371722200912033866","450921201211260415","440306201607080834","441203201510191219","430626200310030022","440402201308229176"];
-
- // AWS S3配置 - 请替换为您的实际配置
- const awsConfig = {
- region: 'cn-northwest-1', // 替换为您的区域
- credentials: {
- accessKeyId: 'AKIATLPEDU37QV5CHLMH',
- secretAccessKey: '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'
- }
- };
-
- // 初始化S3客户端
- AWS.config.update(awsConfig);
- const s3 = new AWS.S3();
- const bucketName = 'ccrb'; // 您的存储桶名称
-
- // 存储文件夹数据
- let folderData = [];
-
- // DOM元素
- const loadFoldersBtn = document.getElementById('loadFolders');
- const downloadZipBtn = document.getElementById('downloadZip');
- const clearAllBtn = document.getElementById('clearAll');
- const foldersContainer = document.getElementById('foldersContainer');
- const summary = document.getElementById('summary');
- const summaryText = document.getElementById('summaryText');
- const overallProgress = document.getElementById('overallProgress');
- const totalFoldersEl = document.getElementById('totalFolders');
- const loadedFoldersEl = document.getElementById('loadedFolders');
- const readyFoldersEl = document.getElementById('readyFolders');
- const completedFoldersEl = document.getElementById('completedFolders');
-
- // 初始化文件夹数据
- function initializeFolderData() {
- folderData = folders.map(folder => ({
- id: folder,
- path: folder,
- files: [],
- status: 'pending', // pending, loading, ready, downloading, completed, error
- expanded: false,
- fileCount: 0,
- completedFiles: 0
- }));
-
- updateStats();
- renderFolders();
- }
-
- // 加载所有文件夹的文件列表
- async function loadAllFolders() {
- loadFoldersBtn.disabled = true;
- loadFoldersBtn.textContent = '加载中...';
-
- // 分批加载,避免同时发起太多请求
- const batchSize = 5;
- for (let i = 0; i < folderData.length; i += batchSize) {
- const batch = folderData.slice(i, i + batchSize);
- await Promise.allSettled(batch.map(folder => loadFolderFiles(folder)));
-
- // 更新统计信息
- updateStats();
-
- // 添加延迟以避免请求过于频繁
- await new Promise(resolve => setTimeout(resolve, 1000));
- }
-
- loadFoldersBtn.textContent = '加载完成';
- updateDownloadButtonState();
- }
-
- // 加载文件夹中的文件
- async function loadFolderFiles(folder) {
- folder.status = 'loading';
- updateFolderUI(folder);
-
- try {
- const params = {
- Bucket: bucketName,
- Prefix: folder.path
- };
-
- const data = await s3.listObjectsV2(params).promise();
-
- // 过滤掉文件夹本身(如果存在)
- folder.files = data.Contents.filter(item =>
- item.Key !== folder.path
- ).map(item => ({
- key: item.Key,
- name: item.Key.replace(folder.path, ''),
- size: formatFileSize(item.Size),
- status: 'pending',
- progress: 0,
- url: null
- }));
-
- folder.fileCount = folder.files.length;
- folder.status = folder.files.length > 0 ? 'ready' : 'empty';
- updateFolderUI(folder);
- updateStats();
- } catch (error) {
- console.error(`加载文件夹 ${folder.path} 失败:`, error);
- folder.status = 'error';
- folder.error = error.message;
- updateFolderUI(folder);
- updateStats();
- }
- }
-
- // 下载所有文件并打包为ZIP
- async function downloadAllAsZip() {
- summary.style.display = 'block';
- summaryText.textContent = '正在准备下载...';
- overallProgress.style.width = '0%';
-
- // 收集所有需要下载的文件
- const allFiles = [];
- folderData.forEach(folder => {
- if (folder.status === 'ready' || folder.status === 'partial') {
- folder.files.forEach(file => {
- if (file.status !== 'completed') {
- allFiles.push({
- folder: folder.path,
- key: file.key,
- name: file.name || file.key.split('/').pop()
- });
- }
- });
- }
- });
-
- if (allFiles.length === 0) {
- alert('没有可下载的文件');
- summary.style.display = 'none';
- return;
- }
-
- summaryText.textContent = `正在下载 ${allFiles.length} 个文件...`;
-
- // 创建ZIP文件
- const zip = new JSZip();
- let downloadedCount = 0;
-
- // 分批下载文件,避免同时发起太多请求
- const batchSize = 5;
- for (let i = 0; i < allFiles.length; i += batchSize) {
- const batch = allFiles.slice(i, i + batchSize);
-
- // 下载当前批次的所有文件
- await Promise.allSettled(batch.map(file => downloadFileForZip(file, zip)));
-
- downloadedCount += batch.length;
-
- // 更新进度
- const progress = (downloadedCount / allFiles.length) * 100;
- overallProgress.style.width = `${progress}%`;
- summaryText.textContent = `已下载 ${downloadedCount}/${allFiles.length} 个文件 (${Math.round(progress)}%)`;
-
- // 添加延迟以避免请求过于频繁
- await new Promise(resolve => setTimeout(resolve, 500));
- }
-
- summaryText.textContent = '正在生成ZIP文件...';
-
- // 生成ZIP文件
- const zipBlob = await zip.generateAsync({ type: 'blob' });
-
- // 下载ZIP文件
- saveAs(zipBlob, 'folders_download.zip');
- summaryText.textContent = `下载完成!共打包 ${allFiles.length} 个文件`;
-
- // 更新文件夹状态
- folderData.forEach(folder => {
- if (folder.status === 'ready' || folder.status === 'partial') {
- folder.status = 'completed';
- folder.completedFiles = folder.fileCount;
- updateFolderUI(folder);
- }
- });
-
- updateStats();
- updateDownloadButtonState();
- }
-
- // 下载单个文件并添加到ZIP
- async function downloadFileForZip(file, zip) {
- try {
- const params = {
- Bucket: bucketName,
- Key: file.key
- };
-
- const data = await s3.getObject(params).promise();
-
- // 将文件添加到ZIP中,保持文件夹结构
- const folderPath = file.folder + '/';
- const filePath = folderPath + file.name;
-
- zip.file(filePath, data.Body);
-
- // 更新对应文件夹的完成状态
- const folder = folderData.find(f => f.path === file.folder);
- if (folder) {
- const fileObj = folder.files.find(f => f.key === file.key);
- if (fileObj) {
- fileObj.status = 'completed';
- fileObj.progress = 100;
- folder.completedFiles++;
- updateFolderUI(folder);
- }
- }
-
- return true;
- } catch (error) {
- console.error(`下载文件 ${file.key} 失败:`, error);
- return false;
- }
- }
-
- // 更新文件夹UI
- function updateFolderUI(folder) {
- const folderElement = document.getElementById(`folder-${folder.id}`);
- if (!folderElement) return;
-
- const statusElement = folderElement.querySelector('.folder-status');
- const progressBar = folderElement.querySelector('.progress');
- const fileCountElement = folderElement.querySelector('.file-count');
- const fileList = folderElement.querySelector('.file-list');
-
- // 更新状态
- let statusText = '';
- let statusClass = '';
-
- switch (folder.status) {
- case 'pending':
- statusText = '等待中';
- statusClass = 'status-pending';
- break;
- case 'loading':
- statusText = '加载中';
- statusClass = 'status-loading';
- break;
- case 'ready':
- statusText = '准备下载';
- statusClass = 'status-ready';
- break;
- case 'empty':
- statusText = '空文件夹';
- statusClass = 'status-pending';
- break;
- case 'downloading':
- statusText = '下载中';
- statusClass = 'status-downloading';
- break;
- case 'completed':
- statusText = '已完成';
- statusClass = 'status-completed';
- break;
- case 'partial':
- statusText = '部分完成';
- statusClass = 'status-ready';
- break;
- case 'error':
- statusText = '错误';
- statusClass = 'status-error';
- break;
- }
-
- statusElement.textContent = statusText;
- statusElement.className = `folder-status ${statusClass}`;
-
- // 更新文件计数
- fileCountElement.textContent = `${folder.completedFiles}/${folder.fileCount} 个文件`;
-
- // 更新进度条
- if (folder.fileCount > 0) {
- const progress = (folder.completedFiles / folder.fileCount) * 100;
- progressBar.style.width = `${progress}%`;
- }
-
- // 更新文件列表
- if (folder.expanded) {
- fileList.classList.add('expanded');
- renderFileList(folder, fileList);
- }
- }
-
- // 渲染文件列表
- function renderFileList(folder, container) {
- container.innerHTML = '';
-
- folder.files.forEach(file => {
- const fileItem = document.createElement('div');
- fileItem.className = 'file-item';
-
- let fileStatus = '';
- let fileStatusClass = '';
-
- switch (file.status) {
- case 'pending':
- fileStatus = '等待下载';
- break;
- case 'downloading':
- fileStatus = '下载中...';
- break;
- case 'completed':
- fileStatus = '已完成';
- fileStatusClass = 'status-completed';
- break;
- case 'error':
- fileStatus = `错误: ${file.error}`;
- fileStatusClass = 'status-error';
- break;
- }
-
- fileItem.innerHTML = `
- <div class="file-name">${file.name || file.key}</div>
- <div class="file-size">${file.size}</div>
- <div class="folder-status ${fileStatusClass}">${fileStatus}</div>
- `;
-
- container.appendChild(fileItem);
- });
- }
-
- // 渲染文件夹列表
- function renderFolders() {
- foldersContainer.innerHTML = '';
-
- folderData.forEach(folder => {
- const folderElement = document.createElement('div');
- folderElement.className = 'folder-card';
- folderElement.id = `folder-${folder.id}`;
-
- folderElement.innerHTML = `
- <div class="folder-header">
- <div class="folder-name">${folder.path}</div>
- <div class="folder-status status-pending">等待中</div>
- </div>
- <div class="file-count">0/0 个文件</div>
- <div class="progress-bar">
- <div class="progress"></div>
- </div>
- <button class="expand-btn">显示文件</button>
- <div class="file-list"></div>
- `;
-
- // 添加事件监听器
- const expandBtn = folderElement.querySelector('.expand-btn');
- const fileList = folderElement.querySelector('.file-list');
-
- expandBtn.addEventListener('click', () => {
- folder.expanded = !folder.expanded;
- if (folder.expanded) {
- fileList.classList.add('expanded');
- renderFileList(folder, fileList);
- expandBtn.textContent = '隐藏文件';
- } else {
- fileList.classList.remove('expanded');
- expandBtn.textContent = '显示文件';
- }
- });
-
- foldersContainer.appendChild(folderElement);
- updateFolderUI(folder);
- });
- }
-
- // 更新统计信息
- function updateStats() {
- totalFoldersEl.textContent = folderData.length;
- loadedFoldersEl.textContent = folderData.filter(f => f.status !== 'pending').length;
- readyFoldersEl.textContent = folderData.filter(f => f.status === 'ready' || f.status === 'partial').length;
- completedFoldersEl.textContent = folderData.filter(f => f.status === 'completed').length;
- }
-
- // 更新下载按钮状态
- function updateDownloadButtonState() {
- const hasReadyFolders = folderData.some(f =>
- f.status === 'ready' || f.status === 'partial'
- );
- downloadZipBtn.disabled = !hasReadyFolders;
- }
-
- // 格式化文件大小
- function formatFileSize(bytes) {
- if (bytes === 0) return '0 B';
-
- const k = 1024;
- const sizes = ['B', 'KB', 'MB', 'GB'];
- const i = Math.floor(Math.log(bytes) / Math.log(k));
-
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
- }
-
- // 事件监听器
- loadFoldersBtn.addEventListener('click', loadAllFolders);
- downloadZipBtn.addEventListener('click', downloadAllAsZip);
-
- clearAllBtn.addEventListener('click', () => {
- if (confirm('确定要清空所有文件夹吗?')) {
- initializeFolderData();
- summary.style.display = 'none';
- loadFoldersBtn.disabled = false;
- loadFoldersBtn.textContent = '加载所有文件夹';
- updateDownloadButtonState();
- }
- });
-
- // 初始化
- initializeFolderData();
- </script>
- </body>
- </html>
|