Merge remote-tracking branch 'origin/main' into main

# Conflicts:
#	frontend/src/views/panel/list/PanelViewShow.vue
This commit is contained in:
wangjiahao 2021-04-19 11:51:43 +08:00
commit f4f43a47aa
46 changed files with 1400 additions and 545 deletions

View File

@ -2,8 +2,6 @@ package io.dataease.config;
import com.fit2cloud.autoconfigure.QuartzAutoConfiguration;
import io.dataease.commons.utils.CommonThreadPool;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.SparkSession;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.repository.filerep.KettleFileRepository;
@ -40,7 +38,22 @@ public class CommonConfig {
SparkSession spark = SparkSession.builder()
.appName(env.getProperty("spark.appName", "DataeaseJob"))
.master(env.getProperty("spark.master", "local[*]"))
.config("spark.scheduler.mode", "FAIR")
.config("spark.scheduler.mode", env.getProperty("spark.scheduler.mode", "FAIR"))
.config("spark.serializer", env.getProperty("spark.serializer", "org.apache.spark.serializer.KryoSerializer"))
.config("spark.executor.cores", env.getProperty("spark.executor.cores", "8"))
.config("spark.executor.memory", env.getProperty("spark.executor.memory", "6442450944b"))
.config("spark.locality.wait", env.getProperty("spark.locality.wait", "600000"))
.config("spark.maxRemoteBlockSizeFetchToMem", env.getProperty("spark.maxRemoteBlockSizeFetchToMem", "2000m"))
.config("spark.shuffle.detectCorrupt", env.getProperty("spark.shuffle.detectCorrupt", "false"))
.config("spark.shuffle.service.enabled", env.getProperty("spark.shuffle.service.enabled", "true"))
.config("spark.sql.adaptive.enabled", env.getProperty("spark.sql.adaptive.enabled", "true"))
.config("spark.sql.adaptive.shuffle.targetPostShuffleInputSize", env.getProperty("spark.sql.adaptive.shuffle.targetPostShuffleInputSize", "200M"))
.config("spark.sql.broadcastTimeout", env.getProperty("spark.sql.broadcastTimeout", "12000"))
.config("spark.sql.retainGroupColumns", env.getProperty("spark.sql.retainGroupColumns", "false"))
.config("spark.sql.sortMergeJoinExec.buffer.in.memory.threshold", env.getProperty("spark.sql.sortMergeJoinExec.buffer.in.memory.threshold", "100000"))
.config("spark.sql.sortMergeJoinExec.buffer.spill.threshold", env.getProperty("spark.sql.sortMergeJoinExec.buffer.spill.threshold", "100000"))
.config("spark.sql.variable.substitute", env.getProperty("spark.sql.variable.substitute", "false"))
.config("spark.temp.expired.time", env.getProperty("spark.temp.expired.time", "3600"))
.getOrCreate();
return spark;
}

View File

@ -1,6 +1,8 @@
package io.dataease.controller.chart;
import io.dataease.base.domain.ChartViewWithBLOBs;
import io.dataease.controller.request.chart.ChartExtFilterRequest;
import io.dataease.controller.request.chart.ChartExtRequest;
import io.dataease.controller.request.chart.ChartViewRequest;
import io.dataease.dto.chart.ChartViewDTO;
import io.dataease.service.chart.ChartViewService;
@ -41,7 +43,12 @@ public class ChartViewController {
}
@PostMapping("/getData/{id}")
public ChartViewDTO getData(@PathVariable String id) throws Exception {
return chartViewService.getData(id);
public ChartViewDTO getData(@PathVariable String id, @RequestBody ChartExtRequest requestList) throws Exception {
return chartViewService.getData(id, requestList);
}
@PostMapping("chartDetail/{id}")
public Map<String, Object> chartDetail(@PathVariable String id) {
return chartViewService.getChartDetail(id);
}
}

View File

@ -82,4 +82,8 @@ public class DataSetTableController {
dataSetTableService.saveIncrementalConfig(datasetTableIncrementalConfig);
}
@PostMapping("datasetDetail/{id}")
public Map<String, Object> datasetDetail(@PathVariable String id) {
return dataSetTableService.getDatasetDetail(id);
}
}

View File

@ -0,0 +1,22 @@
package io.dataease.controller.request.chart;
import io.dataease.base.domain.DatasetTableField;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* @Author gin
* @Date 2021/4/19 10:24 上午
*/
@Getter
@Setter
public class ChartExtFilterRequest {
private String componentId;
private String fieldId;
private String operator;
private List<String> value;
private List<String> viewIds;
private DatasetTableField datasetTableField;
}

View File

@ -0,0 +1,16 @@
package io.dataease.controller.request.chart;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* @Author gin
* @Date 2021/4/19 11:29 上午
*/
@Getter
@Setter
public class ChartExtRequest {
private List<ChartExtFilterRequest> filter;
}

View File

@ -19,7 +19,7 @@ public abstract class DatasourceProvider {
abstract public List<String> getTables(DatasourceRequest datasourceRequest) throws Exception;
public List<TableFiled> getTableFileds(DatasourceRequest datasourceRequest) throws Exception{
public List<TableFiled> getTableFileds(DatasourceRequest datasourceRequest) throws Exception {
return new ArrayList<>();
};
@ -27,7 +27,7 @@ public abstract class DatasourceProvider {
getData(datasourceRequest);
}
abstract public Long count(DatasourceRequest datasourceRequest)throws Exception;
abstract public Long count(DatasourceRequest datasourceRequest) throws Exception;
abstract public List<String[]> getPageData(DatasourceRequest datasourceRequest) throws Exception;
@ -35,4 +35,5 @@ public abstract class DatasourceProvider {
abstract public List<TableFiled> fetchResultField(ResultSet rs) throws Exception;
abstract public void initConnectionPool(DatasourceRequest datasourceRequest) throws Exception;
}

View File

@ -13,24 +13,28 @@ import org.springframework.stereotype.Service;
import java.sql.*;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
@Service("jdbc")
public class JdbcProvider extends DatasourceProvider {
private static Map<String, ArrayBlockingQueue<Connection>> jdbcConnection = new HashMap<>();
private static int poolSize = 20;
@Override
public List<String[]> getData(DatasourceRequest datasourceRequest) throws Exception {
List<String[]> list = new LinkedList<>();
try (
Connection connection = getConnection(datasourceRequest);
Statement stat = connection.createStatement();
ResultSet rs = stat.executeQuery(datasourceRequest.getQuery())
) {
Connection connection = null;
try {
connection = getConnectionFromPool(datasourceRequest);
Statement stat = connection.createStatement();
ResultSet rs = stat.executeQuery(datasourceRequest.getQuery());
list = fetchResult(rs);
} catch (SQLException e) {
throw new Exception("ERROR:" + e.getMessage(), e);
} catch (Exception e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}finally {
returnSource(connection, datasourceRequest.getDatasource().getId());
}
return list;
}
@ -38,14 +42,18 @@ public class JdbcProvider extends DatasourceProvider {
@Override
public ResultSet getDataResultSet(DatasourceRequest datasourceRequest) throws Exception {
ResultSet rs;
Connection connection = null;
try {
Connection connection = getConnection(datasourceRequest);
connection = getConnectionFromPool(datasourceRequest);
Statement stat = connection.createStatement();
rs = stat.executeQuery(datasourceRequest.getQuery());
returnSource(connection, datasourceRequest.getDatasource().getId());
} catch (SQLException e) {
throw new Exception("ERROR:" + e.getMessage(), e);
} catch (Exception e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}finally {
returnSource(connection, datasourceRequest.getDatasource().getId());
}
return rs;
}
@ -53,16 +61,19 @@ public class JdbcProvider extends DatasourceProvider {
@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()))
) {
Connection connection = null;
try {
connection = getConnectionFromPool(datasourceRequest);
Statement stat = connection.createStatement();
ResultSet rs = stat.executeQuery(datasourceRequest.getQuery() + MessageFormat.format(" LIMIT {0}, {1}", (datasourceRequest.getStartPage() - 1) * datasourceRequest.getPageSize(), datasourceRequest.getPageSize()));
returnSource(connection, datasourceRequest.getDatasource().getId());
list = fetchResult(rs);
} catch (SQLException e) {
throw new Exception("ERROR:" + e.getMessage(), e);
} catch (Exception e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}finally {
returnSource(connection, datasourceRequest.getDatasource().getId());
}
return list;
}
@ -112,23 +123,28 @@ public class JdbcProvider extends DatasourceProvider {
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()) {
Connection con = null;
try {
con = getConnectionFromPool(datasourceRequest);
Statement ps = con.createStatement();
ResultSet resultSet = ps.executeQuery(queryStr);
while (resultSet.next()) {
tables.add(resultSet.getString(1));
}
return tables;
} catch (Exception e) {
throw new Exception("ERROR: " + e.getMessage(), e);
}finally {
returnSource(con, datasourceRequest.getDatasource().getId());
}
return tables;
}
@Override
public List<TableFiled> getTableFileds(DatasourceRequest datasourceRequest) throws Exception {
List<TableFiled> list = new LinkedList<>();
try (
Connection connection = getConnection(datasourceRequest);
) {
Connection connection = null;
try {
connection = getConnectionFromPool(datasourceRequest);
DatabaseMetaData databaseMetaData = connection.getMetaData();
ResultSet resultSet = databaseMetaData.getColumns(null, "%", datasourceRequest.getTable().toUpperCase(), "%");
while (resultSet.next()) {
@ -152,6 +168,8 @@ public class JdbcProvider extends DatasourceProvider {
throw new Exception("ERROR:" + e.getMessage(), e);
} catch (Exception e) {
throw new Exception("ERROR:" + e.getMessage(), e);
}finally {
returnSource(connection, datasourceRequest.getDatasource().getId());
}
return list;
}
@ -161,27 +179,73 @@ public class JdbcProvider extends DatasourceProvider {
@Override
public void test(DatasourceRequest datasourceRequest) throws Exception {
String queryStr = getTablesSql(datasourceRequest);
try (Connection con = getConnection(datasourceRequest); Statement ps = con.createStatement()) {
Connection con = null;
try {
con = getConnection(datasourceRequest);
Statement ps = con.createStatement();
ResultSet resultSet = ps.executeQuery(queryStr);
} catch (Exception e) {
throw new Exception("ERROR: " + e.getMessage(), e);
}finally {
con.close();
}
}
public Long count(DatasourceRequest datasourceRequest) throws Exception {
try (Connection con = getConnection(datasourceRequest); Statement ps = con.createStatement()) {
Connection con = null;
try {
con = getConnectionFromPool(datasourceRequest); Statement ps = con.createStatement();
ResultSet resultSet = ps.executeQuery(datasourceRequest.getQuery());
while (resultSet.next()) {
return resultSet.getLong(1);
}
} catch (Exception e) {
throw new Exception("ERROR: " + e.getMessage(), e);
}finally {
returnSource(con, datasourceRequest.getDatasource().getId());
}
return 0L;
}
private Connection getConnection(DatasourceRequest datasourceRequest) throws Exception {
private void returnSource(Connection connection, String dataSourceId) throws Exception{
if(connection != null && !connection.isClosed()){
ArrayBlockingQueue<Connection> connections = jdbcConnection.get(dataSourceId);
connections.put(connection);
}
}
private Connection getConnectionFromPool(DatasourceRequest datasourceRequest)throws Exception {
ArrayBlockingQueue<Connection> connections = jdbcConnection.get(datasourceRequest.getDatasource().getId());
if (connections == null) {
initConnectionPool(datasourceRequest);
}
connections = jdbcConnection.get(datasourceRequest.getDatasource().getId());
Connection co = connections.take();
return co;
}
@Override
public void initConnectionPool(DatasourceRequest datasourceRequest)throws Exception{
ArrayBlockingQueue<Connection> connections = jdbcConnection.get(datasourceRequest.getDatasource().getId());
if (connections == null) {
connections = new ArrayBlockingQueue<>(poolSize);
for (int i = 0; i < poolSize ; i++) {
Connection connection = getConnection(datasourceRequest);
connections.add(connection);
}
jdbcConnection.put(datasourceRequest.getDatasource().getId(), connections);
}else {
for (int i = 0; i < poolSize ; i++) {
Connection connection = connections.take();
connection.close();
connection = getConnection(datasourceRequest);
connections.add(connection);
}
}
}
private static Connection getConnection(DatasourceRequest datasourceRequest) throws Exception {
String username = null;
String password = null;
String driver = null;

View File

@ -5,6 +5,7 @@ import io.dataease.base.mapper.*;
import io.dataease.base.mapper.ext.ExtDataSourceMapper;
import io.dataease.base.mapper.ext.query.GridExample;
import io.dataease.commons.exception.DEException;
import io.dataease.commons.utils.CommonThreadPool;
import io.dataease.controller.sys.base.BaseGridRequest;
import io.dataease.datasource.provider.DatasourceProvider;
import io.dataease.datasource.provider.ProviderFactory;
@ -24,7 +25,8 @@ public class DatasourceService {
@Resource
private DatasourceMapper datasourceMapper;
@Resource
private CommonThreadPool commonThreadPool;
@Resource
private ExtDataSourceMapper extDataSourceMapper;
@ -39,6 +41,7 @@ public class DatasourceService {
datasource.setUpdateTime(currentTimeMillis);
datasource.setCreateTime(currentTimeMillis);
datasourceMapper.insertSelective(datasource);
initConnectionPool(datasource);
return datasource;
}
@ -68,6 +71,7 @@ public class DatasourceService {
datasource.setCreateTime(null);
datasource.setUpdateTime(System.currentTimeMillis());
datasourceMapper.updateByPrimaryKeySelective(datasource);
initConnectionPool(datasource);
}
public void validate(Datasource datasource) throws Exception {
@ -89,4 +93,30 @@ public class DatasourceService {
return datasourceMapper.selectByPrimaryKey(id);
}
private void initConnectionPool(Datasource datasource){
commonThreadPool.addTask(() ->{
try {
DatasourceProvider datasourceProvider = ProviderFactory.getProvider(datasource.getType());
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setDatasource(datasource);
datasourceProvider.initConnectionPool(datasourceRequest);
}catch (Exception e){}
});
}
public void initAllDataSourceConnectionPool(){
List<Datasource> datasources = datasourceMapper.selectByExampleWithBLOBs(new DatasourceExample());
datasources.forEach(datasource -> {
commonThreadPool.addTask(() ->{
try {
DatasourceProvider datasourceProvider = ProviderFactory.getProvider(datasource.getType());
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setDatasource(datasource);
datasourceProvider.initConnectionPool(datasourceRequest);
}catch (Exception e){
e.printStackTrace();
}
});
});
}
}

View File

@ -0,0 +1,31 @@
package io.dataease.listener;
import io.dataease.base.domain.DatasetTable;
import io.dataease.base.domain.DatasetTableExample;
import io.dataease.base.domain.DatasetTableField;
import io.dataease.base.mapper.DatasetTableMapper;
import io.dataease.commons.utils.CommonThreadPool;
import io.dataease.datasource.service.DatasourceService;
import io.dataease.service.dataset.DataSetTableFieldsService;
import io.dataease.service.spark.SparkCalc;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
@Component
@Order(value = 2)
public class AppStartInitDataSourceListener implements ApplicationListener<ApplicationReadyEvent> {
@Resource
private DatasourceService datasourceService;
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
System.out.println("================= Init datasource connection pool =================");
// 项目启动从数据集中找到定时抽取的表从HBase中读取放入缓存
datasourceService.initAllDataSourceConnectionPool();
}
}

View File

@ -1,7 +1,6 @@
package io.dataease.listener;
import io.dataease.base.domain.DatasetTableTask;
import io.dataease.job.sechedule.ScheduleManager;
import io.dataease.service.ScheduleService;
import io.dataease.service.dataset.DataSetTableTaskService;
import org.springframework.boot.context.event.ApplicationReadyEvent;

View File

@ -3,16 +3,10 @@ package io.dataease.listener;
import io.dataease.base.domain.DatasetTable;
import io.dataease.base.domain.DatasetTableExample;
import io.dataease.base.domain.DatasetTableField;
import io.dataease.base.domain.DatasetTableFieldExample;
import io.dataease.base.mapper.DatasetTableFieldMapper;
import io.dataease.base.mapper.DatasetTableMapper;
import io.dataease.commons.utils.CommonBeanFactory;
import io.dataease.commons.utils.CommonThreadPool;
import io.dataease.service.dataset.DataSetTableFieldsService;
import io.dataease.service.spark.SparkCalc;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.SparkSession;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
@ -45,14 +39,14 @@ public class AppStartReadHBaseListener implements ApplicationListener<Applicatio
datasetTableExample.createCriteria().andModeEqualTo(1);
List<DatasetTable> datasetTables = datasetTableMapper.selectByExampleWithBLOBs(datasetTableExample);
for (DatasetTable table : datasetTables) {
commonThreadPool.addTask(() -> {
// commonThreadPool.addTask(() -> {
try {
List<DatasetTableField> fields = dataSetTableFieldsService.getFieldsByTableId(table.getId());
sparkCalc.getHBaseDataAndCache(table.getId(), fields);
} catch (Exception e) {
e.printStackTrace();
}
});
// });
}
}
}

View File

@ -4,9 +4,10 @@ import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.dataease.base.domain.*;
import io.dataease.base.mapper.ChartViewMapper;
import io.dataease.base.mapper.DatasetTableFieldMapper;
import io.dataease.commons.utils.AuthUtils;
import io.dataease.commons.utils.BeanUtils;
import io.dataease.controller.request.chart.ChartExtFilterRequest;
import io.dataease.controller.request.chart.ChartExtRequest;
import io.dataease.controller.request.chart.ChartViewRequest;
import io.dataease.datasource.constants.DatasourceTypes;
import io.dataease.datasource.provider.DatasourceProvider;
@ -21,6 +22,7 @@ import io.dataease.service.dataset.DataSetTableFieldsService;
import io.dataease.service.dataset.DataSetTableService;
import io.dataease.service.spark.SparkCalc;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@ -88,7 +90,7 @@ public class ChartViewService {
chartViewMapper.deleteByExample(chartViewExample);
}
public ChartViewDTO getData(String id) throws Exception {
public ChartViewDTO getData(String id, ChartExtRequest requestList) throws Exception {
ChartViewWithBLOBs view = chartViewMapper.selectByPrimaryKey(id);
List<ChartViewFieldDTO> xAxis = new Gson().fromJson(view.getXAxis(), new TypeToken<List<ChartViewFieldDTO>>() {
}.getType());
@ -107,6 +109,24 @@ public class ChartViewService {
// List<DatasetTableField> xList = dataSetTableFieldsService.getListByIds(xIds);
// List<DatasetTableField> yList = dataSetTableFieldsService.getListByIds(yIds);
// 过滤来自仪表盘的条件
List<ChartExtFilterRequest> extFilterList = new ArrayList<>();
if (ObjectUtils.isNotEmpty(requestList.getFilter())) {
for (ChartExtFilterRequest request : requestList.getFilter()) {
DatasetTableField datasetTableField = dataSetTableFieldsService.get(request.getFieldId());
request.setDatasetTableField(datasetTableField);
if (StringUtils.equalsIgnoreCase(datasetTableField.getTableId(), view.getTableId())) {
if (CollectionUtils.isNotEmpty(request.getViewIds())) {
if (request.getViewIds().contains(view.getId())) {
extFilterList.add(request);
}
} else {
extFilterList.add(request);
}
}
}
}
// 获取数据集
DatasetTable table = dataSetTableService.get(view.getTableId());
// 判断连接方式直连或者定时抽取 table.mode
@ -119,15 +139,15 @@ public class ChartViewService {
DataTableInfoDTO dataTableInfoDTO = new Gson().fromJson(table.getInfo(), DataTableInfoDTO.class);
if (StringUtils.equalsIgnoreCase(table.getType(), "db")) {
datasourceRequest.setTable(dataTableInfoDTO.getTable());
datasourceRequest.setQuery(getSQL(ds.getType(), dataTableInfoDTO.getTable(), xAxis, yAxis));
datasourceRequest.setQuery(getSQL(ds.getType(), dataTableInfoDTO.getTable(), xAxis, yAxis, extFilterList));
} else if (StringUtils.equalsIgnoreCase(table.getType(), "sql")) {
datasourceRequest.setQuery(getSQL(ds.getType(), " (" + dataTableInfoDTO.getSql() + ") AS tmp ", xAxis, yAxis));
datasourceRequest.setQuery(getSQL(ds.getType(), " (" + dataTableInfoDTO.getSql() + ") AS tmp ", xAxis, yAxis, extFilterList));
}
data = datasourceProvider.getData(datasourceRequest);
} else if (table.getMode() == 1) {// 抽取
// 获取数据集de字段
List<DatasetTableField> fields = dataSetTableFieldsService.getFieldsByTableId(table.getId());
data = sparkCalc.getData(table.getId(), fields, xAxis, yAxis, "tmp_" + view.getId().split("-")[0]);
data = sparkCalc.getData(table.getId(), fields, xAxis, yAxis, "tmp_" + view.getId().split("-")[0], extFilterList);
}
// 图表组件可再扩展
@ -163,18 +183,45 @@ public class ChartViewService {
return dto;
}
public String getSQL(String type, String table, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis) {
public String transMysqlExtFilter(List<ChartExtFilterRequest> requestList) {
if (CollectionUtils.isEmpty(requestList)) {
return "";
}
StringBuilder filter = new StringBuilder();
for (ChartExtFilterRequest request : requestList) {
List<String> value = request.getValue();
if (CollectionUtils.isEmpty(value)) {
continue;
}
DatasetTableField field = request.getDatasetTableField();
filter.append(" AND ")
.append(field.getOriginName())
.append(" ")
.append(transMysqlFilterTerm(request.getOperator()))
.append(" ");
if (StringUtils.containsIgnoreCase(request.getOperator(), "in")) {
filter.append("('").append(StringUtils.join(value, "','")).append("')");
} else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) {
filter.append("'%").append(value.get(0)).append("%'");
} else {
filter.append("'").append(value.get(0)).append("'");
}
}
return filter.toString();
}
public String getSQL(String type, String table, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, List<ChartExtFilterRequest> extFilterRequestList) {
DatasourceTypes datasourceType = DatasourceTypes.valueOf(type);
switch (datasourceType) {
case mysql:
return transMysqlSQL(table, xAxis, yAxis);
return transMysqlSQL(table, xAxis, yAxis, extFilterRequestList);
case sqlServer:
default:
return "";
}
}
public String transMysqlSQL(String table, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis) {
public String transMysqlSQL(String table, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, List<ChartExtFilterRequest> extFilterRequestList) {
// 字段汇总 排序等
String[] field = yAxis.stream().map(y -> "CAST(" + y.getSummary() + "(" + y.getOriginName() + ") AS DECIMAL(20,2)) AS _" + y.getSummary() + "_" + y.getOriginName()).toArray(String[]::new);
String[] group = xAxis.stream().map(ChartViewFieldDTO::getOriginName).toArray(String[]::new);
@ -185,7 +232,7 @@ public class ChartViewService {
StringUtils.join(group, ","),
StringUtils.join(field, ","),
table,
"",
transMysqlExtFilter(extFilterRequestList),// origin field filter and panel field filter
StringUtils.join(group, ","),
StringUtils.join(order, ","));
if (sql.endsWith(",")) {
@ -221,6 +268,14 @@ public class ChartViewService {
return " > ";
case "ge":
return " >= ";
case "in":
return " IN ";
case "not in":
return " NOT IN ";
case "like":
return " LIKE ";
case "not like":
return " NOT LIKE ";
case "null":
return " IS NULL ";
case "not_null":
@ -250,4 +305,15 @@ public class ChartViewService {
throw new RuntimeException("Name can't repeat in same group.");
}
}
public Map<String, Object> getChartDetail(String id) {
Map<String, Object> map = new HashMap<>();
ChartViewWithBLOBs chartViewWithBLOBs = chartViewMapper.selectByPrimaryKey(id);
map.put("chart", chartViewWithBLOBs);
if (ObjectUtils.isNotEmpty(chartViewWithBLOBs)) {
Map<String, Object> datasetDetail = dataSetTableService.getDatasetDetail(chartViewWithBLOBs.getTableId());
map.putAll(datasetDetail);
}
return map;
}
}

View File

@ -66,4 +66,8 @@ public class DataSetTableFieldsService {
datasetTableFieldExample.createCriteria().andTableIdEqualTo(id);
return datasetTableFieldMapper.selectByExample(datasetTableFieldExample);
}
public DatasetTableField get(String id) {
return datasetTableFieldMapper.selectByPrimaryKey(id);
}
}

View File

@ -16,6 +16,7 @@ import io.dataease.datasource.provider.ProviderFactory;
import io.dataease.datasource.request.DatasourceRequest;
import io.dataease.dto.dataset.DataTableInfoDTO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@ -422,4 +423,15 @@ public class DataSetTableService {
throw new RuntimeException("Name can't repeat in same group.");
}
}
public Map<String, Object> getDatasetDetail(String id) {
Map<String, Object> map = new HashMap<>();
DatasetTable table = datasetTableMapper.selectByPrimaryKey(id);
map.put("table", table);
if (ObjectUtils.isNotEmpty(table)) {
Datasource datasource = datasourceMapper.selectByPrimaryKey(table.getDataSourceId());
map.put("datasource", datasource);
}
return map;
}
}

View File

@ -472,6 +472,8 @@ public class ExtractDataService {
hBaseOutputMeta.setTargetMappingName("target_mapping");
hBaseOutputMeta.setNamedCluster(clusterTemplate);
hBaseOutputMeta.setCoreConfigURL(hbase_conf_file);
hBaseOutputMeta.setDisableWriteToWAL(true);
hBaseOutputMeta.setWriteBufferSize("31457280"); //30M
if (extractType.equalsIgnoreCase("incremental_delete")) {
hBaseOutputMeta.setDeleteRowKey(true);
}

View File

@ -58,7 +58,7 @@ public class PanelGroupService {
return panelGroupDTOList;
}
public void getTreeChildren(List<PanelGroupDTO> parentPanelGroupDTO){
public void getTreeChildren(List<PanelGroupDTO> parentPanelGroupDTO) {
Optional.ofNullable(parentPanelGroupDTO).ifPresent(parent -> parent.forEach(panelGroupDTO -> {
List<PanelGroupDTO> panelGroupDTOChildren = extPanelGroupMapper.panelGroupList(new PanelGroupRequest(panelGroupDTO.getId()));
panelGroupDTO.setChildren(panelGroupDTOChildren);
@ -66,7 +66,7 @@ public class PanelGroupService {
}));
}
public List<PanelGroupDTO> getDefaultTree(PanelGroupRequest panelGroupRequest){
public List<PanelGroupDTO> getDefaultTree(PanelGroupRequest panelGroupRequest) {
return extPanelGroupMapper.panelGroupList(panelGroupRequest);
}
@ -86,32 +86,32 @@ public class PanelGroupService {
}
public void deleteCircle(String id){
public void deleteCircle(String id) {
Assert.notNull(id, "id cannot be null");
extPanelGroupMapper.deleteCircle(id);
}
public PanelGroupWithBLOBs findOne(String panelId){
return panelGroupMapper.selectByPrimaryKey(panelId);
public PanelGroupWithBLOBs findOne(String panelId) {
return panelGroupMapper.selectByPrimaryKey(panelId);
}
public PanelGroupDTO findOneBack(String panelId) throws Exception{
public PanelGroupDTO findOneBack(String panelId) throws Exception {
PanelGroupDTO panelGroupDTO = extPanelGroupMapper.panelGroup(panelId);
Assert.notNull(panelGroupDTO, "未查询到仪表盘信息");
PanelDesignExample panelDesignExample = new PanelDesignExample();
panelDesignExample.createCriteria().andPanelIdEqualTo(panelId);
List<PanelDesign> panelDesignList = panelDesignMapper.selectByExample(panelDesignExample);
if(CollectionUtils.isNotEmpty(panelDesignList)){
List<PanelDesign> panelDesignList = panelDesignMapper.selectByExample(panelDesignExample);
if (CollectionUtils.isNotEmpty(panelDesignList)) {
List<PanelDesignDTO> panelDesignDTOList = new ArrayList<>();
//TODO 加载所有视图和组件的数据
for(PanelDesign panelDesign:panelDesignList){
for (PanelDesign panelDesign : panelDesignList) {
//TODO 获取view 视图数据
ChartViewDTO chartViewDTO = chartViewService.getData(panelDesign.getComponentId());
ChartViewDTO chartViewDTO = chartViewService.getData(panelDesign.getComponentId(), null);
//TODO 获取systemComponent 系统组件数据待开发
PanelDesignDTO panelDesignDTO = new PanelDesignDTO(chartViewDTO);
BeanUtils.copyBean(panelDesignDTO,panelDesign);
BeanUtils.copyBean(panelDesignDTO, panelDesign);
panelDesignDTO.setKeepFlag(true);
panelDesignDTOList.add(panelDesignDTO);
}
@ -123,14 +123,14 @@ public class PanelGroupService {
}
public List<ChartViewDTO> getUsableViews(String panelId) throws Exception{
public List<ChartViewDTO> getUsableViews(String panelId) throws Exception {
List<ChartViewDTO> chartViewDTOList = new ArrayList<>();
List<ChartView> allChartView = chartViewMapper.selectByExample(null);
Optional.ofNullable(allChartView).orElse(new ArrayList<>()).stream().forEach(chartView -> {
try {
chartViewDTOList.add(chartViewService.getData(chartView.getId()));
}catch (Exception e){
LOGGER.error("获取view详情出错"+chartView.getId(),e);
chartViewDTOList.add(chartViewService.getData(chartView.getId(), null));
} catch (Exception e) {
LOGGER.error("获取view详情出错" + chartView.getId(), e);
}
});
return chartViewDTOList;
@ -150,24 +150,24 @@ public class PanelGroupService {
//TODO 更新panelDesign 信息
String panelId = request.getId();
Assert.notNull(panelId,"panelId should not be null");
Assert.notNull(panelId, "panelId should not be null");
//清理原有design
extPanelDesignMapper.deleteByPanelId(panelId);
//保存view 或者component design
Optional.ofNullable(request.getPanelDesigns()).orElse(new ArrayList<>()).stream().forEach(panelDesignDTO -> {
if(panelDesignDTO.isKeepFlag()) {
String componentId = "";
if(StringUtils.equals(PanelConstants.COMPONENT_TYPE_VIEW,panelDesignDTO.getComponentType())){
componentId = panelDesignDTO.getChartView().getId();
}else{
//预留 公共组件id获取
componentId = "";
}
panelDesignDTO.setPanelId(panelId);
panelDesignDTO.setComponentId(componentId);
panelDesignDTO.setUpdateTime(System.currentTimeMillis());
panelDesignMapper.insertSelective(panelDesignDTO);
}
if (panelDesignDTO.isKeepFlag()) {
String componentId = "";
if (StringUtils.equals(PanelConstants.COMPONENT_TYPE_VIEW, panelDesignDTO.getComponentType())) {
componentId = panelDesignDTO.getChartView().getId();
} else {
//预留 公共组件id获取
componentId = "";
}
panelDesignDTO.setPanelId(panelId);
panelDesignDTO.setComponentId(componentId);
panelDesignDTO.setUpdateTime(System.currentTimeMillis());
panelDesignMapper.insertSelective(panelDesignDTO);
}
});
}
}

View File

@ -2,11 +2,11 @@ package io.dataease.service.spark;
import io.dataease.base.domain.DatasetTableField;
import io.dataease.commons.utils.CommonBeanFactory;
import io.dataease.controller.request.chart.ChartExtFilterRequest;
import io.dataease.dto.chart.ChartViewFieldDTO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
@ -22,12 +22,12 @@ import org.apache.spark.sql.*;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
import org.apache.spark.storage.StorageLevel;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import scala.Tuple2;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Base64;
@ -44,13 +44,12 @@ public class SparkCalc {
@Resource
private Environment env; // 保存了配置文件的信息
public List<String[]> getData(String hTable, List<DatasetTableField> fields, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, String tmpTable) throws Exception {
public List<String[]> getData(String hTable, List<DatasetTableField> fields, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, String tmpTable, List<ChartExtFilterRequest> requestList) throws Exception {
// Spark Context
SparkSession spark = CommonBeanFactory.getBean(SparkSession.class);
JavaSparkContext sparkContext = new JavaSparkContext(spark.sparkContext());
// Spark SQL Context
// SQLContext sqlContext = CommonBeanFactory.getBean(SQLContext.class);
SQLContext sqlContext = new SQLContext(sparkContext);
sqlContext.setConf("spark.sql.shuffle.partitions", env.getProperty("spark.sql.shuffle.partitions", "1"));
sqlContext.setConf("spark.default.parallelism", env.getProperty("spark.default.parallelism", "1"));
@ -61,7 +60,7 @@ public class SparkCalc {
}
dataFrame.createOrReplaceTempView(tmpTable);
Dataset<Row> sql = sqlContext.sql(getSQL(xAxis, yAxis, tmpTable));
Dataset<Row> sql = sqlContext.sql(getSQL(xAxis, yAxis, tmpTable, requestList));
// transform
List<String[]> data = new ArrayList<>();
List<Row> list = sql.collectAsList();
@ -81,7 +80,6 @@ public class SparkCalc {
JavaSparkContext sparkContext = new JavaSparkContext(spark.sparkContext());
// Spark SQL Context
// SQLContext sqlContext = CommonBeanFactory.getBean(SQLContext.class);
SQLContext sqlContext = new SQLContext(sparkContext);
sqlContext.setConf("spark.sql.shuffle.partitions", env.getProperty("spark.sql.shuffle.partitions", "1"));
sqlContext.setConf("spark.default.parallelism", env.getProperty("spark.default.parallelism", "1"));
@ -90,12 +88,14 @@ public class SparkCalc {
public Dataset<Row> getHBaseDataAndCache(JavaSparkContext sparkContext, SQLContext sqlContext, String hTable, List<DatasetTableField> fields) throws Exception {
Scan scan = new Scan();
scan.addFamily(column_family.getBytes());
scan.addFamily(Bytes.toBytes(column_family));
for (DatasetTableField field : fields) {
scan.addColumn(Bytes.toBytes(column_family), Bytes.toBytes(field.getOriginName()));
}
ClientProtos.Scan proto = ProtobufUtil.toScan(scan);
String scanToString = new String(Base64.getEncoder().encode(proto.toByteArray()));
// HBase config
// Configuration conf = CommonBeanFactory.getBean(Configuration.class);
org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration();
conf.set("hbase.zookeeper.quorum", env.getProperty("hbase.zookeeper.quorum"));
conf.set("hbase.zookeeper.property.clientPort", env.getProperty("hbase.zookeeper.property.clientPort"));
@ -144,13 +144,13 @@ public class SparkCalc {
});
StructType structType = DataTypes.createStructType(structFields);
Dataset<Row> dataFrame = sqlContext.createDataFrame(rdd, structType).persist();
Dataset<Row> dataFrame = sqlContext.createDataFrame(rdd, structType).persist(StorageLevel.MEMORY_AND_DISK_SER());
CacheUtil.getInstance().addCacheData(hTable, dataFrame);
dataFrame.count();
return dataFrame;
}
public String getSQL(List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, String table) {
public String getSQL(List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, String table, List<ChartExtFilterRequest> extFilterRequestList) {
// 字段汇总 排序等
String[] field = yAxis.stream().map(y -> "CAST(" + y.getSummary() + "(" + y.getOriginName() + ") AS DECIMAL(20,2)) AS _" + y.getSummary() + "_" + y.getOriginName()).toArray(String[]::new);
String[] group = xAxis.stream().map(ChartViewFieldDTO::getOriginName).toArray(String[]::new);
@ -161,7 +161,7 @@ public class SparkCalc {
StringUtils.join(group, ","),
StringUtils.join(field, ","),
table,
"",
transExtFilter(extFilterRequestList),// origin field filter and panel field filter,
StringUtils.join(group, ","),
StringUtils.join(order, ","));
if (sql.endsWith(",")) {
@ -197,6 +197,14 @@ public class SparkCalc {
return " > ";
case "ge":
return " >= ";
case "in":
return " IN ";
case "not in":
return " NOT IN ";
case "like":
return " LIKE ";
case "not like":
return " NOT LIKE ";
case "null":
return " IS NULL ";
case "not_null":
@ -205,4 +213,31 @@ public class SparkCalc {
return "";
}
}
public String transExtFilter(List<ChartExtFilterRequest> requestList) {
if (CollectionUtils.isEmpty(requestList)) {
return "";
}
StringBuilder filter = new StringBuilder();
for (ChartExtFilterRequest request : requestList) {
List<String> value = request.getValue();
if (CollectionUtils.isEmpty(value)) {
continue;
}
DatasetTableField field = request.getDatasetTableField();
filter.append(" AND ")
.append(field.getOriginName())
.append(" ")
.append(transFilterTerm(request.getOperator()))
.append(" ");
if (StringUtils.containsIgnoreCase(request.getOperator(), "in")) {
filter.append("('").append(StringUtils.join(value, "','")).append("')");
} else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) {
filter.append("'%").append(value.get(0)).append("%'");
} else {
filter.append("'").append(value.get(0)).append("'");
}
}
return filter.toString();
}
}

View File

@ -49,6 +49,9 @@ export default {
this.$store.dispatch('chart/setViewId', this.curComponent.propValue.viewId)
bus.$emit('PanelSwitchComponent', { name: 'ChartEdit' })
}
if (this.curComponent.type === 'custom') {
bus.$emit('component-dialog-edit')
}
//
},
lock() {
@ -65,6 +68,7 @@ export default {
},
cut() {
this.deleteCurCondition()
this.$store.commit('cut')
},
@ -78,10 +82,17 @@ export default {
},
deleteComponent() {
this.deleteCurCondition()
this.$store.commit('deleteComponent')
this.$store.commit('recordSnapshot')
},
deleteCurCondition() {
if (this.curComponent.type === 'custom') {
bus.$emit('delete-condition', { componentId: this.curComponent.id })
}
},
upComponent() {
this.$store.commit('upComponent')
this.$store.commit('recordSnapshot')

View File

@ -1,14 +1,14 @@
<template>
<div class="mark-line">
<div
v-for="line in lines"
:key="line"
class="line"
:class="line.includes('x')? 'xline' : 'yline'"
:ref="line"
v-show="lineStatus[line] || false"
></div>
</div>
<div class="mark-line">
<div
v-for="line in lines"
v-show="lineStatus[line] || false"
:key="line"
:ref="line"
class="line"
:class="line.includes('x')? 'xline' : 'yline'"
/>
</div>
</template>
<script>
@ -17,215 +17,215 @@ import { mapState } from 'vuex'
import { getComponentRotatedStyle } from '@/components/canvas/utils/style'
export default {
data() {
return {
lines: ['xt', 'xc', 'xb', 'yl', 'yc', 'yr'], // 线线
diff: 3, // dff
lineStatus: {
xt: false,
xc: false,
xb: false,
yl: false,
yc: false,
yr: false,
data() {
return {
lines: ['xt', 'xc', 'xb', 'yl', 'yc', 'yr'], // 线线
diff: 3, // dff
lineStatus: {
xt: false,
xc: false,
xb: false,
yl: false,
yc: false,
yr: false
}
}
},
computed: mapState([
'curComponent',
'componentData'
]),
mounted() {
//
eventBus.$on('move', (isDownward, isRightward) => {
this.showLine(isDownward, isRightward)
})
eventBus.$on('unmove', () => {
this.hideLine()
})
},
methods: {
hideLine() {
Object.keys(this.lineStatus).forEach(line => {
this.lineStatus[line] = false
})
},
showLine(isDownward, isRightward) {
const lines = this.$refs
const components = this.componentData
const curComponentStyle = getComponentRotatedStyle(this.curComponent.style)
const curComponentHalfwidth = curComponentStyle.width / 2
const curComponentHalfHeight = curComponentStyle.height / 2
this.hideLine()
components.forEach(component => {
if (component === this.curComponent) return
const componentStyle = getComponentRotatedStyle(component.style)
const { top, left, bottom, right } = componentStyle
const componentHalfwidth = componentStyle.width / 2
const componentHalfHeight = componentStyle.height / 2
const conditions = {
top: [
{
isNearly: this.isNearly(curComponentStyle.top, top),
lineNode: lines.xt[0], // xt
line: 'xt',
dragShift: top,
lineShift: top
},
{
isNearly: this.isNearly(curComponentStyle.bottom, top),
lineNode: lines.xt[0], // xt
line: 'xt',
dragShift: top - curComponentStyle.height,
lineShift: top
},
{
//
isNearly: this.isNearly(curComponentStyle.top + curComponentHalfHeight, top + componentHalfHeight),
lineNode: lines.xc[0], // xc
line: 'xc',
dragShift: top + componentHalfHeight - curComponentHalfHeight,
lineShift: top + componentHalfHeight
},
{
isNearly: this.isNearly(curComponentStyle.top, bottom),
lineNode: lines.xb[0], // xb
line: 'xb',
dragShift: bottom,
lineShift: bottom
},
{
isNearly: this.isNearly(curComponentStyle.bottom, bottom),
lineNode: lines.xb[0], // xb
line: 'xb',
dragShift: bottom - curComponentStyle.height,
lineShift: bottom
}
],
left: [
{
isNearly: this.isNearly(curComponentStyle.left, left),
lineNode: lines.yl[0], // yl
line: 'yl',
dragShift: left,
lineShift: left
},
{
isNearly: this.isNearly(curComponentStyle.right, left),
lineNode: lines.yl[0], // yl
line: 'yl',
dragShift: left - curComponentStyle.width,
lineShift: left
},
{
//
isNearly: this.isNearly(curComponentStyle.left + curComponentHalfwidth, left + componentHalfwidth),
lineNode: lines.yc[0], // yc
line: 'yc',
dragShift: left + componentHalfwidth - curComponentHalfwidth,
lineShift: left + componentHalfwidth
},
{
isNearly: this.isNearly(curComponentStyle.left, right),
lineNode: lines.yr[0], // yr
line: 'yr',
dragShift: right,
lineShift: right
},
{
isNearly: this.isNearly(curComponentStyle.right, right),
lineNode: lines.yr[0], // yr
line: 'yr',
dragShift: right - curComponentStyle.width,
lineShift: right
}
]
}
},
computed: mapState([
'curComponent',
'componentData',
]),
mounted() {
//
eventBus.$on('move', (isDownward, isRightward) => {
this.showLine(isDownward, isRightward)
const needToShow = []
const { rotate } = this.curComponent.style
Object.keys(conditions).forEach(key => {
//
conditions[key].forEach((condition) => {
if (!condition.isNearly) return
//
this.$store.commit('setShapeSingleStyle', {
key,
value: rotate !== 0 ? this.translatecurComponentShift(key, condition, curComponentStyle) : condition.dragShift
})
condition.lineNode && (condition.lineNode.style[key] = `${condition.lineShift}px`)
needToShow.push(condition.line)
})
})
eventBus.$on('unmove', () => {
this.hideLine()
})
// 线
// 线线
if (needToShow.length) {
this.chooseTheTureLine(needToShow, isDownward, isRightward)
}
})
},
methods: {
hideLine() {
Object.keys(this.lineStatus).forEach(line => {
this.lineStatus[line] = false
})
},
showLine(isDownward, isRightward) {
const lines = this.$refs
const components = this.componentData
const curComponentStyle = getComponentRotatedStyle(this.curComponent.style)
const curComponentHalfwidth = curComponentStyle.width / 2
const curComponentHalfHeight = curComponentStyle.height / 2
translatecurComponentShift(key, condition, curComponentStyle) {
const { width, height } = this.curComponent.style
if (key === 'top') {
return Math.round(condition.dragShift - (height - curComponentStyle.height) / 2)
}
this.hideLine()
components.forEach(component => {
if (component == this.curComponent) return
const componentStyle = getComponentRotatedStyle(component.style)
const { top, left, bottom, right } = componentStyle
const componentHalfwidth = componentStyle.width / 2
const componentHalfHeight = componentStyle.height / 2
const conditions = {
top: [
{
isNearly: this.isNearly(curComponentStyle.top, top),
lineNode: lines.xt[0], // xt
line: 'xt',
dragShift: top,
lineShift: top,
},
{
isNearly: this.isNearly(curComponentStyle.bottom, top),
lineNode: lines.xt[0], // xt
line: 'xt',
dragShift: top - curComponentStyle.height,
lineShift: top,
},
{
//
isNearly: this.isNearly(curComponentStyle.top + curComponentHalfHeight, top + componentHalfHeight),
lineNode: lines.xc[0], // xc
line: 'xc',
dragShift: top + componentHalfHeight - curComponentHalfHeight,
lineShift: top + componentHalfHeight,
},
{
isNearly: this.isNearly(curComponentStyle.top, bottom),
lineNode: lines.xb[0], // xb
line: 'xb',
dragShift: bottom,
lineShift: bottom,
},
{
isNearly: this.isNearly(curComponentStyle.bottom, bottom),
lineNode: lines.xb[0], // xb
line: 'xb',
dragShift: bottom - curComponentStyle.height,
lineShift: bottom,
},
],
left: [
{
isNearly: this.isNearly(curComponentStyle.left, left),
lineNode: lines.yl[0], // yl
line: 'yl',
dragShift: left,
lineShift: left,
},
{
isNearly: this.isNearly(curComponentStyle.right, left),
lineNode: lines.yl[0], // yl
line: 'yl',
dragShift: left - curComponentStyle.width,
lineShift: left,
},
{
//
isNearly: this.isNearly(curComponentStyle.left + curComponentHalfwidth, left + componentHalfwidth),
lineNode: lines.yc[0], // yc
line: 'yc',
dragShift: left + componentHalfwidth - curComponentHalfwidth,
lineShift: left + componentHalfwidth,
},
{
isNearly: this.isNearly(curComponentStyle.left, right),
lineNode: lines.yr[0], // yr
line: 'yr',
dragShift: right,
lineShift: right,
},
{
isNearly: this.isNearly(curComponentStyle.right, right),
lineNode: lines.yr[0], // yr
line: 'yr',
dragShift: right - curComponentStyle.width,
lineShift: right,
},
],
}
const needToShow = []
const { rotate } = this.curComponent.style
Object.keys(conditions).forEach(key => {
//
conditions[key].forEach((condition) => {
if (!condition.isNearly) return
//
this.$store.commit('setShapeSingleStyle', {
key,
value: rotate !== 0? this.translatecurComponentShift(key, condition, curComponentStyle) : condition.dragShift,
})
condition.lineNode.style[key] = `${condition.lineShift}px`
needToShow.push(condition.line)
})
})
// 线
// 线线
if (needToShow.length) {
this.chooseTheTureLine(needToShow, isDownward, isRightward)
}
})
},
translatecurComponentShift(key, condition, curComponentStyle) {
const { width, height } = this.curComponent.style
if (key === 'top') {
return Math.round(condition.dragShift - (height - curComponentStyle.height) / 2)
}
return Math.round(condition.dragShift - (width - curComponentStyle.width) / 2)
},
chooseTheTureLine(needToShow, isDownward, isRightward) {
// 线
// 线
if (isRightward) {
if (needToShow.includes('yr')) {
this.lineStatus.yr = true
} else if (needToShow.includes('yc')) {
this.lineStatus.yc = true
} else if (needToShow.includes('yl')) {
this.lineStatus.yl = true
}
} else {
// eslint-disable-next-line no-lonely-if
if (needToShow.includes('yl')) {
this.lineStatus.yl = true
} else if (needToShow.includes('yc')) {
this.lineStatus.yc = true
} else if (needToShow.includes('yr')) {
this.lineStatus.yr = true
}
}
if (isDownward) {
if (needToShow.includes('xb')) {
this.lineStatus.xb = true
} else if (needToShow.includes('xc')) {
this.lineStatus.xc = true
} else if (needToShow.includes('xt')) {
this.lineStatus.xt = true
}
} else {
// eslint-disable-next-line no-lonely-if
if (needToShow.includes('xt')) {
this.lineStatus.xt = true
} else if (needToShow.includes('xc')) {
this.lineStatus.xc = true
} else if (needToShow.includes('xb')) {
this.lineStatus.xb = true
}
}
},
isNearly(dragValue, targetValue) {
return Math.abs(dragValue - targetValue) <= this.diff
},
return Math.round(condition.dragShift - (width - curComponentStyle.width) / 2)
},
chooseTheTureLine(needToShow, isDownward, isRightward) {
// 线
// 线
if (isRightward) {
if (needToShow.includes('yr')) {
this.lineStatus.yr = true
} else if (needToShow.includes('yc')) {
this.lineStatus.yc = true
} else if (needToShow.includes('yl')) {
this.lineStatus.yl = true
}
} else {
// eslint-disable-next-line no-lonely-if
if (needToShow.includes('yl')) {
this.lineStatus.yl = true
} else if (needToShow.includes('yc')) {
this.lineStatus.yc = true
} else if (needToShow.includes('yr')) {
this.lineStatus.yr = true
}
}
if (isDownward) {
if (needToShow.includes('xb')) {
this.lineStatus.xb = true
} else if (needToShow.includes('xc')) {
this.lineStatus.xc = true
} else if (needToShow.includes('xt')) {
this.lineStatus.xt = true
}
} else {
// eslint-disable-next-line no-lonely-if
if (needToShow.includes('xt')) {
this.lineStatus.xt = true
} else if (needToShow.includes('xc')) {
this.lineStatus.xc = true
} else if (needToShow.includes('xb')) {
this.lineStatus.xb = true
}
}
},
isNearly(dragValue, targetValue) {
return Math.abs(dragValue - targetValue) <= this.diff
}
}
}
</script>

View File

@ -61,13 +61,11 @@ export default {
])
},
mounted() {
debugger
const _this = this
const erd = elementResizeDetectorMaker()
// div
erd.listenTo(document.getElementById('canvasInfo'), element => {
_this.$nextTick(() => {
debugger
_this.restore()
})
})

View File

@ -71,7 +71,6 @@ export default {
})
})
window.onresize = () => {
debugger
this.resize()
}
// this.resize()
@ -88,7 +87,6 @@ export default {
this.handleScaleChange()
},
restore() {
debugger
this.panelId = this.$route.path.split('/')[2]
//
get('panel/group/findOne/' + this.panelId).then(response => {

View File

@ -19,7 +19,6 @@ export default {
methods: {
toDir() {
debugger
this.$router.replace('/panel/index')
bus.$emit('PanelSwitchComponent', { name: 'PanelEdit' })
}

View File

@ -3,13 +3,13 @@
<span v-show="isActive()" class="iconfont icon-xiangyouxuanzhuan" @mousedown="handleRotate" />
<span v-show="element.isLock" class="iconfont icon-suo" />
<!-- <span v-show="isActive()" class="iconfont icon-more">-->
<!-- <el-button-->
<!-- icon="el-icon-more"-->
<!-- type="text"-->
<!-- size="small"-->
<!-- />-->
<!-- </span>-->
<!-- <span v-show="isActive()" class="iconfont icon-more">-->
<!-- <el-button-->
<!-- icon="el-icon-more"-->
<!-- type="text"-->
<!-- size="small"-->
<!-- />-->
<!-- </span>-->
<div
v-for="item in (isActive()? pointList : [])"
:key="item"
@ -335,9 +335,9 @@ export default {
symmetricPoint
})
console.log('this is test:' + JSON.stringify(this.element.propValue.viewId))
// console.log('this is test:' + JSON.stringify(this.element.propValue.viewId))
this.$store.commit('setShapeStyle', style)
eventBus.$emit('resizing', this.element.propValue.viewId)
this.element.propValue && this.element.propValue.viewId && eventBus.$emit('resizing', this.element.propValue.viewId)
}
const up = () => {

View File

@ -25,14 +25,14 @@
:class="{ lock: item.isLock }"
>
<de-drawing-widget
<component
:is="item.component"
v-if="item.type==='custom'"
:id="'component' + item.id"
class="component"
:style="getComponentStyle(item.style)"
:style="item.style"
:element="item"
:item="item"
@filter-value-change="filterValueChange"
@set-condition-value="setConditionValue"
/>
<component
@ -67,6 +67,7 @@
<script>
import { mapState } from 'vuex'
import Shape from './Shape'
// eslint-disable-next-line no-unused-vars
import { getStyle, getComponentRotatedStyle } from '@/components/canvas/utils/style'
import { $ } from '@/components/canvas/utils/utils'
import ContextMenu from './ContextMenu'
@ -75,7 +76,8 @@ import Area from './Area'
import eventBus from '@/components/canvas/utils/eventBus'
import Grid from './Grid'
import { changeStyleWithScale } from '@/components/canvas/utils/translate'
import { Condition } from '@/components/widget/bean/Condition'
import bus from '@/utils/bus'
export default {
components: { Shape, ContextMenu, MarkLine, Area, Grid },
props: {
@ -94,15 +96,22 @@ export default {
},
width: 0,
height: 0,
isShowArea: false
isShowArea: false,
conditions: []
}
},
computed: mapState([
'componentData',
'curComponent',
'canvasStyleData',
'editor'
]),
computed: {
panelInfo() {
return this.$store.state.panel.panelInfo
},
...mapState([
'componentData',
'curComponent',
'canvasStyleData',
'editor'
])
},
mounted() {
//
this.$store.commit('getEditor')
@ -110,6 +119,9 @@ export default {
eventBus.$on('hideArea', () => {
this.hideArea()
})
bus.$on('delete-condition', condition => {
this.deleteCondition(condition)
})
},
methods: {
changeStyleWithScale,
@ -275,7 +287,8 @@ export default {
},
getComponentStyle(style) {
return getStyle(style, ['top', 'left', 'width', 'height', 'rotate'])
// return getStyle(style, ['top', 'left', 'width', 'height', 'rotate'])
return style
},
handleInput(element, value) {
@ -284,6 +297,7 @@ export default {
},
getTextareaHeight(element, text) {
// eslint-disable-next-line prefer-const
let { lineHeight, fontSize, height } = element.style
if (lineHeight === '') {
lineHeight = 1.5
@ -295,6 +309,28 @@ export default {
filterValueChange(value) {
console.log('emit:' + value)
},
setConditionValue(obj) {
const { component, value, operator } = obj
const fieldId = component.options.attrs.fieldId
const condition = new Condition(component.id, fieldId, operator, value, null)
this.addCondition(condition)
},
addCondition(condition) {
this.conditions.push(condition)
this.executeSearch()
},
deleteCondition(condition) {
this.conditions = this.conditions.filter(item => {
const componentIdSuitable = !condition.componentId || (item.componentId === condition.componentId)
const fieldIdSuitable = !condition.fieldId || (item.fieldId === condition.fieldId)
return !(componentIdSuitable && fieldIdSuitable)
})
this.executeSearch()
},
executeSearch() {
console.log('当前查询条件是: ' + JSON.stringify(this.conditions))
}
}
}

View File

@ -228,8 +228,8 @@ export default {
float: right;
height: 35px;
line-height: 35px;
background: #fff;
border-bottom: 1px solid #ddd;
/*background: #fff;*/
/*border-bottom: 1px solid #ddd;*/
.canvas-config {
display: inline-block;

View File

@ -6,95 +6,95 @@ import { $ } from '@/components/canvas/utils/utils'
import { commonStyle, commonAttr } from '@/components/canvas/custom-component/component-list'
export default {
state: {
areaData: { // 选中区域包含的组件以及区域位移信息
style: {
top: 0,
left: 0,
width: 0,
height: 0,
},
components: [],
},
editor: null,
state: {
areaData: { // 选中区域包含的组件以及区域位移信息
style: {
top: 0,
left: 0,
width: 0,
height: 0
},
components: []
},
mutations: {
getEditor(state) {
state.editor = $('#editor')
},
setAreaData(state, data) {
state.areaData = data
},
compose({ componentData, areaData, editor }) {
const components = []
areaData.components.forEach(component => {
if (component.component != 'Group') {
components.push(component)
} else {
// 如果要组合的组件中,已经存在组合数据,则需要提前拆分
const parentStyle = { ...component.style }
const subComponents = component.propValue
const editorRect = editor.getBoundingClientRect()
store.commit('deleteComponent')
subComponents.forEach(component => {
decomposeComponent(component, editorRect, parentStyle)
store.commit('addComponent', { component })
})
components.push(...component.propValue)
store.commit('batchDeleteComponent', component.propValue)
}
})
store.commit('addComponent', {
component: {
id: generateID(),
component: 'Group',
...commonAttr,
style: {
...commonStyle,
...areaData.style,
},
propValue: components,
},
})
eventBus.$emit('hideArea')
store.commit('batchDeleteComponent', areaData.components)
store.commit('setCurComponent', {
component: componentData[componentData.length - 1],
index: componentData.length - 1,
})
areaData.components = []
},
// 将已经放到 Group 组件数据删除,也就是在 componentData 中删除,因为它们已经放到 Group 组件中了
batchDeleteComponent({ componentData }, deleteData) {
deleteData.forEach(component => {
for (let i = 0, len = componentData.length; i < len; i++) {
if (component.id == componentData[i].id) {
componentData.splice(i, 1)
break
}
}
})
},
decompose({ curComponent, editor }) {
const parentStyle = { ...curComponent.style }
const components = curComponent.propValue
const editorRect = editor.getBoundingClientRect()
store.commit('deleteComponent')
components.forEach(component => {
decomposeComponent(component, editorRect, parentStyle)
store.commit('addComponent', { component })
})
},
editor: null
},
mutations: {
getEditor(state) {
state.editor = $('#editor')
},
setAreaData(state, data) {
state.areaData = data
},
compose({ componentData, areaData, editor }) {
const components = []
areaData.components.forEach(component => {
if (component.component !== 'Group') {
components.push(component)
} else {
// 如果要组合的组件中,已经存在组合数据,则需要提前拆分
const parentStyle = { ...component.style }
const subComponents = component.propValue
const editorRect = editor.getBoundingClientRect()
store.commit('deleteComponent')
subComponents.forEach(component => {
decomposeComponent(component, editorRect, parentStyle)
store.commit('addComponent', { component })
})
components.push(...component.propValue)
store.commit('batchDeleteComponent', component.propValue)
}
})
store.commit('addComponent', {
component: {
id: generateID(),
component: 'Group',
...commonAttr,
style: {
...commonStyle,
...areaData.style
},
propValue: components
}
})
eventBus.$emit('hideArea')
store.commit('batchDeleteComponent', areaData.components)
store.commit('setCurComponent', {
component: componentData[componentData.length - 1],
index: componentData.length - 1
})
areaData.components = []
},
// 将已经放到 Group 组件数据删除,也就是在 componentData 中删除,因为它们已经放到 Group 组件中了
batchDeleteComponent({ componentData }, deleteData) {
deleteData.forEach(component => {
for (let i = 0, len = componentData.length; i < len; i++) {
if (component.id == componentData[i].id) {
componentData.splice(i, 1)
break
}
}
})
},
decompose({ curComponent, editor }) {
const parentStyle = { ...curComponent.style }
const components = curComponent.propValue
const editorRect = editor.getBoundingClientRect()
store.commit('deleteComponent')
components.forEach(component => {
decomposeComponent(component, editorRect, parentStyle)
store.commit('addComponent', { component })
})
}
}
}

View File

@ -1,55 +1,55 @@
import { sin, cos } from '@/components/canvas/utils/translate'
export function getStyle(style, filter = []) {
const needUnit = [
'fontSize',
'width',
'height',
'top',
'left',
'borderWidth',
'letterSpacing',
'borderRadius',
]
const needUnit = [
'fontSize',
'width',
'height',
'top',
'left',
'borderWidth',
'letterSpacing',
'borderRadius'
]
const result = {}
Object.keys(style).forEach(key => {
if (!filter.includes(key)) {
if (key != 'rotate') {
result[key] = style[key]
const result = {}
Object.keys(style).forEach(key => {
if (!filter.includes(key)) {
if (key !== 'rotate') {
result[key] = style[key]
if (needUnit.includes(key)) {
result[key] += 'px'
}
} else {
result.transform = key + '(' + style[key] + 'deg)'
}
if (needUnit.includes(key)) {
result[key] += 'px'
}
})
} else {
result.transform = key + '(' + style[key] + 'deg)'
}
}
})
return result
return result
}
// 获取一个组件旋转 rotate 后的样式
export function getComponentRotatedStyle(style) {
style = { ...style }
if (style.rotate != 0) {
const newWidth = style.width * cos(style.rotate) + style.height * sin(style.rotate)
const diffX = (style.width - newWidth) / 2 // 旋转后范围变小是正值,变大是负值
style.left += diffX
style.right = style.left + newWidth
style = { ...style }
if (style.rotate != 0) {
const newWidth = style.width * cos(style.rotate) + style.height * sin(style.rotate)
const diffX = (style.width - newWidth) / 2 // 旋转后范围变小是正值,变大是负值
style.left += diffX
style.right = style.left + newWidth
const newHeight = style.height * cos(style.rotate) + style.width * sin(style.rotate)
const diffY = (newHeight - style.height) / 2 // 始终是正
style.top -= diffY
style.bottom = style.top + newHeight
const newHeight = style.height * cos(style.rotate) + style.width * sin(style.rotate)
const diffY = (newHeight - style.height) / 2 // 始终是正
style.top -= diffY
style.bottom = style.top + newHeight
style.width = newWidth
style.height = newHeight
} else {
style.bottom = style.top + style.height
style.right = style.left + style.width
}
style.width = newWidth
style.height = newHeight
} else {
style.bottom = style.top + style.height
style.right = style.left + style.width
}
return style
return style
}

View File

@ -1,20 +1,30 @@
<script>
import { ApplicationContext } from '@/utils/ApplicationContext'
import store from '@/store'
export default {
name: 'DeDrawingWidget',
functional: true,
props: {
item: {
type: Object,
serviceName: {
type: String,
default: null
}
},
render(createElement, context) {
const item = context.props.item
return createElement(item.component, {
const widgetInfo = ApplicationContext.getService(context.props.serviceName)
// const widgetInfo = context.props.widgetInfo
const dialogInfo = widgetInfo.getDialogPanel && widgetInfo.getDialogPanel() || null
const drawInfo = widgetInfo.getDrawPanel && widgetInfo.getDrawPanel() || null
const curComponent = store.state.curComponent
if (!dialogInfo) {
throw new Error('系统错误')
}
return createElement(dialogInfo.component, {
props: {
element: item
element: curComponent || drawInfo || dialogInfo
},
style: context.data.style,
on: {
'value-change': value => {
context.listeners['filter-value-change'] && context.listeners['filter-value-change'](value)

View File

@ -1,6 +1,6 @@
<template>
<el-select v-if="options!== null && options.attrs!==null" v-model="options.value" :placeholder="options.attrs.placeholder" @change="changeValue">
<el-select v-if="options!== null && options.attrs!==null" v-model="options.value" :style="element.style" :placeholder="options.attrs.placeholder" @change="changeValue">
<el-option
v-for="item in options.attrs.datas"
:key="item[options.attrs.key]"
@ -12,19 +12,31 @@
</template>
<script>
export default {
props: {
element: {
type: Object,
default: null
},
inDraw: {
type: Boolean,
default: true
}
},
data() {
return {
options: null
options: null,
operator: 'eq'
}
},
watch: {
'element.style': function(value) {
// console.log(value)
}
},
created() {
this.options = this.element.options
},
@ -35,7 +47,7 @@ export default {
},
methods: {
changeValue(value) {
this.$emit('value-change', value)
this.inDraw && this.$emit('set-condition-value', { component: this.element, value: [value], operator: this.operator })
}
}
}

View File

@ -0,0 +1,15 @@
/**
* fieldId 字段ID
* value 字段值
* operator 操作[eq, ne, gt, ge, lt, le, in, not in, like, not like]
* viewIds 过滤视图范围
*/
export class Condition {
constructor(componentId, fieldId, operator, value, viewIds) {
this.componentId = componentId
this.fieldId = fieldId
this.operator = operator || 'eq'
this.value = value
this.viewIds = viewIds
}
}

View File

@ -1,8 +0,0 @@
export class Widget {
constructor(options = {}) {
this.type = options.type
this.default_style = options.default_style
this.icon = options.icon
this.lable = options.label
}
}

View File

@ -0,0 +1,83 @@
import { DrawWidgetService } from '../service/DrawWidgetService'
const leftPanel = {
// name: 'text-select',
icon: 'iconfont icon-xialakuang',
label: '文本下拉',
defaultClass: 'text-filter'
}
const dialogPanel = {
options: {
refId: '1234567890',
attrs: {
multiple: false,
placeholder: '请选择',
datas: [],
key: 'id',
label: 'text',
value: 'id'
},
value: ''
},
defaultClass: 'text-filter',
component: 'de-select'
}
const drawPanel = {
type: 'custom',
style: {
width: 200,
height: 22,
fontSize: 14,
fontWeight: 500,
lineHeight: '',
letterSpacing: 0,
textAlign: '',
color: ''
},
component: 'de-select'
}
class MySelectImpl extends DrawWidgetService {
constructor(options = {}) {
Object.assign(options, { name: 'mySelectWidget' })
super(options)
this.filterDialog = true
this.showSwitch = true
}
initLeftPanel() {
const value = JSON.parse(JSON.stringify(leftPanel))
return value
// console.log('this is first initWidget')
}
initFilterDialog() {
const value = JSON.parse(JSON.stringify(dialogPanel))
return value
}
initDrawPanel() {
const value = JSON.parse(JSON.stringify(drawPanel))
return value
}
filterFieldMethod(fields) {
return fields.filter(field => {
return field['deType'] === 0
})
}
optionDatas(datas) {
if (!datas) return null
return datas.map(item => {
return {
id: item,
text: item
}
})
}
}
const mySelectImpl = new MySelectImpl()
export default mySelectImpl

View File

@ -31,7 +31,8 @@ requireComponent.keys().forEach(fileName => {
)
})
const req = require.context('./serviceImpl', false, /\.js$/)
// const req = require.context('./serviceImpl', false, /\.js$/)
const req = require.context('./drawServiceImpl', false, /\.js$/)
const requireAll = requireContext => requireContext.keys()
const widgets = {}

View File

@ -0,0 +1,53 @@
import store from '@/store'
export const commonStyle = {
rotate: 0,
opacity: 1
}
export const commonAttr = {
animations: [],
events: {},
groupStyle: {}, // 当一个组件成为 Group 的子组件时使用
isLock: false // 是否锁定组件
}
export class DrawWidgetService {
constructor(options) {
this.options = options
this.name = options.name
// this.leftPanelPath = 'application/addLeftWidget'
// this.dialogPanelPath = 'application/addDialogWidget'
// this.drawPanelPath = 'application/addDrawWidget'
this.storeWidget()
}
/**
* 存储数据到本地
* @param {本地存储路径} path
* @param {要存储的数据} data
*/
store(path, data) {
store.dispatch(path, data)
}
getLeftPanel() {
return this.initLeftPanel()
}
getDialogPanel() {
return this.initFilterDialog()
}
getDrawPanel() {
let drawPanel = this.initDrawPanel()
drawPanel.serviceName = this.options.name
drawPanel.style = Object.assign(drawPanel.style, commonStyle)
drawPanel = Object.assign(drawPanel, commonAttr)
if (this.filterDialog) {
const dialogOptions = this.getDialogPanel()
drawPanel = Object.assign(drawPanel, dialogOptions)
}
return drawPanel
}
storeWidget() {
this.store('application/loadBean', { key: this.name, value: this })
}
}

View File

@ -697,7 +697,9 @@ export default {
rose_type: '玫瑰图模式',
radius_mode: '半径',
area_mode: '面积',
rose_radius: '圆角'
rose_radius: '圆角',
view_name: '视图名称',
name_can_not_empty: '名称不能为空'
},
dataset: {
datalist: '数据集',
@ -777,9 +779,14 @@ export default {
showRow: '显示行',
add_excel_table: '添加Excel数据集',
add_custom_table: '添加自助数据集',
upload_file: '上传文件'
upload_file: '上传文件',
detail: '详情',
type: '类型',
create_by: '创建者',
create_time: '创建时间'
},
datasource: {
datasource: '数据源',
create: '新建数据连接',
type: '类型',
please_choose_type: '请选择数据源类型',

View File

@ -18,6 +18,9 @@ const getters = {
loadingMap: state => state.request.loadingMap,
currentPath: state => state.permission.currentPath,
permissions: state => state.user.permissions,
beanMap: state => state.application.beanMap
beanMap: state => state.application.beanMap,
leftWidgetMap: state => state.application.leftWidgetMap,
dialogWidgetMap: state => state.application.dialogWidgetMap,
drawWidgetMap: state => state.application.drawWidgetMap
}
export default getters

View File

@ -97,6 +97,26 @@ const data = {
}
},
setComponentWithId(state, component) {
for (let index = 0; index < state.componentData.length; index++) {
const element = state.componentData[index]
if (element.id && element.id === component.id) {
state.componentData[index] = component
return
}
}
state.componentData.push(component)
},
deleteComponentWithId(state, id) {
for (let index = 0; index < state.componentData.length; index++) {
const element = state.componentData[index]
if (element.id && element.id === id) {
state.componentData.splice(index, 1)
break
}
}
},
deleteComponent(state, index) {
if (index === undefined) {
index = state.curComponentIndex

View File

@ -1,11 +1,26 @@
const state = {
beanMap: {}
beanMap: {},
leftWidgetMap: {},
dialogWidgetMap: {},
drawWidgetMap: {}
}
const mutations = {
ADD_BEAN: (state, { key, value }) => {
state.beanMap[key] = value
},
ADD_LEFT_WIDGET: (state, { uuid, leftPanel }) => {
state.leftWidgetMap[uuid] = leftPanel
},
ADD_DIALOG_WIDGET: (state, { uuid, dialogPanel }) => {
state.dialogWidgetMap[uuid] = dialogPanel
},
ADD_DRAW_WIDGET: (state, { uuid, drawPanel }) => {
state.drawWidgetMap[uuid] = drawPanel
}
}
@ -13,7 +28,20 @@ const mutations = {
const actions = {
loadBean({ commit }, data) {
commit('ADD_BEAN', data)
},
addLeftWidget({ commit }, data) {
commit('ADD_LEFT_WIDGET', data)
},
addDialogWidget({ commit }, data) {
commit('ADD_DIALOG_WIDGET', data)
},
addDrawWidget({ commit }, data) {
commit('ADD_DRAW_WIDGET', data)
}
}
export default {

View File

@ -199,10 +199,17 @@
width="70%"
class="dialog-css"
>
<el-row style="width: 400px;">
<el-form ref="form" :model="table" label-width="80px" size="mini" class="form-item">
<el-form-item :label="$t('chart.view_name')">
<el-input v-model="table.name" size="mini" />
</el-form-item>
</el-form>
</el-row>
<table-selector @getTable="getTable" />
<div slot="footer" class="dialog-footer">
<el-button size="mini" @click="selectTableFlag = false">{{ $t('chart.cancel') }}</el-button>
<el-button type="primary" size="mini" @click="createChart">{{ $t('chart.confirm') }}</el-button>
<el-button size="mini" @click="closeCreateChart">{{ $t('chart.cancel') }}</el-button>
<el-button type="primary" size="mini" :disabled="!table.id" @click="createChart">{{ $t('chart.confirm') }}</el-button>
</div>
</el-dialog>
@ -518,10 +525,24 @@ export default {
this.selectTableFlag = true
},
closeCreateChart() {
this.selectTableFlag = false
this.table = {}
},
createChart() {
console.log(this.table)
if (!this.table.name) {
this.$message({
message: this.$t('chart.name_can_not_empty'),
type: 'error',
showClose: true
})
return
}
const view = {}
view.name = this.table.name
view.title = this.table.name
view.sceneId = this.currGroup.id
view.tableId = this.table.id
view.type = 'bar'
@ -540,7 +561,7 @@ export default {
})
view.customFilter = JSON.stringify([])
post('/chart/view/save', view).then(response => {
this.selectTableFlag = false
this.closeCreateChart()
this.$store.dispatch('chart/setTableId', null)
this.$store.dispatch('chart/setTableId', this.table.id)
// this.$router.push('/chart/chart-edit')
@ -551,7 +572,7 @@ export default {
},
getTable(table) {
this.table = table
this.table = JSON.parse(JSON.stringify(table))
},
refresh() {
@ -630,4 +651,8 @@ export default {
.dialog-css >>> .el-dialog__body {
padding: 10px 20px 20px;
}
.form-item>>>.el-form-item__label{
font-size: 12px;
}
</style>

View File

@ -2,7 +2,16 @@
<el-row style="height: 100%;overflow-y: hidden;width: 100%;">
<span v-show="false">{{ vId }}</span>
<el-row style="height: 40px;background-color: white" class="padding-lr">
<span style="line-height: 40px;">{{ view.name }}</span>
<el-popover
placement="right-start"
width="400"
trigger="click"
@show="showTab"
@hide="hideTab"
>
<dataset-chart-detail type="chart" :data="view" :tab-status="tabStatus" />
<span slot="reference" style="line-height: 40px;cursor: pointer;">{{ view.name }}</span>
</el-popover>
<span style="float: right;line-height: 40px;">
<el-button size="mini" @click="closeEdit">
{{ $t('chart.close') }}
@ -132,7 +141,7 @@
</el-tab-pane>
</el-tabs>
</div>
<div style="overflow:auto;border-top: 1px solid #e6e6e6" class="padding-lr filter-class">
<div v-if="false" style="overflow:auto;border-top: 1px solid #e6e6e6" class="padding-lr filter-class">
<span>{{ $t('chart.result_filter') }}</span>
<div style="margin: 8px" class="filter-inner-class">
<draggable
@ -229,6 +238,7 @@ import QuotaItem from '../components/drag-item/QuotaItem'
import FilterItem from '../components/drag-item/FilterItem'
import ChartComponent from '../components/ChartComponent'
import bus from '@/utils/bus'
import DatasetChartDetail from '../../dataset/common/DatasetChartDetail'
// shape attr,component style
import {
@ -255,7 +265,7 @@ import QuotaFilterEditor from '../components/filter/QuotaFilterEditor'
export default {
name: 'ChartEdit',
components: { QuotaFilterEditor, BackgroundColorSelector, FilterItem, XAxisSelector, YAxisSelector, TooltipSelector, LabelSelector, LegendSelector, TitleSelector, SizeSelector, ColorSelector, ChartComponent, QuotaItem, DimensionItem, draggable },
components: { DatasetChartDetail, QuotaFilterEditor, BackgroundColorSelector, FilterItem, XAxisSelector, YAxisSelector, TooltipSelector, LabelSelector, LegendSelector, TitleSelector, SizeSelector, ColorSelector, ChartComponent, QuotaItem, DimensionItem, draggable },
data() {
return {
table: {},
@ -296,7 +306,8 @@ export default {
name: [
{ required: true, message: this.$t('commons.input_content'), trigger: 'change' }
]
}
},
tabStatus: false
}
},
computed: {
@ -380,7 +391,9 @@ export default {
},
getData(id) {
if (id) {
post('/chart/view/getData/' + id, null).then(response => {
post('/chart/view/getData/' + id, {
filter: []
}).then(response => {
this.initTableData(response.data.tableId)
this.view = JSON.parse(JSON.stringify(response.data))
this.view.xaxis = this.view.xaxis ? JSON.parse(this.view.xaxis) : []
@ -577,6 +590,13 @@ export default {
},
resetRename() {
// this.itemForm = {}
},
showTab() {
this.tabStatus = true
},
hideTab() {
this.tabStatus = false
}
}
}

View File

@ -24,10 +24,11 @@
</el-form-item>
<el-form-item>
<el-upload
action="https://jsonplaceholder.typicode.com/posts/"
action="/posts/"
:multiple="false"
:show-file-list="false"
accept=".xls,.xlsx,.csv"
:on-success="uploadSuccess"
>
<el-button size="mini" type="primary">{{ $t('dataset.upload_file') }}</el-button>
</el-upload>
@ -117,6 +118,9 @@ export default {
// this.options = response.data
// })
// },
uploadSuccess(response, file, fileList) {
console.log(response)
},
save() {
// console.log(this.checkTableList);

View File

@ -0,0 +1,165 @@
<template>
<el-col>
<el-row>
<span style="font-weight: 500;">{{ $t('dataset.detail') }}</span>
</el-row>
<el-col>
<el-tabs v-if="tabStatus" v-model="tabActive" class="info-tab">
<el-tab-pane v-if="type === 'chart'" :label="$t('chart.datalist')" name="chart">
<el-col class="info-item">
<p class="info-title">{{ $t('commons.name') }}</p>
<p class="info-content">{{ detail.chart.name }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('chart.chart_type') }}</p>
<svg-icon v-if="detail.chart.type" :icon-class="detail.chart.type" />
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('chart.title') }}</p>
<p class="info-content">{{ detail.chart.title || 'N/A' }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('dataset.create_by') }}</p>
<p class="info-content">{{ detail.chart.createBy }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('dataset.create_time') }}</p>
<p class="info-content">{{ detail.chart.createTime | timestampFormatDate }}</p>
</el-col>
</el-tab-pane>
<el-tab-pane :label="$t('dataset.datalist')" name="table">
<el-col class="info-item">
<p class="info-title">{{ $t('commons.name') }}</p>
<p class="info-content">{{ detail.table.name }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('dataset.type') }}</p>
<p v-if="detail.table.type === 'db'" class="info-content">{{ $t('dataset.db_data') }}</p>
<p v-if="detail.table.type === 'sql'" class="info-content">{{ $t('dataset.sql_data') }}</p>
<p v-if="detail.table.type === 'excel'" class="info-content">{{ $t('dataset.excel_data') }}</p>
<p v-if="detail.table.type === 'custom'" class="info-content">{{ $t('dataset.custom_data') }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('dataset.mode') }}</p>
<p v-if="detail.table.mode === 0" class="info-content">{{ $t('dataset.direct_connect') }}</p>
<p v-if="detail.table.mode === 1" class="info-content">{{ $t('dataset.sync_data') }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('dataset.create_by') }}</p>
<p class="info-content">{{ detail.table.createBy }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('dataset.create_time') }}</p>
<p class="info-content">{{ detail.table.createTime | timestampFormatDate }}</p>
</el-col>
</el-tab-pane>
<el-tab-pane :label="$t('datasource.datasource')" name="datasource">
<el-col class="info-item">
<p class="info-title">{{ $t('commons.name') }}</p>
<p class="info-content">{{ detail.datasource.name }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('commons.description') }}</p>
<p class="info-content">{{ detail.datasource.desc || 'N/A' }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('datasource.type') }}</p>
<p class="info-content">{{ detail.datasource.type }}</p>
</el-col>
<el-col class="info-item">
<p class="info-title">{{ $t('dataset.create_time') }}</p>
<p class="info-content">{{ detail.datasource.createTime | timestampFormatDate }}</p>
</el-col>
</el-tab-pane>
</el-tabs>
</el-col>
</el-col>
</template>
<script>
import { post } from '@/api/dataset/dataset'
export default {
name: 'DatasetChartDetail',
props: {
type: {
type: String,
required: true
},
data: {
type: Object,
required: true
},
tabStatus: {
type: Boolean,
required: true
}
},
data() {
return {
tabActive: 'chart',
detail: {
chart: {},
table: {},
datasource: {}
}
}
},
watch: {
'data': function() {
this.init()
},
'type': function() {
this.typeChange()
},
'tabStatus': function() {
this.typeChange()
}
},
mounted() {
this.init()
},
methods: {
init() {
if (this.data.id) {
if (this.type === 'dataset') {
post('/dataset/table/datasetDetail/' + this.data.id, null).then(res => {
this.detail = res.data
})
} else if (this.type === 'chart') {
post('/chart/view/chartDetail/' + this.data.id, null).then(res => {
this.detail = res.data
})
}
}
},
typeChange() {
if (this.type === 'dataset') {
this.tabActive = 'table'
} else if (this.type === 'chart') {
this.tabActive = 'chart'
}
}
}
}
</script>
<style scoped>
.info-tab>>>.el-tabs__item{
font-weight: 400;
font-size: 12px;
}
.info-item{
margin: 6px 0;
}
.info-title{
margin: 0!important;
font-weight: 600;
font-size: 12px;
}
.info-content{
margin: 0!important;
font-size: 12px;
}
</style>

View File

@ -3,9 +3,18 @@
<el-row>
<el-row style="height: 26px;">
<span v-show="false">{{ tableId }}</span>
<span style="line-height: 26px;">
{{ table.name }}
</span>
<el-popover
placement="right-start"
width="400"
trigger="click"
@show="showTab"
@hide="hideTab"
>
<dataset-chart-detail type="dataset" :data="table" :tab-status="tabStatus" />
<span slot="reference" style="line-height: 26px;cursor: pointer;">
{{ table.name }}
</span>
</el-popover>
<el-row style="float: right">
<el-button v-if="table.type ==='sql'" size="mini" @click="editSql">
{{ $t('dataset.edit_sql') }}
@ -81,10 +90,11 @@
import { getTable, getPreviewData, fieldList, batchEdit } from '@/api/dataset/dataset'
import TabDataPreview from './TabDataPreview'
import UpdateInfo from './UpdateInfo'
import DatasetChartDetail from '../common/DatasetChartDetail'
export default {
name: 'ViewTable',
components: { UpdateInfo, TabDataPreview },
components: { DatasetChartDetail, UpdateInfo, TabDataPreview },
data() {
return {
createViewDialog: false,
@ -98,7 +108,8 @@ export default {
tableFields: [],
tableViewRowForm: {
row: 1000
}
},
tabStatus: false
}
},
computed: {
@ -173,6 +184,13 @@ export default {
reSearch(val) {
this.tableViewRowForm = val
this.initPreviewData()
},
showTab() {
this.tabStatus = true
},
hideTab() {
this.tabStatus = false
}
}
}

View File

@ -69,19 +69,25 @@
</de-container>
<el-dialog
v-if="filterVisible"
v-if="filterVisible && panelInfo.id"
title="过滤组件"
:visible.sync="filterVisible"
custom-class="de-filter-dialog"
>
<filter-dialog v-if="filterVisible" :component-info="currentComponent" :widget-id="currentWidgetId" @re-fresh-component="reFreshComponent">
<de-drawing-widget
v-if="filterVisible && currentComponent"
:id="'component' + currentComponent.id"
<filter-dialog v-if="filterVisible && currentWidget" :widget-info="currentWidget" :component-info="currentFilterCom" @re-fresh-component="reFreshComponent">
<!-- <de-drawing-widget
v-if="filterVisible"
style="width: 100% !important;"
class="component"
:element="currentComponent"
:item="currentComponent"
:service-name="currentWidget.name"
/> -->
<component
:is="currentFilterCom.component"
:id="'component' + currentFilterCom.id"
class="component"
:style="currentFilterCom.style"
:element="currentFilterCom"
:in-draw="false"
/>
</filter-dialog>
<!-- <div slot="footer" class="dialog-footer">
@ -144,9 +150,8 @@ export default {
activeName: 'attr',
reSelectAnimateIndex: undefined,
filterVisible: false,
currentWidgetId: null,
currentWidget: null,
currentComponent: null
currentFilterCom: null
}
},
@ -158,7 +163,8 @@ export default {
'componentData',
'curComponent',
'isClickComponent',
'canvasStyleData'
'canvasStyleData',
'curComponentIndex'
])
},
@ -174,7 +180,6 @@ export default {
}
},
panelInfo(newVal, oldVal) {
debugger
this.init(newVal.id)
}
},
@ -189,6 +194,10 @@ export default {
bus.$on('component-on-drag', () => {
this.show = false
})
bus.$on('component-dialog-edit', () => {
this.eidtDialog()
})
},
beforeDestroy() {
const elx = this.$refs.rightPanel
@ -196,7 +205,6 @@ export default {
},
methods: {
init(panelId) {
debugger
// 使
const componentDataTemp = this.$store.state.panel.componentDataTemp
const canvasStyleDataTemp = this.$store.state.panel.canvasStyleDataTemp
@ -252,6 +260,7 @@ export default {
e.stopPropagation()
let component
const newComponentId = uuid.v1()
const componentInfo = JSON.parse(e.dataTransfer.getData('componentInfo'))
//
@ -268,16 +277,17 @@ export default {
})
} else {
this.currentWidget = ApplicationContext.getService(componentInfo.id)
this.currentFilterCom = this.currentWidget.getDrawPanel()
this.currentFilterCom.style.top = e.offsetY
this.currentFilterCom.style.left = e.offsetX
this.currentFilterCom.id = newComponentId
if (this.currentWidget.filterDialog) {
this.show = false
this.currentComponent = deepCopy(this.currentWidget)
this.currentComponent.style.top = e.offsetY
this.currentComponent.style.left = e.offsetX
this.currentComponent.id = newComponentId
this.openFilterDiolog()
return
}
component = deepCopy(this.currentWidget)
component = deepCopy(this.currentFilterCom)
}
component.style.top = e.offsetY
@ -285,6 +295,11 @@ export default {
component.id = newComponentId
this.$store.commit('addComponent', { component })
this.$store.commit('recordSnapshot')
this.clearCurrentInfo()
},
clearCurrentInfo() {
this.currentWidget = null
this.currentFilterCom = null
},
handleDragOver(e) {
@ -311,23 +326,28 @@ export default {
}
},
openFilterDiolog() {
this.currentWidgetId = this.currentComponent.name
this.filterVisible = true
},
cancelFilter() {
this.filterVisible = false
this.currentWidgetId = null
this.currentWidget = null
this.currentComponent = null
this.clearCurrentInfo()
},
sureFilter() {
const component = deepCopy(this.currentComponent)
this.$store.commit('addComponent', { component })
const component = deepCopy(this.currentFilterCom)
// this.$store.commit('addComponent', { component })
this.$store.commit('setComponentWithId', component)
this.$store.commit('recordSnapshot')
this.cancelFilter()
},
reFreshComponent(component) {
this.currentComponent = component
this.currentFilterCom = component
},
eidtDialog() {
const serviceName = this.curComponent.serviceName
this.currentWidget = ApplicationContext.getService(serviceName)
this.currentFilterCom = this.curComponent
this.openFilterDiolog()
}
}
}

View File

@ -106,14 +106,17 @@
<el-col :span="8">
<div class="filter-options-left">
<el-switch
active-text="单选"
inactive-text="多选"
v-if="widget.showSwitch"
v-model="componentInfo.options.attrs.multiple"
active-text="多选"
inactive-text="单选"
/>
</div>
</el-col>
<el-col :span="16"><div class="filter-options-right">
<el-checkbox disabled>备选项1</el-checkbox>
<el-checkbox disabled>备选项</el-checkbox>
<el-checkbox v-model="customRange"><span> 自定义控制范围 </span> </el-checkbox>
<i :class="{'i-filter-active': customRange, 'i-filter-inactive': !customRange}" class="el-icon-setting i-filter" @click="showFilterRange" />
<!-- <el-checkbox disabled>备选项</el-checkbox> -->
</div>
</el-col>
@ -144,7 +147,7 @@ import DeContainer from '@/components/dataease/DeContainer'
import DeAsideContainer from '@/components/dataease/DeAsideContainer'
import draggable from 'vuedraggable'
import DragItem from '@/components/DragItem'
import { ApplicationContext } from '@/utils/ApplicationContext'
// import { ApplicationContext } from '@/utils/ApplicationContext'
import { groupTree, loadTable, fieldList, fieldValues } from '@/api/dataset/dataset'
export default {
name: 'FilterDialog',
@ -156,8 +159,9 @@ export default {
DragItem
},
props: {
widgetId: {
type: String,
widgetInfo: {
type: Object,
default: null
},
componentInfo: {
@ -181,27 +185,34 @@ export default {
},
selectField: [],
widget: null,
fieldValues: []
fieldValues: [],
customRange: false
}
},
watch: {
selectField(values) {
if (values && values.length > 0) {
const value = values[0]
const fieldId = value.id
this.componentInfo && this.componentInfo.setOptionDatas && fieldValues(fieldId).then(res => {
const datas = res.data.map(item => {
return { id: item, text: item }
})
this.componentInfo.setOptionDatas(datas)
this.$emit('re-fresh-component', this.componentInfo)
const info = this.componentInfo
this.widget && fieldValues(fieldId).then(res => {
info.options.attrs.datas = this.widget.optionDatas(res.data)
info.options.attrs.fieldId = fieldId
info.options.attrs.dragItems = values
this.$emit('re-fresh-component', info)
})
}
}
},
created() {
this.widget = ApplicationContext.getService(this.widgetId)
// this.widget = ApplicationContext.getService(this.widgetId)
this.widget = this.widgetInfo
this.loadDataSetTree()
if (this.componentInfo && this.componentInfo.options.attrs.dragItems) {
this.selectField = this.componentInfo.options.attrs.dragItems
}
},
methods: {
@ -322,6 +333,12 @@ export default {
closeItem(tag) {
const index = tag.index
this.selectField.splice(index, 1)
},
showFilterRange() {
//
if (!this.customRange) {
return
}
}
}
}
@ -454,5 +471,17 @@ export default {
width: 100%;
height: 100%;
}
.i-filter {
text-align: center;
margin-left: 5px;
margin-top: 1px;
}
.i-filter-inactive {
color: #9ea6b2!important;
cursor: not-allowed!important;
}
.i-filter-active {
cursor: pointer!important;
}
</style>

View File

@ -10,8 +10,8 @@
<div class="filter-widget-content">
<div
v-for="(widget, index) in item"
:key="widget.name+index"
:data-id="widget.name"
:key="widget.widgetName+index"
:data-id="widget.widgetName"
draggable
:data-index="index"
:class="'filter-widget '+ (widget.defaultClass || '')"
@ -35,23 +35,29 @@ export default {
data() {
return {
componentList,
panelInfo: this.$store.state.panel.panelInfo,
widgetSubjects: {
'时间过滤组件': [
'timeYearWidget',
'timeMonthWidget',
'timeQuarterWidget',
'timeDateWidget',
'timeDateRangeWidget'
],
'文本过滤组件': [
'textSelectWidget',
'textInputWidget'
],
'按钮': [
'buttonSureWidget'
'mySelectWidget'
]
}
// widgetSubjects: {
// '': [
// 'timeYearWidget',
// 'timeMonthWidget',
// 'timeQuarterWidget',
// 'timeDateWidget',
// 'timeDateRangeWidget'
// ],
// '': [
// 'textSelectWidget',
// 'textInputWidget'
// ],
// '': [
// 'buttonSureWidget'
// ]
// }
}
},
created() {
@ -59,7 +65,9 @@ export default {
const widgetNames = this.widgetSubjects[key]
this.widgetSubjects[key] = widgetNames.map(widgetName => {
const widget = ApplicationContext.getService(widgetName)
return widget
const result = { widgetName: widgetName }
Object.assign(result, widget.getLeftPanel())
return result
})
}
},