41 changed files with 648 additions and 226 deletions
@ -0,0 +1,59 @@ |
|||
<template> |
|||
<div v-if="showRef"> |
|||
<div class="pl-1 truncate">{{ $t('progress.tip') }} {{ messageRef }}</div> |
|||
<q-linear-progress size="20px" :value="percentageRef" color="primary" rounded v-bind="attrs"> </q-linear-progress> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref, useAttrs, onMounted } from 'vue'; |
|||
import { axios, Environment } from '@/platform'; |
|||
|
|||
const props = defineProps({ |
|||
dataUrl: { type: String, default: '' }, |
|||
interval: { type: Number, default: 1000 }, |
|||
}); |
|||
const attrs = useAttrs(); |
|||
|
|||
const showRef = ref(false); |
|||
const percentageRef = ref(0.2); |
|||
const messageRef = ref(''); |
|||
let executeProgressInterval; |
|||
|
|||
const refreshProgress = () => { |
|||
axios |
|||
.get(Environment.apiContextPath(props.dataUrl)) |
|||
.then((response) => { |
|||
const progressInfo = response.data; |
|||
percentageRef.value = progressInfo.currentWeight / progressInfo.totalWeight; |
|||
messageRef.value = progressInfo.messageKey; |
|||
if (percentageRef.value >= 1) { |
|||
clearInterval(executeProgressInterval); |
|||
showRef.value = false; |
|||
} |
|||
}) |
|||
.catch(() => { |
|||
clearInterval(executeProgressInterval); |
|||
showRef.value = false; |
|||
}); |
|||
}; |
|||
|
|||
const start = () => { |
|||
showRef.value = true; |
|||
executeProgressInterval = setInterval(refreshProgress, props.interval); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
axios |
|||
.get(Environment.apiContextPath(props.dataUrl)) |
|||
.then((response) => { |
|||
start(); |
|||
}) |
|||
.catch(() => { |
|||
showRef.value = false; |
|||
}); |
|||
}); |
|||
|
|||
defineExpose({ |
|||
start, |
|||
}); |
|||
</script> |
@ -1,13 +1,15 @@ |
|||
package io.sc.platform.csv.exporter; |
|||
|
|||
import io.sc.platform.core.support.ProgressInfo; |
|||
import io.sc.platform.jdbc.exporter.DataExporter; |
|||
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
|||
|
|||
import javax.sql.DataSource; |
|||
import java.util.Locale; |
|||
|
|||
public class CsvExporter implements DataExporter { |
|||
@Override |
|||
public void export(DataSource dataSource, DataExportConfigure configure) { |
|||
public void export(DataSource dataSource, DataExportConfigure configure, ProgressInfo progressInfo, Locale locale) { |
|||
|
|||
} |
|||
} |
|||
|
@ -0,0 +1,70 @@ |
|||
<template> |
|||
<div v-if="showRef"> |
|||
<div class="pl-1 truncate">{{ $t('progress.tip') }} {{ messageRef }}</div> |
|||
<q-linear-progress size="20px" :value="percentageRef" color="primary" rounded v-bind="attrs"> </q-linear-progress> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref, useAttrs, onMounted } from 'vue'; |
|||
import { axios, Environment } from 'platform-core'; |
|||
|
|||
const props = defineProps({ |
|||
dataUrl: { type: String, default: '' }, |
|||
interval: { type: Number, default: 1000 }, |
|||
}); |
|||
const attrs = useAttrs(); |
|||
|
|||
const showRef = ref(false); |
|||
const percentageRef = ref(0); |
|||
const messageRef = ref(''); |
|||
let executeProgressInterval; |
|||
|
|||
const refreshProgress = () => { |
|||
axios |
|||
.get(Environment.apiContextPath(props.dataUrl)) |
|||
.then((response) => { |
|||
if (response?.data?.running) { |
|||
const progressInfo = response.data; |
|||
percentageRef.value = progressInfo.currentWeight / progressInfo.totalWeight; |
|||
messageRef.value = progressInfo.messageKey; |
|||
if (percentageRef.value >= 1) { |
|||
stop(); |
|||
} |
|||
} else { |
|||
stop(); |
|||
} |
|||
}) |
|||
.catch(() => { |
|||
stop(); |
|||
}); |
|||
}; |
|||
|
|||
const start = () => { |
|||
showRef.value = true; |
|||
percentageRef.value = 0; |
|||
executeProgressInterval = setInterval(refreshProgress, props.interval); |
|||
}; |
|||
|
|||
const stop = () => { |
|||
clearInterval(executeProgressInterval); |
|||
showRef.value = false; |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
axios |
|||
.get(Environment.apiContextPath(props.dataUrl)) |
|||
.then((response) => { |
|||
if (response?.data?.running) { |
|||
start(); |
|||
} |
|||
}) |
|||
.catch(() => { |
|||
stop(); |
|||
}); |
|||
}); |
|||
|
|||
defineExpose({ |
|||
start, |
|||
stop, |
|||
}); |
|||
</script> |
@ -0,0 +1,75 @@ |
|||
<template> |
|||
<q-btn icon="bi-database-down" :label="$t('export')" outline no-caps v-bind="attrs" :loading="showRef" :percentage="percentageRef"> |
|||
<!-- <template #loading> |
|||
<div class="justify-between"> |
|||
<q-icon :name="attrs.icon"></q-icon> |
|||
<span>正在执行...</span> |
|||
<q-btn v-if="showRef" icon="bi-info" title="show detail" dense rounded flat @click.stop.prevent="() => {}"></q-btn> |
|||
</div> |
|||
</template> --> |
|||
</q-btn> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref, useAttrs, onMounted } from 'vue'; |
|||
import { axios, Environment } from 'platform-core'; |
|||
|
|||
const props = defineProps({ |
|||
dataUrl: { type: String, default: '' }, |
|||
interval: { type: Number, default: 1000 }, |
|||
}); |
|||
const attrs = useAttrs(); |
|||
|
|||
const showRef = ref(false); |
|||
const percentageRef = ref(0); |
|||
const messageRef = ref(''); |
|||
let executeProgressInterval; |
|||
|
|||
const refreshProgress = () => { |
|||
axios |
|||
.get(Environment.apiContextPath(props.dataUrl)) |
|||
.then((response) => { |
|||
if (response?.data?.running) { |
|||
const progressInfo = response.data; |
|||
percentageRef.value = (progressInfo.currentWeight / progressInfo.totalWeight) * 100; |
|||
messageRef.value = progressInfo.messageKey; |
|||
if (percentageRef.value >= 100) { |
|||
stop(); |
|||
} |
|||
} else { |
|||
stop(); |
|||
} |
|||
}) |
|||
.catch(() => { |
|||
stop(); |
|||
}); |
|||
}; |
|||
|
|||
const start = () => { |
|||
showRef.value = true; |
|||
percentageRef.value = 0; |
|||
executeProgressInterval = setInterval(refreshProgress, props.interval); |
|||
}; |
|||
|
|||
const stop = () => { |
|||
clearInterval(executeProgressInterval); |
|||
showRef.value = false; |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
axios |
|||
.get(Environment.apiContextPath(props.dataUrl)) |
|||
.then((response) => { |
|||
if (response?.data?.running) { |
|||
start(); |
|||
} |
|||
}) |
|||
.catch(() => { |
|||
stop(); |
|||
}); |
|||
}); |
|||
|
|||
defineExpose({ |
|||
start, |
|||
stop, |
|||
}); |
|||
</script> |
@ -0,0 +1,43 @@ |
|||
package io.sc.platform.jdbc.controller; |
|||
|
|||
import io.sc.platform.core.support.ProgressInfo; |
|||
import io.sc.platform.jdbc.controller.support.ExporterThread; |
|||
import io.sc.platform.jdbc.exporter.exception.ExporterNotRunningException; |
|||
import io.sc.platform.jdbc.exporter.exception.ExporterRunningException; |
|||
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
|||
import io.sc.platform.jdbc.service.JdbcExportService; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Locale; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api/jdbc/export") |
|||
public class JdbcExportWebController { |
|||
@Autowired private JdbcExportService jdbcExportService; |
|||
private ExporterThread thread =null; |
|||
|
|||
@PostMapping("export") |
|||
public void export(@RequestBody DataExportConfigure configure, Locale locale) throws Exception { |
|||
//检查有当前用户启动的执行线程是否正在运行
|
|||
if(thread!=null && thread.isAlive()){ |
|||
throw new ExporterRunningException(); |
|||
} |
|||
//启动新线程
|
|||
thread =new ExporterThread(jdbcExportService,configure,locale); |
|||
thread.start(); |
|||
} |
|||
|
|||
@GetMapping("traceExecuteProgress") |
|||
public ProgressInfo traceExecuteProgress(Locale locale) throws Exception{ |
|||
if(thread!=null && thread.isAlive()){ |
|||
if(thread.getException()!=null){ |
|||
throw thread.getException(); |
|||
} |
|||
return thread.getProgressInfo(); |
|||
}else{ |
|||
return ProgressInfo.notRunning(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,39 @@ |
|||
package io.sc.platform.jdbc.controller.support; |
|||
|
|||
import io.sc.platform.core.support.ProgressInfo; |
|||
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
|||
import io.sc.platform.jdbc.service.JdbcExportService; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
import java.util.Locale; |
|||
|
|||
public class ExporterThread extends Thread { |
|||
private Logger log = LoggerFactory.getLogger(ExporterThread.class); |
|||
private JdbcExportService jdbcExportService; |
|||
private DataExportConfigure exportConfigure; |
|||
private Locale locale; |
|||
private volatile ProgressInfo progressInfo =new ProgressInfo(100,0); |
|||
private Exception exception; |
|||
|
|||
public ExporterThread(JdbcExportService jdbcExportService,DataExportConfigure exportConfigure, Locale locale){ |
|||
this.jdbcExportService =jdbcExportService; |
|||
this.exportConfigure =exportConfigure; |
|||
this.locale =locale; |
|||
} |
|||
@Override |
|||
public void run() { |
|||
try { |
|||
jdbcExportService.export(exportConfigure,progressInfo,locale); |
|||
} catch (Exception e) { |
|||
this.exception =e; |
|||
log.error("",e); |
|||
} |
|||
} |
|||
public ProgressInfo getProgressInfo(){ |
|||
return progressInfo; |
|||
} |
|||
public Exception getException() { |
|||
return exception; |
|||
} |
|||
} |
@ -0,0 +1,5 @@ |
|||
package io.sc.platform.jdbc.exporter.exception; |
|||
|
|||
public class ExporterNotRunningException extends RuntimeException { |
|||
|
|||
} |
@ -0,0 +1,5 @@ |
|||
package io.sc.platform.jdbc.exporter.exception; |
|||
|
|||
public class ExporterRunningException extends RuntimeException { |
|||
|
|||
} |
@ -1,6 +0,0 @@ |
|||
package io.sc.platform.jdbc.exporter.support; |
|||
|
|||
public enum ExportMode { |
|||
SINGLE_FILE, // 单文件
|
|||
MULTI_FILE; // 多文件(每个表一个文件)
|
|||
} |
@ -0,0 +1,10 @@ |
|||
package io.sc.platform.jdbc.service; |
|||
|
|||
import io.sc.platform.core.support.ProgressInfo; |
|||
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
|||
|
|||
import java.util.Locale; |
|||
|
|||
public interface JdbcExportService { |
|||
public void export(DataExportConfigure configure, ProgressInfo progressInfo, Locale locale) throws Exception; |
|||
} |
@ -0,0 +1,43 @@ |
|||
package io.sc.platform.jdbc.service.impl; |
|||
|
|||
import io.sc.platform.core.support.ProgressInfo; |
|||
import io.sc.platform.jdbc.exporter.DataExporter; |
|||
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
|||
import io.sc.platform.jdbc.service.DatasourceService; |
|||
import io.sc.platform.jdbc.service.JdbcExportService; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.util.StringUtils; |
|||
|
|||
import javax.sql.DataSource; |
|||
import java.util.Date; |
|||
import java.util.Locale; |
|||
|
|||
@Service |
|||
public class JdbcExportServiceImpl implements JdbcExportService { |
|||
@Autowired private DatasourceService datasourceService; |
|||
|
|||
@Override |
|||
public void export(DataExportConfigure configure, ProgressInfo progressInfo, Locale locale) throws Exception { |
|||
if(configure==null){ |
|||
return; |
|||
} |
|||
progressInfo.setRunning(true); |
|||
DataSource dataSource =null; |
|||
if(StringUtils.hasText(configure.getDatasource())){ |
|||
dataSource =datasourceService.getDatasource(configure.getDatasource()); |
|||
}else{ |
|||
dataSource =datasourceService.getDefaultDatasource(); |
|||
} |
|||
|
|||
progressInfo.setStartDatetime(new Date()); |
|||
progressInfo.setTotalWeight(100); |
|||
|
|||
DataExporter dataExporter =DataExporter.newInstance(); |
|||
dataExporter.export(dataSource,configure,progressInfo,locale); |
|||
|
|||
//执行完毕
|
|||
progressInfo.setCompletedDatetime(new Date()); |
|||
progressInfo.setCurrentWeight(progressInfo.getTotalWeight()); |
|||
} |
|||
} |
Loading…
Reference in new issue