数据包下载功能
This commit is contained in:
parent
8263f74a2c
commit
9910c1479a
37
oscm/board/src/js/api/dataPackageApi.js
Normal file
37
oscm/board/src/js/api/dataPackageApi.js
Normal file
@ -0,0 +1,37 @@
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
getPackageList(page, size) {
|
||||
return axios.get('/api/data-package/list', {
|
||||
params: {page, size}
|
||||
});
|
||||
},
|
||||
|
||||
getLogList(page, size) {
|
||||
return axios.get('/api/data-package/log/list', {
|
||||
params: {page, size}
|
||||
});
|
||||
},
|
||||
|
||||
downloadPackage(id) {
|
||||
// 1. 先调用后端记录日志
|
||||
axios.get(`/api/data-package/download/${id}`)
|
||||
.then(response => {
|
||||
// 2. 获取文件URL后直接触发下载
|
||||
const fileUrl = response.data;
|
||||
console.log("开始下载:", fileUrl);
|
||||
|
||||
// 方法1:直接跳转(最简单)
|
||||
window.location.href = fileUrl;
|
||||
|
||||
// 方法2:创建隐藏的iframe(避免页面跳转)
|
||||
// const iframe = document.createElement('iframe');
|
||||
// iframe.style.display = 'none';
|
||||
// iframe.src = fileUrl;
|
||||
// document.body.appendChild(iframe);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$message.error("下载失败: " + error.message);
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -12,7 +12,8 @@ import settings from './modules/settings'
|
||||
import wordBank from './modules/wordBank'
|
||||
import sensitiveTarget from "./modules/targetSensitive"
|
||||
import metaDict from "./modules/metaDict"
|
||||
import apiRules from "@/js/modules/apiRules";
|
||||
import apiRules from "@/js/modules/apiRules"
|
||||
import DataPackage from "../modules/dataPackage/DataPackage";
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
@ -32,7 +33,8 @@ export default new Vuex.Store({
|
||||
wordBank,
|
||||
sensitiveTarget,
|
||||
metaDict,
|
||||
apiRules
|
||||
apiRules,
|
||||
DataPackage
|
||||
},
|
||||
strict: debug
|
||||
})
|
||||
@ -6,6 +6,7 @@ import OverView from './modules/overview/Homepage'
|
||||
import LogManage from './modules/log/LogList'
|
||||
import ServerManage from './modules/server/ServerList'
|
||||
import ProjectManage from './modules/project/ProjectList'
|
||||
import DataPackage from "./modules/dataPackage/DataPackage";
|
||||
// import TaskManage from './modules/task/MainFrame'
|
||||
import CommonTaskTab from "@/modules/task/CommonTaskList";
|
||||
import SingleWebsiteTaskTab from "@/modules/task/SingleWebsiteTaskList";
|
||||
@ -66,7 +67,8 @@ const routes = [
|
||||
// {path: 'settings', component: SystemSettings, meta: {keepAlive: true}},
|
||||
{path: 'settings/metaData', component: MetaDataTab, meta: {keepAlive: true}},
|
||||
{path: 'settings/metaDict', component: MetaDictTab, meta: {keepAlive: true}},
|
||||
{path: 'settings/wordBank', component: WordBankTab, meta: {keepAlive: true}}
|
||||
{path: 'settings/wordBank', component: WordBankTab, meta: {keepAlive: true}},
|
||||
{path: 'data-package', component: DataPackage, meta: {keepAlive: true}}
|
||||
]
|
||||
},
|
||||
{path: '/oscm/login', component: login}
|
||||
|
||||
@ -54,6 +54,7 @@
|
||||
<span slot="title">系统管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/oscm/log">运行日志</el-menu-item>
|
||||
<el-menu-item index="/oscm/data-package">数据包操作</el-menu-item>
|
||||
<el-menu-item index="/oscm/settings/wordBank">词库管理</el-menu-item>
|
||||
<el-menu-item index="/oscm/settings/metaData">元数据表格</el-menu-item>
|
||||
<el-menu-item index="/oscm/settings/metaDict">元数据字典</el-menu-item>
|
||||
|
||||
180
oscm/board/src/modules/dataPackage/DataPackage.vue
Normal file
180
oscm/board/src/modules/dataPackage/DataPackage.vue
Normal file
@ -0,0 +1,180 @@
|
||||
<!-- src/views/DataPackage.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="下载列表" name="package">
|
||||
<el-table :data="packageList" style="width: 100%">
|
||||
<el-table-column prop="packageName" label="数据包名称"></el-table-column>
|
||||
<el-table-column prop="createTime" label="上传时间" :formatter="formatDate"></el-table-column>
|
||||
<el-table-column prop="packageSize" label="大小" :formatter="formatSize"></el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button @click="downloadPackage(scope.row.id)" type="primary" size="small">下载</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
@current-change="handlePackagePageChange"
|
||||
:current-page="packagePage.current"
|
||||
:page-size="packagePage.size"
|
||||
:total="packagePage.total"
|
||||
layout="total, prev, pager, next">
|
||||
</el-pagination>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="日志列表" name="log">
|
||||
<el-table :data="logList" style="width: 100%">
|
||||
<el-table-column prop="packageName" label="数据包名称"></el-table-column>
|
||||
<el-table-column prop="operationType" label="操作类型"></el-table-column>
|
||||
<el-table-column prop="operationTime" label="操作时间" :formatter="formatDate"></el-table-column>
|
||||
<el-table-column prop="userName" label="用户名"></el-table-column>
|
||||
<el-table-column prop="userIp" label="IP"></el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
@current-change="handleLogPageChange"
|
||||
:current-page="logPage.current"
|
||||
:page-size="logPage.size"
|
||||
:total="logPage.total"
|
||||
layout="total, prev, pager, next">
|
||||
</el-pagination>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Cascader,
|
||||
Col,
|
||||
Dialog,
|
||||
Divider,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
Option,
|
||||
RadioGroup,
|
||||
Row,
|
||||
Select,
|
||||
TabPane,
|
||||
Tabs,
|
||||
Tag,
|
||||
Tooltip
|
||||
} from 'element-ui'
|
||||
import dataPackageApi from '@/js/api/dataPackageApi';
|
||||
Vue.use(Select)
|
||||
Vue.use(Option)
|
||||
Vue.use(Input)
|
||||
Vue.use(Row)
|
||||
Vue.use(Col)
|
||||
Vue.use(Button)
|
||||
Vue.use(Dialog)
|
||||
Vue.use(Form)
|
||||
Vue.use(FormItem)
|
||||
Vue.use(Divider)
|
||||
Vue.use(Cascader)
|
||||
Vue.use(Dropdown)
|
||||
Vue.use(DropdownMenu)
|
||||
Vue.use(DropdownItem)
|
||||
Vue.use(Tabs)
|
||||
Vue.use(TabPane)
|
||||
Vue.use(RadioGroup)
|
||||
Vue.use(Tag)
|
||||
Vue.use(ButtonGroup)
|
||||
Vue.use(Tooltip)
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'package',
|
||||
packageList: [],
|
||||
logList: [],
|
||||
packagePage: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
logPage: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.fetchPackageList();
|
||||
this.fetchLogList();
|
||||
},
|
||||
methods: {
|
||||
fetchPackageList() {
|
||||
dataPackageApi.getPackageList(this.packagePage.current - 1, this.packagePage.size)
|
||||
.then(response => {
|
||||
this.packageList = response.data.content;
|
||||
this.packagePage.total = response.data.totalElements;
|
||||
});
|
||||
},
|
||||
|
||||
fetchLogList() {
|
||||
dataPackageApi.getLogList(this.logPage.current - 1, this.logPage.size)
|
||||
.then(response => {
|
||||
this.logList = response.data.content;
|
||||
this.logPage.total = response.data.totalElements;
|
||||
});
|
||||
},
|
||||
|
||||
handlePackagePageChange(current) {
|
||||
this.packagePage.current = current;
|
||||
this.fetchPackageList();
|
||||
},
|
||||
|
||||
handleLogPageChange(current) {
|
||||
this.logPage.current = current;
|
||||
this.fetchLogList();
|
||||
},
|
||||
|
||||
downloadPackage(id) {
|
||||
dataPackageApi.downloadPackage(id)
|
||||
.then(response => {
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
// 假设文件名可以从响应头获取
|
||||
const contentDisposition = response.headers['content-disposition'];
|
||||
let fileName = 'package.dat';
|
||||
if (contentDisposition) {
|
||||
const fileNameMatch = contentDisposition.match(/filename="(.+?)"/);
|
||||
if (fileNameMatch && fileNameMatch.length === 2) {
|
||||
fileName = fileNameMatch[1];
|
||||
}
|
||||
}
|
||||
link.setAttribute('download', fileName);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
});
|
||||
},
|
||||
|
||||
formatDate(row, column, cellValue) {
|
||||
if (!cellValue) return '';
|
||||
const date = new Date(cellValue);
|
||||
return date.toLocaleString();
|
||||
},
|
||||
|
||||
formatSize(row, column, cellValue) {
|
||||
if (!cellValue) return '0 B';
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
let size = Number(cellValue);
|
||||
let unitIndex = 0;
|
||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||
size /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
return `${size.toFixed(2)} ${units[unitIndex]}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -69,7 +69,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import {Row, Col, Table, TableColumn, Button, Select, Option, DatePicker, Message, Dialog} from 'element-ui'
|
||||
import {Row, Col, Table, TableColumn, Button, Select, Option, DatePicker, Message, Dialog, Pagination} from 'element-ui'
|
||||
import logApi from '../../js/api/logApi'
|
||||
import projectApi from '../../js/api/projectApi'
|
||||
import mytable from '../components/CustomTable'
|
||||
@ -84,6 +84,7 @@ Vue.use(Select)
|
||||
Vue.use(Option)
|
||||
Vue.use(DatePicker)
|
||||
Vue.use(Dialog)
|
||||
Vue.use(Pagination)
|
||||
export default {
|
||||
name: 'LogManage',
|
||||
props: ['taskid'],
|
||||
|
||||
@ -72,6 +72,10 @@
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<!-- <repositories>-->
|
||||
<!-- <repository>-->
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
package com.jsc.oscm.controller;
|
||||
|
||||
import com.jsc.oscm.entity.DataPackage;
|
||||
import com.jsc.oscm.entity.DataPackageLog;
|
||||
import com.jsc.oscm.service.DataPackageService;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/data-package")
|
||||
public class DataPackageController {
|
||||
@javax.annotation.Resource
|
||||
private DataPackageService dataPackageService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<Page<DataPackage>> getPackageList(
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@RequestParam(defaultValue = "10") int size) {
|
||||
Pageable pageable = PageRequest.of(page, size);
|
||||
return ResponseEntity.ok(dataPackageService.getPackageList(pageable));
|
||||
}
|
||||
|
||||
@GetMapping("/log/list")
|
||||
public ResponseEntity<Page<DataPackageLog>> getLogList(
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@RequestParam(defaultValue = "10") int size) {
|
||||
Pageable pageable = PageRequest.of(page, size);
|
||||
return ResponseEntity.ok(dataPackageService.getLogList(pageable));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Void> addPackage(@RequestBody DataPackage dataPackage) {
|
||||
dataPackageService.addPackage(dataPackage);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@GetMapping("/download/{id}")
|
||||
public ResponseEntity<String> getDownloadUrl(@PathVariable Integer id, HttpServletRequest request) {
|
||||
DataPackage dataPackage = dataPackageService.getPackageById(id);
|
||||
if (dataPackage == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
// 记录下载日志(关键操作)
|
||||
dataPackageService.addLog(dataPackage.getPackageName(), "下载", request);
|
||||
|
||||
// 直接返回Nginx文件URL
|
||||
return ResponseEntity.ok(dataPackage.getDownloadUrl());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.jsc.oscm.dao;
|
||||
|
||||
import com.jsc.oscm.entity.DataPackageLog;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface DataPackageLogRepository extends JpaRepository<DataPackageLog, Integer> {
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.jsc.oscm.dao;
|
||||
|
||||
import com.jsc.oscm.entity.DataPackage;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface DataPackageRepository extends JpaRepository<DataPackage, Integer> {
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.jsc.oscm.entity;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@Table(name = "data_package")
|
||||
public class DataPackage {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "package_name")
|
||||
private String packageName;
|
||||
|
||||
@Column(name = "package_size")
|
||||
private Long packageSize;
|
||||
|
||||
@Column(name = "download_url")
|
||||
private String downloadUrl;
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.jsc.oscm.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "data_package_log")
|
||||
public class DataPackageLog {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "package_name")
|
||||
private String packageName;
|
||||
|
||||
@Column(name = "operation_time")
|
||||
private LocalDateTime operationTime;
|
||||
|
||||
@Column(name = "operation_type")
|
||||
private String operationType;
|
||||
|
||||
@Column(name = "user_name")
|
||||
private String userName;
|
||||
|
||||
@Column(name = "user_ip")
|
||||
private String userIp;
|
||||
|
||||
@Column(name = "user_agent")
|
||||
private String userAgent;
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.jsc.oscm.service;
|
||||
|
||||
import com.jsc.oscm.dao.DataPackageLogRepository;
|
||||
import com.jsc.oscm.dao.DataPackageRepository;
|
||||
import com.jsc.oscm.entity.DataPackage;
|
||||
import com.jsc.oscm.entity.DataPackageLog;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
public class DataPackageService {
|
||||
@Resource
|
||||
private DataPackageRepository dataPackageRepository;
|
||||
|
||||
@Resource
|
||||
private DataPackageLogRepository dataPackageLogRepository;
|
||||
|
||||
public Page<DataPackage> getPackageList(Pageable pageable) {
|
||||
return dataPackageRepository.findAll(pageable);
|
||||
}
|
||||
|
||||
public Page<DataPackageLog> getLogList(Pageable pageable) {
|
||||
return dataPackageLogRepository.findAll(pageable);
|
||||
}
|
||||
|
||||
public void addPackage(DataPackage dataPackage) {
|
||||
dataPackage.setCreateTime(LocalDateTime.now());
|
||||
dataPackageRepository.save(dataPackage);
|
||||
}
|
||||
|
||||
public void addLog(String packageName, String operationType, HttpServletRequest request) {
|
||||
DataPackageLog log = new DataPackageLog();
|
||||
log.setPackageName(packageName);
|
||||
log.setOperationType(operationType);
|
||||
log.setOperationTime(LocalDateTime.now());
|
||||
log.setUserIp(request.getRemoteAddr());
|
||||
log.setUserAgent(request.getHeader("User-Agent"));
|
||||
// 可以从SecurityContext中获取当前用户
|
||||
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
// log.setUserName(authentication.getName());
|
||||
dataPackageLogRepository.save(log);
|
||||
}
|
||||
|
||||
public DataPackage getPackageById(Integer id) {
|
||||
return dataPackageRepository.findById(id).orElse(null);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user