压缩下载
This commit is contained in:
parent
280b9ef75c
commit
d2b6200af8
|
|
@ -0,0 +1,105 @@
|
|||
package com.bonus.imgTool.backstage.controller;
|
||||
|
||||
|
||||
import com.bonus.imgTool.backstage.entity.DownloadRequest;
|
||||
import com.bonus.imgTool.backstage.service.DownloadService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @className:DownloadController
|
||||
* @author:cwchen
|
||||
* @date:2025-04-07-13:23
|
||||
* @version:1.0
|
||||
* @description:文件下载
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/download")
|
||||
@Slf4j
|
||||
public class DownloadController {
|
||||
|
||||
@Autowired
|
||||
private DownloadService downloadService;
|
||||
|
||||
@PostMapping("/start")
|
||||
public ResponseEntity<String> startDownload(@RequestBody DownloadRequest request) {
|
||||
downloadService.startDownloadTask(request.getTaskId(), request.getProId(),request.getType());
|
||||
return ResponseEntity.ok("Download task started");
|
||||
}
|
||||
|
||||
@GetMapping(value = "/progress", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public SseEmitter streamProgress(@RequestParam String taskId) {
|
||||
SseEmitter emitter = new SseEmitter(3600000L); // 1小时超时
|
||||
|
||||
downloadService.addProgressListener(taskId, new DownloadService.DownloadProgressListener() {
|
||||
@Override
|
||||
public void onProgress(String taskId, int progress, int processed, int total) {
|
||||
try {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("type", "progress");
|
||||
data.put("progress", progress);
|
||||
data.put("processed", processed);
|
||||
data.put("total", total);
|
||||
emitter.send(SseEmitter.event().data(data));
|
||||
} catch (IOException e) {
|
||||
log.error(e.toString(),e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(String taskId, String downloadUrl) {
|
||||
try {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("type", "complete");
|
||||
data.put("downloadUrl", downloadUrl);
|
||||
emitter.send(SseEmitter.event().data(data));
|
||||
emitter.complete();
|
||||
} catch (IOException e) {
|
||||
emitter.completeWithError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String taskId, String message) {
|
||||
try {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("type", "error");
|
||||
data.put("message", message);
|
||||
emitter.send(SseEmitter.event().data(data));
|
||||
emitter.complete();
|
||||
} catch (IOException e) {
|
||||
emitter.completeWithError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
@GetMapping("/file")
|
||||
public ResponseEntity<Resource> downloadFile(@RequestParam String taskId) throws IOException {
|
||||
File file = downloadService.getDownloadFile(taskId);
|
||||
if (file == null || !file.exists()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
org.springframework.core.io.Resource resource = new FileSystemResource(file);
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename=\"" + file.getName() + "\"")
|
||||
.contentLength(file.length())
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.body(resource);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.bonus.imgTool.backstage.controller;
|
|||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.hutool.core.io.resource.InputStreamResource;
|
||||
import com.bonus.imgTool.annotation.DecryptAndVerify;
|
||||
import com.bonus.imgTool.annotation.LogAnnotation;
|
||||
import com.bonus.imgTool.backstage.entity.ProClassifyStatisticsVo;
|
||||
|
|
@ -16,9 +17,12 @@ import com.bonus.imgTool.system.vo.SysWhiteVo;
|
|||
import com.bonus.imgTool.utils.ServerResponse;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.google.common.net.HttpHeaders;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
|
@ -29,6 +33,9 @@ import javax.annotation.Resource;
|
|||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ public interface SynthesisQueryDao {
|
|||
|
||||
/**
|
||||
* 综合查询-照片综合查询-照片数量
|
||||
*
|
||||
* @param dto
|
||||
* @return SynthesisNumVo
|
||||
* @author cwchen
|
||||
|
|
@ -27,6 +28,7 @@ public interface SynthesisQueryDao {
|
|||
|
||||
/**
|
||||
* 照片综合查询
|
||||
*
|
||||
* @param dto
|
||||
* @return List<SynthesisQueryVo>
|
||||
* @author cwchen
|
||||
|
|
@ -36,6 +38,7 @@ public interface SynthesisQueryDao {
|
|||
|
||||
/**
|
||||
* 收藏/取消收藏图片
|
||||
*
|
||||
* @param dto
|
||||
* @return void
|
||||
* @author cwchen
|
||||
|
|
@ -49,6 +52,7 @@ public interface SynthesisQueryDao {
|
|||
|
||||
/**
|
||||
* 生成水印照片
|
||||
*
|
||||
* @param vo
|
||||
* @return void
|
||||
* @author cwchen
|
||||
|
|
@ -58,6 +62,7 @@ public interface SynthesisQueryDao {
|
|||
|
||||
/**
|
||||
* 获取水印照片地址
|
||||
*
|
||||
* @param vo
|
||||
* @return String
|
||||
* @author cwchen
|
||||
|
|
@ -67,6 +72,7 @@ public interface SynthesisQueryDao {
|
|||
|
||||
/**
|
||||
* 项目分类统计
|
||||
*
|
||||
* @param dto
|
||||
* @return List<ProClassifyStatisticsVo>
|
||||
* @author cwchen
|
||||
|
|
@ -78,6 +84,7 @@ public interface SynthesisQueryDao {
|
|||
|
||||
/**
|
||||
* 项目分类统计-查看图片
|
||||
*
|
||||
* @param dto
|
||||
* @return List<SynthesisQueryVo>
|
||||
* @author cwchen
|
||||
|
|
@ -87,6 +94,7 @@ public interface SynthesisQueryDao {
|
|||
|
||||
/**
|
||||
* 项目分类统计-查看列表
|
||||
*
|
||||
* @param dto
|
||||
* @return List<ProClassifyStatisticDetailVo>
|
||||
* @author cwchen
|
||||
|
|
@ -96,10 +104,21 @@ public interface SynthesisQueryDao {
|
|||
|
||||
/**
|
||||
* 获取图片
|
||||
*
|
||||
* @param detailVo
|
||||
* @return List<SynthesisQueryVo>
|
||||
* @author cwchen
|
||||
* @date 2025/4/6 18:35
|
||||
*/
|
||||
List<SynthesisQueryVo> getImgs(@Param("params") ProClassifyStatisticDetailVo detailVo, @Param("type") int type);
|
||||
|
||||
/**
|
||||
* 查询原图/水印照片
|
||||
* @param proId
|
||||
* @param type
|
||||
* @return List<String>
|
||||
* @author cwchen
|
||||
* @date 2025/4/7 10:59
|
||||
*/
|
||||
List<Photo> findByAlbumId(@Param("proId") String proId, @Param("type") String type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.bonus.imgTool.backstage.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @className:DownloadFileVo
|
||||
* @author:cwchen
|
||||
* @date:2025-04-07-11:03
|
||||
* @version:1.0
|
||||
* @description:
|
||||
*/
|
||||
@Data
|
||||
public class DownloadFileVo {
|
||||
|
||||
private String path;
|
||||
|
||||
private String uploadTypeName;
|
||||
|
||||
private String uploadType;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.bonus.imgTool.backstage.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @className:DownloadRequest
|
||||
* @author:cwchen
|
||||
* @date:2025-04-07-13:30
|
||||
* @version:1.0
|
||||
* @description:
|
||||
*/
|
||||
@Data
|
||||
public class DownloadRequest {
|
||||
|
||||
private String taskId;
|
||||
private String proId;
|
||||
private String type;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.bonus.imgTool.backstage.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @className:Photo
|
||||
* @author:cwchen
|
||||
* @date:2025-04-07-13:31
|
||||
* @version:1.0
|
||||
* @description:
|
||||
*/
|
||||
@Data
|
||||
public class Photo {
|
||||
private String photoId;
|
||||
private String albumId;
|
||||
private String filePath;
|
||||
private String uploadTypeName;
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
package com.bonus.imgTool.backstage.service;
|
||||
|
||||
import com.bonus.imgTool.backstage.dao.SynthesisQueryDao;
|
||||
import com.bonus.imgTool.backstage.entity.Photo;
|
||||
import com.bonus.imgTool.backstage.entity.ProClassifyStatisticDetailVo;
|
||||
import com.bonus.imgTool.utils.SystemUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* @className:DownloadService
|
||||
* @author:cwchen
|
||||
* @date:2025-04-07-10:46
|
||||
* @version:1.0
|
||||
* @description: 原图/水印下载
|
||||
*/
|
||||
@Service(value = "DownloadService")
|
||||
public class DownloadService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DownloadService.class);
|
||||
|
||||
|
||||
@Value("${download.temp.dir:/tmp/downloads}")
|
||||
private String tempDir;
|
||||
|
||||
@Value("${download.output.dir}")
|
||||
private String outputDir;
|
||||
|
||||
@Resource(name = "SynthesisQueryDao")
|
||||
private SynthesisQueryDao synthesisQueryDao;
|
||||
|
||||
private final Map<String, List<DownloadProgressListener>> progressListeners = new ConcurrentHashMap<>();
|
||||
private final Map<String, String> taskFileMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Async
|
||||
public void startDownloadTask(String taskId, String proId,String type) {
|
||||
Path tempDirPath = null;
|
||||
try {
|
||||
// 准备临时目录
|
||||
tempDirPath = Paths.get(tempDir, taskId);
|
||||
Files.createDirectories(tempDirPath);
|
||||
Path zipFilePath = tempDirPath.resolve("photos.zip");
|
||||
// 获取照片列表
|
||||
List<Photo> photos = getPhotosForAlbum(proId,type);
|
||||
int total = photos.size();
|
||||
// 创建ZIP文件
|
||||
try (ZipOutputStream zos = new ZipOutputStream(
|
||||
new BufferedOutputStream(Files.newOutputStream(zipFilePath)))) {
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int processed = 0;
|
||||
for (Photo photo : photos) {
|
||||
String path = SystemUtils.getUploadPath() + File.separator + photo.getFilePath();
|
||||
Path photoPath = Paths.get(path);
|
||||
String uniqueEntryName = "photos/" + photo.getPhotoId() + "_" + photoPath.getFileName();
|
||||
ZipEntry entry = new ZipEntry(uniqueEntryName);
|
||||
zos.putNextEntry(entry);
|
||||
|
||||
try (InputStream is = Files.newInputStream(photoPath)) {
|
||||
int len;
|
||||
while ((len = is.read(buffer)) > 0) {
|
||||
zos.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
zos.closeEntry();
|
||||
processed++;
|
||||
// 更新进度 (每处理5%或至少每10张照片更新一次)
|
||||
if (processed % Math.max(10, total/20) == 0 || processed == total) {
|
||||
int progress = (int) ((processed * 100.0) / total);
|
||||
notifyProgress(taskId, progress, processed, total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移动到输出目录
|
||||
Path outputDirPath = Paths.get(outputDir);
|
||||
Files.createDirectories(outputDirPath);
|
||||
Path finalFilePath = outputDirPath.resolve(taskId + ".zip");
|
||||
Files.move(zipFilePath, finalFilePath, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
// 记录文件位置
|
||||
taskFileMap.put(taskId, finalFilePath.toString());
|
||||
// 通知完成
|
||||
notifyComplete(taskId, "/imgTool/api/download/file?taskId=" + taskId);
|
||||
} catch (Exception e) {
|
||||
logger.error("下载任务失败: " + taskId, e);
|
||||
notifyError(taskId, "文件生成失败: " + e.getMessage());
|
||||
} finally {
|
||||
// 清理临时目录
|
||||
if (tempDirPath != null) {
|
||||
try {
|
||||
FileUtils.deleteDirectory(tempDirPath.toFile());
|
||||
} catch (IOException e) {
|
||||
logger.warn("清理临时目录失败: " + tempDirPath, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addProgressListener(String taskId, DownloadProgressListener listener) {
|
||||
progressListeners.computeIfAbsent(taskId, k -> new CopyOnWriteArrayList<>()).add(listener);
|
||||
}
|
||||
|
||||
public File getDownloadFile(String taskId) {
|
||||
String filePath = taskFileMap.get(taskId);
|
||||
return filePath != null ? new File(filePath) : null;
|
||||
}
|
||||
|
||||
private List<Photo> getPhotosForAlbum(String proId,String type) {
|
||||
// 实现获取照片列表的逻辑
|
||||
// 返回包含所有照片路径的列表
|
||||
List<Photo> list = Optional.ofNullable(synthesisQueryDao.findByAlbumId(proId,type)).orElseGet(ArrayList::new);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void notifyProgress(String taskId, int progress, int processed, int total) {
|
||||
List<DownloadProgressListener> listeners = progressListeners.get(taskId);
|
||||
if (listeners != null) {
|
||||
listeners.forEach(l -> l.onProgress(taskId, progress, processed, total));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyComplete(String taskId, String downloadUrl) {
|
||||
List<DownloadProgressListener> listeners = progressListeners.remove(taskId);
|
||||
if (listeners != null) {
|
||||
listeners.forEach(l -> l.onComplete(taskId, downloadUrl));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyError(String taskId, String message) {
|
||||
List<DownloadProgressListener> listeners = progressListeners.remove(taskId);
|
||||
if (listeners != null) {
|
||||
listeners.forEach(l -> l.onError(taskId, message));
|
||||
}
|
||||
}
|
||||
|
||||
public interface DownloadProgressListener {
|
||||
void onProgress(String taskId, int progress, int processed, int total);
|
||||
void onComplete(String taskId, String downloadUrl);
|
||||
void onError(String taskId, String message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.bonus.imgTool.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* @className:AsyncConfig
|
||||
* @author:cwchen
|
||||
* @date:2025-04-07-13:29
|
||||
* @version:1.0
|
||||
* @description:
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
public class AsyncConfig implements AsyncConfigurer {
|
||||
|
||||
@Override
|
||||
public Executor getAsyncExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(2);
|
||||
executor.setMaxPoolSize(4);
|
||||
executor.setQueueCapacity(10);
|
||||
executor.setThreadNamePrefix("DownloadTask-");
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
|
|
@ -57,6 +57,8 @@ public class SpringThreadPoolConfig {
|
|||
executor.setThreadNamePrefix(threadNamePrefix);
|
||||
// 线程池对拒绝任务的处理策略
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
// 允许核心线程在空闲时被回收
|
||||
executor.setAllowCoreThreadTimeOut(true);
|
||||
// 初始化
|
||||
executor.initialize();
|
||||
return executor;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ public class SystemUtils {
|
|||
*/
|
||||
public static String getUploadPath() {
|
||||
String os = getSystem();
|
||||
System.err.println("当前系统是=" + os);
|
||||
if ("windows".equals(os)) {
|
||||
return windowsPath;
|
||||
} else if ("linux".equals(os)) {
|
||||
|
|
|
|||
|
|
@ -357,6 +357,17 @@
|
|||
AND sfr.source_id = #{params.id} AND sfr.upload_type = #{params.uploadType} AND sfr.source_type = #{type} AND sfr.is_active = '1'
|
||||
</where>
|
||||
</select>
|
||||
<!--查询原图/水印照片-->
|
||||
<select id="findByAlbumId" resultType="com.bonus.imgTool.backstage.entity.Photo">
|
||||
SELECT sfr.id AS photoId,
|
||||
IF(#{type} = '1',sfr.original_file_path,sfr.watermark_file_path) AS filePath,
|
||||
CASE sfr.upload_type WHEN '1' THEN '安全违章' WHEN '2' THEN '质量检查' WHEN '3' THEN '安全措施落实'
|
||||
WHEN '4' THEN '协调照片' WHEN '5' THEN '重要事项及宣传类' ELSE '' END AS uploadTypeName
|
||||
FROM tb_comprehensive_query tcq
|
||||
LEFT JOIN sys_file_resource sfr ON tcq.id = sfr.source_id AND tcq.upload_type = sfr.upload_type AND sfr.is_active = '1'
|
||||
WHERE tcq.pro_id = #{proId} AND tcq.is_active = '1'
|
||||
ORDER BY sfr.create_time DESC
|
||||
</select>
|
||||
<!--收藏/取消收藏图片-->
|
||||
<update id="collectData">
|
||||
<if test="collectType == 1">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
let proId = decryptCBC(getUrlParam('proId'));
|
||||
let type = decryptCBC(getUrlParam('type'));
|
||||
let title = decryptCBC(getUrlParam('title'));
|
||||
let proName = decryptCBC(getUrlParam('proName'));
|
||||
$('#title').html(proName +"-"+ title);
|
||||
document.getElementById('downloadBtn').addEventListener('click', function() {
|
||||
const btn = this;
|
||||
btn.disabled = true;
|
||||
document.getElementById('progressContainer').style.display = 'block';
|
||||
// 创建任务ID
|
||||
const taskId = 'task_' + Date.now();
|
||||
// 使用EventSource接收服务器推送的进度更新
|
||||
const eventSource = new EventSource(`/imgTool/api/download/progress?taskId=${taskId}`);
|
||||
eventSource.onmessage = function(event) {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data.type === 'progress') {
|
||||
// 更新进度条
|
||||
document.getElementById('progress').style.width = data.progress + '%';
|
||||
document.getElementById('statusText').textContent =
|
||||
`正在压缩: ${data.progress}% (已处理 ${data.processed} / ${data.total} 文件)`;
|
||||
}
|
||||
else if (data.type === 'complete') {
|
||||
// 完成处理
|
||||
document.getElementById('progress').style.width = '100%';
|
||||
document.getElementById('statusText').textContent = '压缩完成!';
|
||||
// 显示下载通知
|
||||
const notification = document.getElementById('downloadNotification');
|
||||
const downloadLink = document.getElementById('downloadLink');
|
||||
downloadLink.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
window.location.href = data.downloadUrl;
|
||||
notification.style.display = 'none';
|
||||
window.close();
|
||||
};
|
||||
notification.style.display = 'block';
|
||||
// 2小时后自动隐藏通知
|
||||
setTimeout(() => {
|
||||
notification.style.display = 'none';
|
||||
}, 1000 * 60 * 60 * 2);
|
||||
// 关闭EventSource连接
|
||||
eventSource.close();
|
||||
}
|
||||
else if (data.type === 'error') {
|
||||
// 错误处理
|
||||
document.getElementById('statusText').textContent = '错误: ' + data.message;
|
||||
btn.disabled = false;
|
||||
eventSource.close();
|
||||
}
|
||||
};
|
||||
eventSource.onerror = function() {
|
||||
document.getElementById('statusText').textContent = '连接出错,请重试';
|
||||
btn.disabled = false;
|
||||
eventSource.close();
|
||||
};
|
||||
// 启动下载任务
|
||||
fetch('/imgTool/api/download/start', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
taskId: taskId,
|
||||
proId: proId,
|
||||
type: type,
|
||||
})
|
||||
}).catch(error => {
|
||||
document.getElementById('statusText').textContent = '启动任务失败';
|
||||
btn.disabled = false;
|
||||
eventSource.close();
|
||||
});
|
||||
});
|
||||
|
|
@ -112,8 +112,8 @@ function initTable(dataList, limit, page) {
|
|||
templet: function (d) {
|
||||
let html = '';
|
||||
let view = "<a class='layui-icon layui-icon-file' style='cursor:pointer;' title='详情' onclick='viewData("+JSON.stringify(d)+")'></a>"
|
||||
let originalDownload = "<a class='layui-icon layui-icon-download-circle' style='cursor:pointer;' title='原图下载' onclick='delData('" + d.id + "')'></a>"
|
||||
let waterDownload = "<a class='layui-icon layui-icon-download-circle' style='cursor:pointer;' title='水印下载' onclick='addProcesses('" + d.id + "')'></a>";
|
||||
let originalDownload = "<a class='layui-icon layui-icon-download-circle' style='cursor:pointer;' title='原图下载' onclick='downloadFile("+JSON.stringify(d)+",1)'></a>"
|
||||
let waterDownload = "<a class='layui-icon layui-icon-download-circle' style='cursor:pointer;' title='水印下载' onclick='downloadFile("+JSON.stringify(d)+",2)'></a>";
|
||||
html = view + originalDownload + waterDownload;
|
||||
return html;
|
||||
}
|
||||
|
|
@ -203,4 +203,10 @@ function downloadExcel(){
|
|||
};
|
||||
// xhr.send(params);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
/**下载原图/水印*/
|
||||
function downloadFile(obj,type){
|
||||
let title = type === 1 ? "原图下载" : "水印下载";
|
||||
window.open("./fileDownload.html?type="+encryptCBC(type)+"&proId="+encryptCBC(obj.proId) + "&title=" + encryptCBC(title) + "&proName=" + encryptCBC(obj.proName));
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>图片下载</title>
|
||||
<script src="../../js/libs/jquery-3.7.0.min.js" charset="UTF-8" type="text/javascript"></script>
|
||||
<script src="../../js/publicJs.js"></script>
|
||||
<script src="../../js/commonUtils.js"></script>
|
||||
<script src="../../js/openIframe.js"></script>
|
||||
<script src="../../js/my/aes.js"></script>
|
||||
<script src="../../js/ajaxRequest.js"></script>
|
||||
</head>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#downloadBtn {
|
||||
padding: 10px 20px;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
#downloadBtn:disabled {
|
||||
background-color: #cccccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
#progressContainer {
|
||||
margin-top: 20px;
|
||||
display: none;
|
||||
}
|
||||
#progressBar {
|
||||
width: 100%;
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 4px;
|
||||
height: 20px;
|
||||
}
|
||||
#progress {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background-color: #4CAF50;
|
||||
border-radius: 4px;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
#statusText {
|
||||
margin-top: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.notification {
|
||||
position: fixed;
|
||||
bottom: 70%;
|
||||
right: 55%;
|
||||
padding: 15px;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
display: none;
|
||||
z-index: 1000;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h3 id="title">照片下载中心</h3>
|
||||
<p>点击下方按钮下载所有照片</p>
|
||||
|
||||
<button id="downloadBtn">下载照片压缩包</button>
|
||||
|
||||
<div id="progressContainer">
|
||||
<div id="progressBar">
|
||||
<div id="progress"></div>
|
||||
</div>
|
||||
<div id="statusText">准备中...</div>
|
||||
</div>
|
||||
|
||||
<div id="downloadNotification" class="notification">
|
||||
您的照片压缩包已准备好!<a href="#" id="downloadLink" style="color: white; text-decoration: underline;">点击下载</a>
|
||||
</div>
|
||||
</body>
|
||||
<script src="../../js/synthesisQuery/fileDownload.js" charset="UTF-8" type="text/javascript"></script>
|
||||
</html>
|
||||
Loading…
Reference in New Issue