feat(数据集): 完成添加SQL的UI。使用umy-ui替换element-ui中el-table,支持超多行、列(上万数据)的table虚拟,grid虚拟,table不会卡顿

This commit is contained in:
junjie 2021-03-15 12:25:11 +08:00
parent 105d8a2a5f
commit 8d911cd463
11 changed files with 204 additions and 52 deletions

View File

@ -65,4 +65,9 @@ public class DataSetTableController {
public Map<String, Object> getPreviewData(@RequestBody DataSetTableRequest dataSetTableRequest) throws Exception {
return dataSetTableService.getPreviewData(dataSetTableRequest);
}
@PostMapping("sqlPreview")
public Map<String, Object> getSQLPreview(@RequestBody DataSetTableRequest dataSetTableRequest) throws Exception {
return dataSetTableService.getSQLPreview(dataSetTableRequest);
}
}

View File

@ -4,6 +4,7 @@ import io.dataease.base.domain.Datasource;
import io.dataease.datasource.dto.TableFiled;
import io.dataease.datasource.request.DatasourceRequest;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
@ -13,6 +14,8 @@ public abstract class DatasourceProvider {
abstract public List<String[]> getData(DatasourceRequest datasourceRequest) throws Exception;
abstract public ResultSet getDataResultSet(DatasourceRequest datasourceRequest) throws Exception;
abstract public List<String> getTables(DatasourceRequest datasourceRequest) throws Exception;
public List<TableFiled> getTableFileds(DatasourceRequest datasourceRequest) throws Exception{
@ -27,4 +30,8 @@ public abstract class DatasourceProvider {
abstract public List<String[]> getPageData(DatasourceRequest datasourceRequest) throws Exception;
abstract public List<String[]> fetchResult(ResultSet rs) throws Exception;
abstract public List<String> fetchResultField(ResultSet rs) throws Exception;
}

View File

@ -8,12 +8,13 @@ import io.dataease.datasource.dto.TableFiled;
import io.dataease.datasource.request.DatasourceRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.sql.*;
import java.text.MessageFormat;
import java.util.*;
@Service("jdbc")
public class JdbcProvider extends DatasourceProvider{
public class JdbcProvider extends DatasourceProvider {
@Override
@ -25,33 +26,48 @@ public class JdbcProvider extends DatasourceProvider{
ResultSet rs = stat.executeQuery(datasourceRequest.getQuery())
) {
list = fetchResult(rs);
} catch (SQLException e){
} catch (SQLException e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}catch (Exception e) {
} catch (Exception e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}
return list;
}
@Override
public ResultSet getDataResultSet(DatasourceRequest datasourceRequest) throws Exception {
ResultSet rs;
try {
Connection connection = getConnection(datasourceRequest);
Statement stat = connection.createStatement();
rs = stat.executeQuery(datasourceRequest.getQuery());
} catch (SQLException e) {
throw new Exception("ERROR:" + e.getMessage(), e);
} catch (Exception e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}
return rs;
}
@Override
public List<String[]> getPageData(DatasourceRequest datasourceRequest) throws Exception {
List<String[]> list = new LinkedList<>();
try (
Connection connection = getConnection(datasourceRequest);
Statement stat = connection.createStatement();
ResultSet rs = stat.executeQuery(datasourceRequest.getQuery() + MessageFormat.format(" LIMIT {0}, {1}", (datasourceRequest.getStartPage() -1)*datasourceRequest.getPageSize(), datasourceRequest.getPageSize()))
ResultSet rs = stat.executeQuery(datasourceRequest.getQuery() + MessageFormat.format(" LIMIT {0}, {1}", (datasourceRequest.getStartPage() - 1) * datasourceRequest.getPageSize(), datasourceRequest.getPageSize()))
) {
list = fetchResult(rs);
} catch (SQLException e){
} catch (SQLException e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}catch (Exception e) {
} catch (Exception e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}
return list;
}
private List<String[]> fetchResult( ResultSet rs) throws Exception{
@Override
public List<String[]> fetchResult(ResultSet rs) throws Exception {
List<String[]> list = new LinkedList<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
@ -73,13 +89,24 @@ public class JdbcProvider extends DatasourceProvider{
return list;
}
@Override
public List<String> fetchResultField(ResultSet rs) throws Exception {
List<String> fieldList = new ArrayList<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
for (int j = 0; j < columnCount; j++) {
fieldList.add(metaData.getColumnName(j + 1));
}
return fieldList;
}
@Override
public List<String> getTables(DatasourceRequest datasourceRequest) throws Exception {
List<String> tables = new ArrayList<>();
String queryStr = getTablesSql(datasourceRequest);
try (Connection con = getConnection(datasourceRequest); Statement ps = con.createStatement()) {
ResultSet resultSet = ps.executeQuery(queryStr);
while (resultSet.next()){
while (resultSet.next()) {
tables.add(resultSet.getString(1));
}
} catch (Exception e) {
@ -89,22 +116,22 @@ public class JdbcProvider extends DatasourceProvider{
}
@Override
public List<TableFiled> getTableFileds(DatasourceRequest datasourceRequest) throws Exception{
public List<TableFiled> getTableFileds(DatasourceRequest datasourceRequest) throws Exception {
List<TableFiled> list = new LinkedList<>();
try (
Connection connection = getConnection(datasourceRequest);
Connection connection = getConnection(datasourceRequest);
) {
DatabaseMetaData databaseMetaData = connection.getMetaData();
ResultSet resultSet = databaseMetaData.getColumns(null, "%", datasourceRequest.getTable().toUpperCase(), "%");
while (resultSet.next()) {
String tableName = resultSet.getString("TABLE_NAME");
String database = resultSet.getString("TABLE_CAT");
if(tableName.equals(datasourceRequest.getTable()) && database.equalsIgnoreCase(getDatabase(datasourceRequest))){
if (tableName.equals(datasourceRequest.getTable()) && database.equalsIgnoreCase(getDatabase(datasourceRequest))) {
TableFiled tableFiled = new TableFiled();
String colName = resultSet.getString("COLUMN_NAME");
tableFiled.setFieldName(colName);
String remarks = resultSet.getString("REMARKS");
if(remarks == null || remarks.equals("")){
if (remarks == null || remarks.equals("")) {
remarks = colName;
}
tableFiled.setRemarks(remarks);
@ -113,13 +140,15 @@ public class JdbcProvider extends DatasourceProvider{
list.add(tableFiled);
}
}
} catch (SQLException e){
} catch (SQLException e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}catch (Exception e) {
} catch (Exception e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}
return list;
};
}
;
@Override
public void test(DatasourceRequest datasourceRequest) throws Exception {
@ -132,7 +161,7 @@ public class JdbcProvider extends DatasourceProvider{
}
public Long count(DatasourceRequest datasourceRequest)throws Exception{
public Long count(DatasourceRequest datasourceRequest) throws Exception {
try (Connection con = getConnection(datasourceRequest); Statement ps = con.createStatement()) {
ResultSet resultSet = ps.executeQuery(datasourceRequest.getQuery());
while (resultSet.next()) {
@ -150,16 +179,16 @@ public class JdbcProvider extends DatasourceProvider{
String driver = null;
String jdbcurl = null;
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
switch (datasourceType){
switch (datasourceType) {
case mysql:
MysqlConfigrationDTO mysqlConfigrationDTO = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfigrationDTO.class);
MysqlConfigrationDTO mysqlConfigrationDTO = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfigrationDTO.class);
username = mysqlConfigrationDTO.getUsername();
password = mysqlConfigrationDTO.getPassword();
driver = mysqlConfigrationDTO.getDriver();
jdbcurl = mysqlConfigrationDTO.getJdbc();
break;
case sqlServer:
SqlServerConfigration sqlServerConfigration= new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfigration.class);
SqlServerConfigration sqlServerConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfigration.class);
username = sqlServerConfigration.getUsername();
password = sqlServerConfigration.getPassword();
driver = sqlServerConfigration.getDriver();
@ -178,7 +207,7 @@ public class JdbcProvider extends DatasourceProvider{
return DriverManager.getConnection(jdbcurl, props);
}
private String getDatabase(DatasourceRequest datasourceRequest){
private String getDatabase(DatasourceRequest datasourceRequest) {
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
switch (datasourceType) {
case mysql:
@ -192,9 +221,9 @@ public class JdbcProvider extends DatasourceProvider{
}
}
private String getTablesSql(DatasourceRequest datasourceRequest){
private String getTablesSql(DatasourceRequest datasourceRequest) {
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
switch (datasourceType){
switch (datasourceType) {
case mysql:
return "show tables;";
case sqlServer:

View File

@ -21,6 +21,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.sql.ResultSet;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;
@ -150,7 +151,7 @@ public class DataSetTableService {
List<DatasetTableField> fields = dataSetTableFieldsService.list(datasetTableField);
String[] fieldArray = fields.stream().map(DatasetTableField::getOriginName).toArray(String[]::new);
datasourceRequest.setQuery(createQuerySQL(ds.getType(), table, fieldArray) + " LIMIT 0,10");
datasourceRequest.setQuery(createQuerySQL(ds.getType(), table, fieldArray) + " LIMIT 0,10");// todo limit
List<String[]> data = new ArrayList<>();
try {
@ -177,6 +178,35 @@ public class DataSetTableService {
return map;
}
public Map<String, Object> getSQLPreview(DataSetTableRequest dataSetTableRequest) throws Exception {
Datasource ds = datasourceMapper.selectByPrimaryKey(dataSetTableRequest.getDataSourceId());
DatasourceProvider datasourceProvider = ProviderFactory.getProvider(ds.getType());
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setDatasource(ds);
String sql = new Gson().fromJson(dataSetTableRequest.getInfo(), DataTableInfoDTO.class).getSql();
datasourceRequest.setQuery(sql);
ResultSet dataResultSet = datasourceProvider.getDataResultSet(datasourceRequest);
List<String[]> data = datasourceProvider.fetchResult(dataResultSet);
List<String> fields = datasourceProvider.fetchResultField(dataResultSet);
List<Map<String, Object>> jsonArray = new ArrayList<>();
if (CollectionUtils.isNotEmpty(data)) {
jsonArray = data.stream().map(ele -> {
Map<String, Object> map = new HashMap<>();
for (int i = 0; i < ele.length; i++) {
map.put(fields.get(i), ele[i]);
}
return map;
}).collect(Collectors.toList());
}
Map<String, Object> map = new HashMap<>();
map.put("fields", fields);
map.put("data", jsonArray);
return map;
}
public List<String[]> getDataSetData(String datasourceId, String table, List<DatasetTableField> fields) {
List<String[]> data = new ArrayList<>();
Datasource ds = datasourceMapper.selectByPrimaryKey(datasourceId);

View File

@ -27,6 +27,7 @@
"screenfull": "4.2.0",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.2",
"umy-ui": "^1.1.6",
"vue": "2.6.10",
"vue-codemirror": "^4.0.6",
"vue-i18n": "7.3.2",

View File

@ -666,7 +666,8 @@ export default {
close: '关闭',
required: '必填',
input_content: '请输入内容',
add_sql_table: '添加SQL'
add_sql_table: '添加SQL',
preview: '预览'
},
datasource: {
create: '新建数据连接',

View File

@ -28,6 +28,10 @@ import * as echarts from 'echarts'
Vue.prototype.$echarts = echarts
import UmyUi from 'umy-ui'
import 'umy-ui/lib/theme-chalk/index.css'// 引入样式
Vue.use(UmyUi)
/**
* If you don't want to use mock-server
* you want to use MockJs for mock api

View File

@ -3,7 +3,7 @@
<el-dropdown trigger="click" size="small">
<span class="el-dropdown-link">
<el-tag size="small" class="item-axis">
{{ item.name }}<span class="summary-span">{{ $t('chart.'+item.summary) }}</span><i class="el-icon-arrow-down el-icon--right" />
{{ item.name }}<span v-if="item.summary" class="summary-span">{{ $t('chart.'+item.summary) }}</span><i class="el-icon-arrow-down el-icon--right" />
</el-tag>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-notebook-2">

View File

@ -394,8 +394,8 @@ export default {
}
.item {
padding: 3px 10px;
margin: 3px 3px 0 3px;
padding: 2px 10px;
margin: 2px 2px 0 2px;
border: solid 1px #eee;
text-align: left;
color: #606266;
@ -403,15 +403,15 @@ export default {
}
.item-on-move {
padding: 3px 10px;
margin: 3px 3px 0 3px;
padding: 2px 10px;
margin: 2px 2px 0 2px;
border: solid 1px #eee;
text-align: left;
color: #606266;
}
.item + .item {
margin-top: 3px;
margin-top: 2px;
}
.item:hover {

View File

@ -28,7 +28,11 @@
</el-select>
</el-form-item>
<el-form-item class="form-item">
<el-input v-model="name" size="mini" placeholder="名称" />
<el-input v-model="name" size="mini" :placeholder="$t('commons.name')" />
</el-form-item>
<el-form-item class="form-item">
<el-radio v-model="mode" label="0">{{ $t('dataset.direct_connect') }}</el-radio>
<el-radio v-model="mode" label="1">{{ $t('dataset.sync_data') }}</el-radio>
</el-form-item>
</el-form>
</el-row>
@ -45,12 +49,38 @@
/>
</el-col>
</el-row>
<el-row style="margin-top: 10px;">
<el-card class="box-card dataPreview" shadow="never">
<div slot="header" class="clearfix">
<span>{{ $t('dataset.data_preview') }}</span>
<el-button style="float: right; padding: 3px 0" type="text" size="mini" @click="getSQLPreview">{{ $t('dataset.preview') }}</el-button>
</div>
<div class="text item">
<ux-grid
ref="plxTable"
size="mini"
style="width: 100%;"
:height="500"
:checkbox-config="{highlight: true}"
>
<ux-table-column
v-for="field in fields"
:key="field"
min-width="200px"
:field="field"
:title="field"
:resizable="true"
/>
</ux-grid>
</div>
</el-card>
</el-row>
</el-row>
</el-col>
</template>
<script>
import { listDatasource } from '@/api/dataset/dataset'
import { post, listDatasource } from '@/api/dataset/dataset'
import { codemirror } from 'vue-codemirror'
//
import 'codemirror/lib/codemirror.css'
@ -96,7 +126,10 @@ export default {
hintOptions: {
completeSingle: true
}
}
},
data: [],
fields: [],
mode: '0'
}
},
computed: {
@ -115,6 +148,32 @@ export default {
})
},
getSQLPreview() {
if (!this.dataSource || this.datasource === '') {
this.$message({
showClose: true,
message: this.$t('dataset.pls_slc_data_source'),
type: 'error'
})
return
}
post('/dataset/table/sqlPreview', {
dataSourceId: this.dataSource,
type: 'sql',
info: '{"sql":"' + this.sql + '"}'
}).then(response => {
this.fields = response.data.fields
this.data = response.data.data
const datas = this.data
this.$refs.plxTable.reloadData(datas)
})
},
cancel() {
// this.dataReset()
this.$emit('switchComponent', { name: '' })
},
showSQL(val) {
this.sql = val || ''
},
@ -125,13 +184,9 @@ export default {
// console.log('the editor is focus!', cm)
},
onCmCodeChange(newCode) {
console.log(newCode)
// console.log(newCode)
this.sql = newCode
this.$emit('codeChange', this.sql)
},
cancel() {
// this.dataReset()
this.$emit('switchComponent', { name: '' })
}
}
}
@ -157,11 +212,23 @@ export default {
}
.codemirror {
height: auto;
min-height: 100px;
height: 160px;
overflow-y: auto;
}
.codemirror >>> .CodeMirror-scroll {
height: auto;
min-height: 100px;
height: 160px;
overflow-y: auto;
}
.dataPreview>>>.el-card__header{
padding: 6px 8px;
}
.dataPreview>>>.el-card__body{
padding:10px;
}
span{
font-size: 14px;
}
</style>

View File

@ -1,19 +1,21 @@
<template>
<el-col>
<el-table
<ux-grid
ref="plxTable"
size="mini"
:data="data"
border
style="width: 100%;"
:height="500"
:checkbox-config="{highlight: true}"
>
<el-table-column
<ux-table-column
v-for="field in fields"
:key="field.originName"
min-width="200px"
:prop="field.originName"
:label="field.name"
:field="field.originName"
:title="field.name"
:resizable="true"
/>
</el-table>
</ux-grid>
</el-col>
</template>
@ -29,8 +31,14 @@ export default {
return {
}
},
computed: {},
watch: {},
computed: {
},
watch: {
data() {
const datas = this.data
this.$refs.plxTable.reloadData(datas)
}
},
created() {
},
mounted() {