Commit d88ad7e8 by yuwei

项目初始化

parent 00b002e0
...@@ -25,6 +25,7 @@ import org.springframework.stereotype.Service; ...@@ -25,6 +25,7 @@ import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
@Slf4j @Slf4j
@Service @Service
...@@ -40,14 +41,11 @@ public class ApiMappingEngine { ...@@ -40,14 +41,11 @@ public class ApiMappingEngine {
private ApiMaskServiceFeign apiMaskServiceFeign; private ApiMaskServiceFeign apiMaskServiceFeign;
public PageResult<Map<String, Object>> execute(DataApiEntity dataApi, Map<String, Object> params) { public PageResult<Map<String, Object>> execute(DataApiEntity dataApi, Map<String, Object> params) {
MetadataSourceEntity dataSource = metadataSourceServiceFeign.getMetadataSourceById(dataApi.getExecuteConfig().getSourceId()); MetadataSourceEntity dataSource = Optional.ofNullable(metadataSourceServiceFeign.getMetadataSourceById(dataApi.getExecuteConfig().getSourceId())).orElseThrow(() -> new DataException("API调用查询数据源出错"));
if (dataSource == null) {
throw new DataException("API调用查询数据源出错");
}
DbSchema dbSchema = dataSource.getDbSchema(); DbSchema dbSchema = dataSource.getDbSchema();
DbQueryProperty dbQueryProperty = new DbQueryProperty(dataSource.getDbType(), dbSchema.getHost(), DbQueryProperty dbQueryProperty = new DbQueryProperty(dataSource.getDbType(), dbSchema.getHost(),
dbSchema.getUsername(), dbSchema.getPassword(), dbSchema.getPort(), dbSchema.getDbName(), dbSchema.getSid()); dbSchema.getUsername(), dbSchema.getPassword(), dbSchema.getPort(), dbSchema.getDbName(), dbSchema.getSid());
DbQuery dbQuery = dataSourceFactory.createDbQuery(dbQueryProperty); DbQuery dbQuery = Optional.ofNullable(dataSourceFactory.createDbQuery(dbQueryProperty)).orElseThrow(() -> new DataException("创建数据查询接口出错"));
// 参数 // 参数
Integer pageNum = Integer.parseInt((String) params.getOrDefault("pageNum", 1)); Integer pageNum = Integer.parseInt((String) params.getOrDefault("pageNum", 1));
Integer pageSize = Integer.parseInt((String) params.getOrDefault("pageSize", 20)); Integer pageSize = Integer.parseInt((String) params.getOrDefault("pageSize", 20));
......
package cn.datax.service.data.visual.api.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class ChartColumnParse implements Serializable {
private static final long serialVersionUID=1L;
private String col;
private String alias;
/**
* 指标聚合函数类型
*/
private String aggregateType;
/**
* 指标柱状、折线图表类型
*/
private String seriesType;
}
...@@ -2,10 +2,22 @@ package cn.datax.service.data.visual.api.dto; ...@@ -2,10 +2,22 @@ package cn.datax.service.data.visual.api.dto;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
@Data @Data
public class ChartConfig implements Serializable { public class ChartConfig implements Serializable {
private static final long serialVersionUID=1L; private static final long serialVersionUID=1L;
@NotBlank(message = "数据集不能为空")
private String datasetId;
@NotBlank(message = "图表类型不能为空")
private String chartType;
private List<ChartColumnParse> rows;
private List<ChartColumnParse> columns;
@NotEmpty(message = "指标不能为空")
private List<ChartColumnParse> measures;
} }
...@@ -74,6 +74,11 @@ ...@@ -74,6 +74,11 @@
<artifactId>data-visual-service-api</artifactId> <artifactId>data-visual-service-api</artifactId>
<version>2.0.0</version> <version>2.0.0</version>
</dependency> </dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>data-metadata-service-api</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
...@@ -4,7 +4,7 @@ import org.springframework.boot.SpringApplication; ...@@ -4,7 +4,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients(basePackages = {"cn.datax.service.system.api.feign"}) @EnableFeignClients(basePackages = {"cn.datax.service.system.api.feign", "cn.datax.service.data.metadata.api.feign"})
@SpringCloudApplication @SpringCloudApplication
public class DataxVisualApplication { public class DataxVisualApplication {
......
...@@ -3,6 +3,7 @@ package cn.datax.service.data.visual.controller; ...@@ -3,6 +3,7 @@ package cn.datax.service.data.visual.controller;
import cn.datax.common.core.JsonPage; import cn.datax.common.core.JsonPage;
import cn.datax.common.core.R; import cn.datax.common.core.R;
import cn.datax.common.validate.ValidationGroups; import cn.datax.common.validate.ValidationGroups;
import cn.datax.service.data.visual.api.dto.ChartConfig;
import cn.datax.service.data.visual.api.dto.ChartDto; import cn.datax.service.data.visual.api.dto.ChartDto;
import cn.datax.service.data.visual.api.entity.ChartEntity; import cn.datax.service.data.visual.api.entity.ChartEntity;
import cn.datax.service.data.visual.api.vo.ChartVo; import cn.datax.service.data.visual.api.vo.ChartVo;
...@@ -23,6 +24,7 @@ import org.springframework.web.bind.annotation.*; ...@@ -23,6 +24,7 @@ import org.springframework.web.bind.annotation.*;
import cn.datax.common.base.BaseController; import cn.datax.common.base.BaseController;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
...@@ -137,4 +139,10 @@ public class ChartController extends BaseController { ...@@ -137,4 +139,10 @@ public class ChartController extends BaseController {
chartService.copyChart(id); chartService.copyChart(id);
return R.ok(); return R.ok();
} }
@PostMapping("/data/parser")
public R dataParser(@RequestBody @Validated ChartConfig chartConfig) {
Map<String, Object> map = chartService.dataParser(chartConfig);
return R.ok().setData(map);
}
} }
package cn.datax.service.data.visual.service; package cn.datax.service.data.visual.service;
import cn.datax.service.data.visual.api.dto.ChartConfig;
import cn.datax.service.data.visual.api.entity.ChartEntity; import cn.datax.service.data.visual.api.entity.ChartEntity;
import cn.datax.service.data.visual.api.dto.ChartDto; import cn.datax.service.data.visual.api.dto.ChartDto;
import cn.datax.common.base.BaseService; import cn.datax.common.base.BaseService;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* <p> * <p>
...@@ -27,4 +29,6 @@ public interface ChartService extends BaseService<ChartEntity> { ...@@ -27,4 +29,6 @@ public interface ChartService extends BaseService<ChartEntity> {
void deleteChartBatch(List<String> ids); void deleteChartBatch(List<String> ids);
void copyChart(String id); void copyChart(String id);
Map<String, Object> dataParser(ChartConfig chartConfig);
} }
package cn.datax.service.data.visual.service.impl; package cn.datax.service.data.visual.service.impl;
import cn.datax.common.core.DataConstant; import cn.datax.common.core.DataConstant;
import cn.datax.common.database.DataSourceFactory;
import cn.datax.common.database.DbQuery;
import cn.datax.common.database.constants.DbQueryProperty;
import cn.datax.common.exception.DataException; import cn.datax.common.exception.DataException;
import cn.datax.service.data.metadata.api.dto.DbSchema;
import cn.datax.service.data.metadata.api.entity.MetadataSourceEntity;
import cn.datax.service.data.metadata.api.feign.MetadataSourceServiceFeign;
import cn.datax.service.data.visual.api.dto.ChartColumnParse;
import cn.datax.service.data.visual.api.dto.ChartConfig;
import cn.datax.service.data.visual.api.entity.ChartEntity; import cn.datax.service.data.visual.api.entity.ChartEntity;
import cn.datax.service.data.visual.api.dto.ChartDto; import cn.datax.service.data.visual.api.dto.ChartDto;
import cn.datax.service.data.visual.api.entity.DataSetEntity;
import cn.datax.service.data.visual.dao.DataSetDao;
import cn.datax.service.data.visual.service.ChartService; import cn.datax.service.data.visual.service.ChartService;
import cn.datax.service.data.visual.mapstruct.ChartMapper; import cn.datax.service.data.visual.mapstruct.ChartMapper;
import cn.datax.service.data.visual.dao.ChartDao; import cn.datax.service.data.visual.dao.ChartDao;
...@@ -16,8 +26,8 @@ import org.springframework.transaction.annotation.Propagation; ...@@ -16,8 +26,8 @@ import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.*;
import java.util.Optional; import java.util.stream.Collectors;
/** /**
* <p> * <p>
...@@ -37,6 +47,15 @@ public class ChartServiceImpl extends BaseServiceImpl<ChartDao, ChartEntity> imp ...@@ -37,6 +47,15 @@ public class ChartServiceImpl extends BaseServiceImpl<ChartDao, ChartEntity> imp
@Autowired @Autowired
private ChartMapper chartMapper; private ChartMapper chartMapper;
@Autowired
private DataSetDao dataSetDao;
@Autowired
private DataSourceFactory dataSourceFactory;
@Autowired
private MetadataSourceServiceFeign metadataSourceServiceFeign;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ChartEntity saveChart(ChartDto chartDto) { public ChartEntity saveChart(ChartDto chartDto) {
...@@ -81,4 +100,34 @@ public class ChartServiceImpl extends BaseServiceImpl<ChartDao, ChartEntity> imp ...@@ -81,4 +100,34 @@ public class ChartServiceImpl extends BaseServiceImpl<ChartDao, ChartEntity> imp
copy.setStatus(DataConstant.EnableState.ENABLE.getKey()); copy.setStatus(DataConstant.EnableState.ENABLE.getKey());
chartDao.insert(copy); chartDao.insert(copy);
} }
@Override
public Map<String, Object> dataParser(ChartConfig chartConfig) {
String datasetId = chartConfig.getDatasetId();
DataSetEntity dataSetEntity = Optional.ofNullable(dataSetDao.selectById(datasetId)).orElseThrow(() -> new DataException("获取数据集失败"));
MetadataSourceEntity metadataSourceEntity = Optional.ofNullable(metadataSourceServiceFeign.getMetadataSourceById(dataSetEntity.getSourceId())).orElseThrow(() -> new DataException("获取数据源失败"));
DbSchema dbSchema = metadataSourceEntity.getDbSchema();
DbQueryProperty dbQueryProperty = new DbQueryProperty(metadataSourceEntity.getDbType(), dbSchema.getHost(),
dbSchema.getUsername(), dbSchema.getPassword(), dbSchema.getPort(), dbSchema.getDbName(), dbSchema.getSid());
DbQuery dbQuery = Optional.ofNullable(dataSourceFactory.createDbQuery(dbQueryProperty)).orElseThrow(() -> new DataException("创建数据查询接口出错"));
List<ChartColumnParse> rows = chartConfig.getRows();
List<ChartColumnParse> columns = chartConfig.getColumns();
List<ChartColumnParse> measures = chartConfig.getMeasures();
String setSql = dataSetEntity.getSetSql();
StringBuilder sql = new StringBuilder();
List<ChartColumnParse> groups = new ArrayList<>();
groups.addAll(rows);
groups.addAll(columns);
String groupJoining = groups.stream().map(s -> s.getCol()).collect(Collectors.joining(", ", " ", ","));
sql.append("SELECT").append(groupJoining);
String measureJoining = Optional.ofNullable(measures).orElse(new ArrayList<>()).stream().map(s -> new StringBuilder().append(s.getAggregateType()).append("(").append(s.getCol()).append(") AS ").append(s.getCol())).collect(Collectors.joining(", ", " ", " "));
sql.append(measureJoining);
sql.append("FROM (").append(setSql).append(") TEMP_VIEW ").append("GROUP BY ").append(groups.stream().map(s -> s.getCol()).collect(Collectors.joining(", ")));
List<Map<String, Object>> data = dbQuery.queryList(sql.toString());
Map<String, Object> map = new HashMap<>(2);
map.put("data", data);
map.put("sql", sql.toString());
return map;
}
} }
...@@ -44,3 +44,11 @@ export function copyDataChart(id) { ...@@ -44,3 +44,11 @@ export function copyDataChart(id) {
method: 'post' method: 'post'
}) })
} }
export function dataParser(data) {
return request({
url: '/data/visual/charts/data/parser',
method: 'post',
data: data
})
}
import request from '@/utils/request' import request from '@/utils/request'
export function listDataSet (data) { export function listDataSet(data) {
return request({ return request({
url: '/data/visual/dataSets/list', url: '/data/visual/dataSets/list',
method: 'get', method: 'get',
...@@ -8,7 +8,7 @@ export function listDataSet (data) { ...@@ -8,7 +8,7 @@ export function listDataSet (data) {
}) })
} }
export function pageDataSet (data) { export function pageDataSet(data) {
return request({ return request({
url: '/data/visual/dataSets/page', url: '/data/visual/dataSets/page',
method: 'get', method: 'get',
...@@ -16,28 +16,28 @@ export function pageDataSet (data) { ...@@ -16,28 +16,28 @@ export function pageDataSet (data) {
}) })
} }
export function getDataSet (id) { export function getDataSet(id) {
return request({ return request({
url: '/data/visual/dataSets/' + id, url: '/data/visual/dataSets/' + id,
method: 'get' method: 'get'
}) })
} }
export function delDataSet (id) { export function delDataSet(id) {
return request({ return request({
url: '/data/visual/dataSets/' + id, url: '/data/visual/dataSets/' + id,
method: 'delete' method: 'delete'
}) })
} }
export function delDataSets (ids) { export function delDataSets(ids) {
return request({ return request({
url: '/data/visual/dataSets/batch/' + ids, url: '/data/visual/dataSets/batch/' + ids,
method: 'delete' method: 'delete'
}) })
} }
export function addDataSet (data) { export function addDataSet(data) {
return request({ return request({
url: '/data/visual/dataSets', url: '/data/visual/dataSets',
method: 'post', method: 'post',
...@@ -45,7 +45,7 @@ export function addDataSet (data) { ...@@ -45,7 +45,7 @@ export function addDataSet (data) {
}) })
} }
export function updateDataSet (data) { export function updateDataSet(data) {
return request({ return request({
url: '/data/visual/dataSets/' + data.id, url: '/data/visual/dataSets/' + data.id,
method: 'put', method: 'put',
...@@ -53,7 +53,7 @@ export function updateDataSet (data) { ...@@ -53,7 +53,7 @@ export function updateDataSet (data) {
}) })
} }
export function sqlAnalyse (data) { export function sqlAnalyse(data) {
return request({ return request({
url: '/data/visual/dataSets/sql/analyse', url: '/data/visual/dataSets/sql/analyse',
method: 'post', method: 'post',
......
...@@ -2,6 +2,7 @@ const chartTypes = [ ...@@ -2,6 +2,7 @@ const chartTypes = [
{ {
name: '表格', value: 'table', icon: 'chart_table', name: '表格', value: 'table', icon: 'chart_table',
status: true, status: true,
component: 'ChartTable',
rule: { rule: {
text: '0个或多个 行维;0个或多个 列维;0个或多个 指标', text: '0个或多个 行维;0个或多个 列维;0个或多个 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -12,6 +13,7 @@ const chartTypes = [ ...@@ -12,6 +13,7 @@ const chartTypes = [
{ {
name: '折线图', value: 'line', icon: 'chart_line', name: '折线图', value: 'line', icon: 'chart_line',
status: true, status: true,
component: 'ChartLine',
rule: { rule: {
text: '1个或多个 行维;0个或多个 列维;1个或多个 指标', text: '1个或多个 行维;0个或多个 列维;1个或多个 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -22,6 +24,7 @@ const chartTypes = [ ...@@ -22,6 +24,7 @@ const chartTypes = [
{ {
name: '柱状图', value: 'bar', icon: 'chart_bar', name: '柱状图', value: 'bar', icon: 'chart_bar',
status: true, status: true,
component: 'ChartBar',
rule: { rule: {
text: '1个或多个 行维;0个或多个 列维;1个或多个 指标', text: '1个或多个 行维;0个或多个 列维;1个或多个 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -32,6 +35,7 @@ const chartTypes = [ ...@@ -32,6 +35,7 @@ const chartTypes = [
{ {
name: '饼图', value: 'pie', icon: 'chart_pie', name: '饼图', value: 'pie', icon: 'chart_pie',
status: true, status: true,
component: 'ChartPie',
rule: { rule: {
text: '1个或多个 行维;0个或多个 列维;1个或多个 指标', text: '1个或多个 行维;0个或多个 列维;1个或多个 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -42,6 +46,7 @@ const chartTypes = [ ...@@ -42,6 +46,7 @@ const chartTypes = [
{ {
name: '指标卡', value: 'kpi', icon: 'chart_kpi', name: '指标卡', value: 'kpi', icon: 'chart_kpi',
status: true, status: true,
component: 'ChartKpi',
rule: { rule: {
text: '0 行维;0 列维;1 指标', text: '0 行维;0 列维;1 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -52,6 +57,7 @@ const chartTypes = [ ...@@ -52,6 +57,7 @@ const chartTypes = [
{ {
name: '雷达图', value: 'radar', icon: 'chart_radar', name: '雷达图', value: 'radar', icon: 'chart_radar',
status: true, status: true,
component: 'ChartRadar',
rule: { rule: {
text: '1个或多个 行维;0个或多个 列维;1个或多个 指标', text: '1个或多个 行维;0个或多个 列维;1个或多个 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -62,6 +68,7 @@ const chartTypes = [ ...@@ -62,6 +68,7 @@ const chartTypes = [
{ {
name: '漏斗图', value: 'funnel', icon: 'chart_funnel', name: '漏斗图', value: 'funnel', icon: 'chart_funnel',
status: true, status: true,
component: 'ChartFunnel',
rule: { rule: {
text: '0个或多个 行维;0 列维;1个或多个 指标', text: '0个或多个 行维;0 列维;1个或多个 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -72,6 +79,7 @@ const chartTypes = [ ...@@ -72,6 +79,7 @@ const chartTypes = [
{ {
name: '散点图', value: 'scatter', icon: 'chart_scatter', name: '散点图', value: 'scatter', icon: 'chart_scatter',
status: true, status: true,
component: 'ChartScatter',
rule: { rule: {
text: '1个或多个 行维;0个或多个 列维;1个或多个 指标', text: '1个或多个 行维;0个或多个 列维;1个或多个 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -82,6 +90,7 @@ const chartTypes = [ ...@@ -82,6 +90,7 @@ const chartTypes = [
{ {
name: '仪表盘', value: 'gauge', icon: 'chart_gauge', name: '仪表盘', value: 'gauge', icon: 'chart_gauge',
status: true, status: true,
component: 'ChartGauge',
rule: { rule: {
text: '0 行维;0 列维;1 指标', text: '0 行维;0 列维;1 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -92,6 +101,7 @@ const chartTypes = [ ...@@ -92,6 +101,7 @@ const chartTypes = [
{ {
name: '矩形树图', value: 'treemap', icon: 'chart_treemap', name: '矩形树图', value: 'treemap', icon: 'chart_treemap',
status: true, status: true,
component: 'ChartTreemap',
rule: { rule: {
text: '1个或多个 行维;0 列维;1 指标', text: '1个或多个 行维;0 列维;1 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -102,6 +112,7 @@ const chartTypes = [ ...@@ -102,6 +112,7 @@ const chartTypes = [
{ {
name: '词云图', value: 'wordcloud', icon: 'chart_wordcloud', name: '词云图', value: 'wordcloud', icon: 'chart_wordcloud',
status: true, status: true,
component: 'ChartWordcloud',
rule: { rule: {
text: '1个或多个 行维;0 列维;1 指标', text: '1个或多个 行维;0 列维;1 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -112,6 +123,7 @@ const chartTypes = [ ...@@ -112,6 +123,7 @@ const chartTypes = [
{ {
name: '水球图', value: 'liquidfill', icon: 'chart_liquidfill', name: '水球图', value: 'liquidfill', icon: 'chart_liquidfill',
status: true, status: true,
component: 'ChartLiquidfill',
rule: { rule: {
text: '0 行维;0 列维;1 指标', text: '0 行维;0 列维;1 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -122,6 +134,7 @@ const chartTypes = [ ...@@ -122,6 +134,7 @@ const chartTypes = [
{ {
name: '桑基图', value: 'sankey', icon: 'chart_sankey', name: '桑基图', value: 'sankey', icon: 'chart_sankey',
status: true, status: true,
component: 'ChartSankey',
rule: { rule: {
text: '1个或多个 行维;0个或多个 列维;1 指标', text: '1个或多个 行维;0个或多个 列维;1 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -132,6 +145,7 @@ const chartTypes = [ ...@@ -132,6 +145,7 @@ const chartTypes = [
{ {
name: '地图', value: 'geo', icon: 'chart_geo', name: '地图', value: 'geo', icon: 'chart_geo',
status: true, status: true,
component: 'ChartGeo',
rule: { rule: {
text: '1个或多个 行维;0个或多个 列维;1个或多个 指标', text: '1个或多个 行维;0个或多个 列维;1个或多个 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -142,6 +156,7 @@ const chartTypes = [ ...@@ -142,6 +156,7 @@ const chartTypes = [
{ {
name: '树图', value: 'tree', icon: 'chart_tree', name: '树图', value: 'tree', icon: 'chart_tree',
status: false, status: false,
component: 'ChartTree',
rule: { rule: {
text: '0 行维;0 列维;0 指标', text: '0 行维;0 列维;0 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -152,6 +167,7 @@ const chartTypes = [ ...@@ -152,6 +167,7 @@ const chartTypes = [
{ {
name: '环形图', value: 'donut', icon: 'chart_donut', name: '环形图', value: 'donut', icon: 'chart_donut',
status: false, status: false,
component: 'ChartDonut',
rule: { rule: {
text: '0 行维;0 列维;0 指标', text: '0 行维;0 列维;0 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -162,6 +178,7 @@ const chartTypes = [ ...@@ -162,6 +178,7 @@ const chartTypes = [
{ {
name: '旭日图', value: 'sunburst', icon: 'chart_sunburst', name: '旭日图', value: 'sunburst', icon: 'chart_sunburst',
status: false, status: false,
component: 'ChartSunburst',
rule: { rule: {
text: '0 行维;0 列维;0 指标', text: '0 行维;0 列维;0 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
...@@ -172,6 +189,7 @@ const chartTypes = [ ...@@ -172,6 +189,7 @@ const chartTypes = [
{ {
name: '极区图', value: 'polar', icon: 'chart_polar', name: '极区图', value: 'polar', icon: 'chart_polar',
status: false, status: false,
component: 'ChartPolar',
rule: { rule: {
text: '0 行维;0 列维;0 指标', text: '0 行维;0 列维;0 指标',
check(rows, columns, measures) { check(rows, columns, measures) {
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
</div> </div>
<div class="widget-center-container"> <div class="widget-center-container">
<div class="widget-center-header"> <div class="widget-center-header">
<el-button icon="el-icon-view" type="text"> <el-button icon="el-icon-view" type="text" @click="handlePreview">
预览 预览
</el-button> </el-button>
<el-button icon="el-icon-delete" type="text" @click="handleReset"> <el-button icon="el-icon-delete" type="text" @click="handleReset">
...@@ -62,13 +62,13 @@ ...@@ -62,13 +62,13 @@
<div class="widget-center-draggable-text"> <div class="widget-center-draggable-text">
<draggable group="measures" :list="widget.measures" @change="handleValueDragChange" class="widget-center-draggable-line"> <draggable group="measures" :list="widget.measures" @change="handleValueDragChange" class="widget-center-draggable-line">
<div v-for="(item, index) in widget.measures" :key="index" class="draggable-item"> <div v-for="(item, index) in widget.measures" :key="index" class="draggable-item">
<el-tag>{{ item.alias ? item.aggregate_type + '(' + item.col + ') -> ' + item.alias : item.aggregate_type + '(' + item.col + ')' }}</el-tag> <el-tag>{{ item.alias ? item.aggregateType + '(' + item.col + ') -> ' + item.alias : item.aggregateType + '(' + item.col + ')' }}</el-tag>
<el-popover <el-popover
placement="top" placement="top"
width="400" width="400"
trigger="click" trigger="click"
> >
<el-radio-group v-model="item.aggregate_type" size="mini"> <el-radio-group v-model="item.aggregateType" size="mini">
<el-radio label="sum" size="mini">求和</el-radio> <el-radio label="sum" size="mini">求和</el-radio>
<el-radio label="count" size="mini">计数</el-radio> <el-radio label="count" size="mini">计数</el-radio>
<el-radio label="avg" size="mini">平均值</el-radio> <el-radio label="avg" size="mini">平均值</el-radio>
...@@ -85,10 +85,12 @@ ...@@ -85,10 +85,12 @@
<div class="widget-center-pane"> <div class="widget-center-pane">
<el-tabs type="card"> <el-tabs type="card">
<el-tab-pane label="图表预览"> <el-tab-pane label="图表预览">
<div class="widget-center-pane-chart">图表预览</div> <div class="widget-center-pane-chart">
<chart-panel :chart-type.sync="widget.chartType" :data="chartData.data" :schema="widget"/>
</div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="查询脚本"> <el-tab-pane label="查询脚本">
<div class="widget-center-pane-script">查询脚本</div> <div class="widget-center-pane-script">{{ chartData.sql }}</div>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
...@@ -102,6 +104,14 @@ ...@@ -102,6 +104,14 @@
<el-form-item label="图表名称"> <el-form-item label="图表名称">
<el-input v-model="datachart.chartName" size="mini" :disabled="true" /> <el-input v-model="datachart.chartName" size="mini" :disabled="true" />
</el-form-item> </el-form-item>
<el-form-item label="缩略图">
<el-button type="primary" size="mini" plain style="margin-bottom: 10px;">点击生成</el-button>
<el-image :src="datachart.chartThumbnail ? ('data:image/png;base64,' + datachart.chartThumbnail) : ''">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline" />
</div>
</el-image>
</el-form-item>
<el-form-item label="图表类型"> <el-form-item label="图表类型">
<div class="chart-type-list"> <div class="chart-type-list">
<span v-for="item in chartTypes" :key="item.value" :class="item.value === widget.chartType ? 'active': ''" @click="item.status && item.rule.check(widget.rows, widget.columns, widget.measures) && changeChart(item.value)"> <span v-for="item in chartTypes" :key="item.value" :class="item.value === widget.chartType ? 'active': ''" @click="item.status && item.rule.check(widget.rows, widget.columns, widget.measures) && changeChart(item.value)">
...@@ -123,15 +133,17 @@ ...@@ -123,15 +133,17 @@
</template> </template>
<script> <script>
import { getDataChart } from '@/api/visual/datachart' import { getDataChart, dataParser } from '@/api/visual/datachart'
import { getDataSet, listDataSet } from '@/api/visual/dataset' import { getDataSet, listDataSet } from '@/api/visual/dataset'
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
import chartTypes from '@/utils/visual-chart' import chartTypes from '@/utils/visual-chart'
import ChartPanel from './components/ChartPanel'
export default { export default {
name: 'DataChartConfig', name: 'DataChartConfig',
components: { components: {
draggable draggable,
ChartPanel
}, },
data() { data() {
return { return {
...@@ -141,13 +153,21 @@ export default { ...@@ -141,13 +153,21 @@ export default {
chartType: 'table', chartType: 'table',
rows: [], rows: [],
columns: [], columns: [],
measures: [] measures: [],
// 后期添加条件过滤
filters: [],
// 后期添加图表配置项
chartOptions: {}
}, },
datasetOptions: [], datasetOptions: [],
dataset: {}, dataset: {},
dimensions: [], dimensions: [],
measures: [], measures: [],
chartTypes chartTypes,
chartData: {
data: [],
sql: ''
}
} }
}, },
created() { created() {
...@@ -174,8 +194,7 @@ export default { ...@@ -174,8 +194,7 @@ export default {
if (response.success) { if (response.success) {
this.dataset = response.data this.dataset = response.data
this.widget.datasetId = this.dataset.id this.widget.datasetId = this.dataset.id
this.dimensions = JSON.parse(JSON.stringify(this.dataset.schemaConfig.dimensions)) this.handleReset()
this.measures = JSON.parse(JSON.stringify(this.dataset.schemaConfig.measures))
} }
}) })
}, },
...@@ -189,14 +208,23 @@ export default { ...@@ -189,14 +208,23 @@ export default {
}, },
handleValueDragChange(tag) { handleValueDragChange(tag) {
if (tag.added) { if (tag.added) {
this.$set(tag.added.element, 'aggregate_type', 'sum') this.$set(tag.added.element, 'aggregateType', 'sum')
} }
}, },
handleValueTagClose(index, tag) { handleValueTagClose(index, tag) {
this.widget.measures.splice(index, 1) this.widget.measures.splice(index, 1)
tag.aggregate_type = '' tag.aggregateType = ''
this.measures.push(tag) this.measures.push(tag)
}, },
handlePreview() {
dataParser(this.widget).then(response => {
if (response.success) {
const { data } = response
this.chartData.data = data.data
this.chartData.sql = data.sql
}
})
},
handleReset() { handleReset() {
this.dimensions = JSON.parse(JSON.stringify(this.dataset.schemaConfig.dimensions)) this.dimensions = JSON.parse(JSON.stringify(this.dataset.schemaConfig.dimensions))
this.measures = JSON.parse(JSON.stringify(this.dataset.schemaConfig.measures)) this.measures = JSON.parse(JSON.stringify(this.dataset.schemaConfig.measures))
...@@ -379,6 +407,20 @@ export default { ...@@ -379,6 +407,20 @@ export default {
height: calc(100vh - 40px); height: calc(100vh - 40px);
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
.el-image{
width: 250px;
height: 150px;
::v-deep .image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: #f5f7fa;
color: #909399;
font-size: 30px;
}
}
.chart-type-list { .chart-type-list {
width: 100%; width: 100%;
display: grid; display: grid;
......
<template>
<component :is="currentChart.component" :data="data" :schema="schema" :chart-style="chartStyle" />
</template>
<script>
import chartTypes from '@/utils/visual-chart'
import ChartTable from './widgets/ChartTable'
import ChartLine from './widgets/ChartLine'
import ChartBar from './widgets/ChartBar'
import ChartPie from './widgets/ChartPie'
import ChartKpi from './widgets/ChartKpi'
import ChartRadar from './widgets/ChartRadar'
import ChartFunnel from './widgets/ChartFunnel'
import ChartScatter from './widgets/ChartScatter'
import ChartGauge from './widgets/ChartGauge'
import ChartTreemap from './widgets/ChartTreemap'
import ChartWordcloud from './widgets/ChartWordcloud'
import ChartLiquidfill from './widgets/ChartLiquidfill'
import ChartSankey from './widgets/ChartSankey'
import ChartGeo from './widgets/ChartGeo'
import ChartTree from './widgets/ChartTree'
import ChartDonut from './widgets/ChartDonut'
import ChartSunburst from './widgets/ChartSunburst'
import ChartPolar from './widgets/ChartPolar'
export default {
name: 'ChartPanel',
components: {
ChartTable, ChartLine, ChartBar, ChartPie,
ChartKpi, ChartRadar, ChartFunnel, ChartScatter,
ChartGauge, ChartTreemap, ChartWordcloud, ChartLiquidfill,
ChartSankey, ChartGeo, ChartTree, ChartDonut,
ChartSunburst, ChartPolar
},
props: {
data: {
type: Array,
required: true
},
schema: {
type: Object,
required: true
},
chartStyle: {
type: Object,
require: false
},
chartType: {
type: String,
default: 'table'
}
},
data() {
return {
chartTypes
}
},
computed: {
currentChart() {
return chartTypes.find(item => item.value === this.chartType)
}
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartBar</div>
</template>
<script>
export default {
name: 'ChartBar',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartDonut</div>
</template>
<script>
export default {
name: 'ChartDonut',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartFunnel</div>
</template>
<script>
export default {
name: 'ChartFunnel',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartGauge</div>
</template>
<script>
export default {
name: 'ChartGauge',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartGeo</div>
</template>
<script>
export default {
name: 'ChartGeo',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartKpi</div>
</template>
<script>
export default {
name: 'ChartKpi',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartLine</div>
</template>
<script>
export default {
name: 'ChartLine',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartLiquidfill</div>
</template>
<script>
export default {
name: 'ChartLiquidfill',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartPie</div>
</template>
<script>
export default {
name: 'ChartPie',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartPolar</div>
</template>
<script>
export default {
name: 'ChartPolar',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartRadar</div>
</template>
<script>
export default {
name: 'ChartRadar',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartSankey</div>
</template>
<script>
export default {
name: 'ChartSankey',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartScatter</div>
</template>
<script>
export default {
name: 'ChartScatter',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartSunburst</div>
</template>
<script>
export default {
name: 'ChartSunburst',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartTable</div>
</template>
<script>
export default {
name: 'ChartTable',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartTree</div>
</template>
<script>
export default {
name: 'ChartTree',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartTreemap</div>
</template>
<script>
export default {
name: 'ChartTreemap',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div ref="chart" :style="chartStyle">ChartWordcloud</div>
</template>
<script>
export default {
name: 'ChartWordcloud',
props: {
data: {
type: Array,
required: true,
default: () => {
return []
}
},
schema: {
type: Object,
required: true,
default: () => {
return {}
}
},
chartStyle: {
type: Object,
require: false,
default: () => {
return {
height: '200px'
}
}
}
},
created() {
console.log(this.data)
}
}
</script>
<style lang="scss" scoped>
</style>
...@@ -54,35 +54,31 @@ ...@@ -54,35 +54,31 @@
<el-row> <el-row>
<el-divider content-position="left">维度列</el-divider> <el-divider content-position="left">维度列</el-divider>
<el-col> <el-col>
<div style="height: 90px; border: 1px dashed #999; margin: 0 10px;"> <draggable group="col" :list="dimensionList" class="draggable-wrapper">
<draggable group="col" :list="dimensionList"> <div v-for="(item, index) in dimensionList" :key="index" class="draggable-item">
<div v-for="(item, index) in dimensionList" :key="index" class="draggable-item"> <el-tag>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</el-tag>
<el-tag>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</el-tag> <span v-if="item.input" class="draggable-item-handle">
<span v-if="item.input" class="draggable-item-handle"> <el-input v-model="item.alias" size="mini" placeholder="请输入内容" @blur="handleDelTagLabel(index, item)" />
<el-input v-model="item.alias" size="mini" placeholder="请输入内容" @blur="handleDelTagLabel(index, item)" /> </span>
</span> <span v-else class="draggable-item-handle" @click="handleTagLabel(index, item)"><i class="el-icon-edit-outline" /></span>
<span v-else class="draggable-item-handle" @click="handleTagLabel(index, item)"><i class="el-icon-edit-outline" /></span> <span class="draggable-item-handle" @click="handleDimensionTagClose(index, item)"><i class="el-icon-delete" /></span>
<span class="draggable-item-handle" @click="handleDimensionTagClose(index, item)"><i class="el-icon-delete" /></span> </div>
</div> </draggable>
</draggable>
</div>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-divider content-position="left">指标列</el-divider> <el-divider content-position="left">指标列</el-divider>
<el-col> <el-col>
<div style="height: 90px; border: 1px dashed #999; margin: 0 10px;"> <draggable group="col" :list="measureList" class="draggable-wrapper">
<draggable group="col" :list="measureList"> <div v-for="(item, index) in measureList" :key="index" class="draggable-item">
<div v-for="(item, index) in measureList" :key="index" class="draggable-item"> <el-tag>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</el-tag>
<el-tag>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</el-tag> <span v-if="item.input" class="draggable-item-handle">
<span v-if="item.input" class="draggable-item-handle"> <el-input v-model="item.alias" size="mini" placeholder="请输入内容" @blur="handleDelTagLabel(index, item)" />
<el-input v-model="item.alias" size="mini" placeholder="请输入内容" @blur="handleDelTagLabel(index, item)" /> </span>
</span> <span v-else class="draggable-item-handle" @click="handleTagLabel(index, item)"><i class="el-icon-edit-outline" /></span>
<span v-else class="draggable-item-handle" @click="handleTagLabel(index, item)"><i class="el-icon-edit-outline" /></span> <span class="draggable-item-handle" @click="handleMeasureTagClose(index, item)"><i class="el-icon-delete" /></span>
<span class="draggable-item-handle" @click="handleMeasureTagClose(index, item)"><i class="el-icon-delete" /></span> </div>
</div> </draggable>
</draggable>
</div>
</el-col> </el-col>
</el-row> </el-row>
</el-col> </el-col>
...@@ -362,29 +358,36 @@ export default { ...@@ -362,29 +358,36 @@ export default {
margin: 10px; margin: 10px;
cursor: move; cursor: move;
} }
.draggable-item { .draggable-wrapper {
cursor: move; height: 90px;
margin: 5px 5px; border: 1px dashed #999;
display: inline-block; margin: 0 10px;
border: 1px solid #ebecef; overflow-x: hidden;
height: 32px; overflow-y: auto;
line-height: 30px; .draggable-item {
border-radius: 4px; cursor: move;
.draggable-item-handle { margin: 5px 5px;
background-color: #ecf5ff;
border-color: #d9ecff;
display: inline-block; display: inline-block;
border: 1px solid #ebecef;
height: 32px; height: 32px;
padding: 0 10px;
line-height: 30px; line-height: 30px;
font-size: 12px; border-radius: 4px;
color: #409EFF; .draggable-item-handle {
border-width: 1px; background-color: #ecf5ff;
border-style: solid; border-color: #d9ecff;
box-sizing: border-box; display: inline-block;
white-space: nowrap; height: 32px;
cursor: pointer; padding: 0 10px;
margin-left: -5px; line-height: 30px;
font-size: 12px;
color: #409EFF;
border-width: 1px;
border-style: solid;
box-sizing: border-box;
white-space: nowrap;
cursor: pointer;
margin-left: -5px;
}
} }
} }
</style> </style>
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
<el-row> <el-row>
<el-divider content-position="left">维度列</el-divider> <el-divider content-position="left">维度列</el-divider>
<el-col> <el-col>
<div style="height: 90px; border: 1px dashed #999; margin: 0 10px;"> <div class="draggable-wrapper">
<el-tag v-for="(item, index) in dimensionList" :key="index" class="draggable-item"> <el-tag v-for="(item, index) in dimensionList" :key="index" class="draggable-item">
{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }} {{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}
</el-tag> </el-tag>
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
<el-row> <el-row>
<el-divider content-position="left">指标列</el-divider> <el-divider content-position="left">指标列</el-divider>
<el-col> <el-col>
<div style="height: 90px; border: 1px dashed #999; margin: 0 10px;"> <div class="draggable-wrapper">
<el-tag v-for="(item, index) in measureList" :key="index" class="draggable-item"> <el-tag v-for="(item, index) in measureList" :key="index" class="draggable-item">
{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }} {{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}
</el-tag> </el-tag>
...@@ -266,29 +266,36 @@ export default { ...@@ -266,29 +266,36 @@ export default {
margin: 10px; margin: 10px;
cursor: move; cursor: move;
} }
.draggable-item { .draggable-wrapper {
cursor: move; height: 90px;
margin: 5px 5px; border: 1px dashed #999;
display: inline-block; margin: 0 10px;
border: 1px solid #ebecef; overflow-x: hidden;
height: 32px; overflow-y: auto;
line-height: 30px; .draggable-item {
border-radius: 4px; cursor: move;
.draggable-item-handle { margin: 5px 5px;
background-color: #ecf5ff;
border-color: #d9ecff;
display: inline-block; display: inline-block;
border: 1px solid #ebecef;
height: 32px; height: 32px;
padding: 0 10px;
line-height: 30px; line-height: 30px;
font-size: 12px; border-radius: 4px;
color: #409EFF; .draggable-item-handle {
border-width: 1px; background-color: #ecf5ff;
border-style: solid; border-color: #d9ecff;
box-sizing: border-box; display: inline-block;
white-space: nowrap; height: 32px;
cursor: pointer; padding: 0 10px;
margin-left: -5px; line-height: 30px;
font-size: 12px;
color: #409EFF;
border-width: 1px;
border-style: solid;
box-sizing: border-box;
white-space: nowrap;
cursor: pointer;
margin-left: -5px;
}
} }
} }
</style> </style>
...@@ -54,35 +54,31 @@ ...@@ -54,35 +54,31 @@
<el-row> <el-row>
<el-divider content-position="left">维度列</el-divider> <el-divider content-position="left">维度列</el-divider>
<el-col> <el-col>
<div style="height: 90px; border: 1px dashed #999; margin: 0 10px;"> <draggable group="col" :list="dimensionList" class="draggable-wrapper">
<draggable group="col" :list="dimensionList"> <div v-for="(item, index) in dimensionList" :key="index" class="draggable-item">
<div v-for="(item, index) in dimensionList" :key="index" class="draggable-item"> <el-tag>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</el-tag>
<el-tag>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</el-tag> <span v-if="item.input" class="draggable-item-handle">
<span v-if="item.input" class="draggable-item-handle"> <el-input v-model="item.alias" size="mini" placeholder="请输入内容" @blur="handleDelTagLabel(index, item)" />
<el-input v-model="item.alias" size="mini" placeholder="请输入内容" @blur="handleDelTagLabel(index, item)" /> </span>
</span> <span v-else class="draggable-item-handle" @click="handleTagLabel(index, item)"><i class="el-icon-edit-outline" /></span>
<span v-else class="draggable-item-handle" @click="handleTagLabel(index, item)"><i class="el-icon-edit-outline" /></span> <span class="draggable-item-handle" @click="handleDimensionTagClose(index, item)"><i class="el-icon-delete" /></span>
<span class="draggable-item-handle" @click="handleDimensionTagClose(index, item)"><i class="el-icon-delete" /></span> </div>
</div> </draggable>
</draggable>
</div>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-divider content-position="left">指标列</el-divider> <el-divider content-position="left">指标列</el-divider>
<el-col> <el-col>
<div style="height: 90px; border: 1px dashed #999; margin: 0 10px;"> <draggable group="col" :list="measureList" class="draggable-wrapper">
<draggable group="col" :list="measureList"> <div v-for="(item, index) in measureList" :key="index" class="draggable-item">
<div v-for="(item, index) in measureList" :key="index" class="draggable-item"> <el-tag>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</el-tag>
<el-tag>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</el-tag> <span v-if="item.input" class="draggable-item-handle">
<span v-if="item.input" class="draggable-item-handle"> <el-input v-model="item.alias" size="mini" placeholder="请输入内容" @blur="handleDelTagLabel(index, item)" />
<el-input v-model="item.alias" size="mini" placeholder="请输入内容" @blur="handleDelTagLabel(index, item)" /> </span>
</span> <span v-else class="draggable-item-handle" @click="handleTagLabel(index, item)"><i class="el-icon-edit-outline" /></span>
<span v-else class="draggable-item-handle" @click="handleTagLabel(index, item)"><i class="el-icon-edit-outline" /></span> <span class="draggable-item-handle" @click="handleMeasureTagClose(index, item)"><i class="el-icon-delete" /></span>
<span class="draggable-item-handle" @click="handleMeasureTagClose(index, item)"><i class="el-icon-delete" /></span> </div>
</div> </draggable>
</draggable>
</div>
</el-col> </el-col>
</el-row> </el-row>
</el-col> </el-col>
...@@ -381,29 +377,36 @@ export default { ...@@ -381,29 +377,36 @@ export default {
margin: 10px; margin: 10px;
cursor: move; cursor: move;
} }
.draggable-item { .draggable-wrapper {
cursor: move; height: 90px;
margin: 5px 5px; border: 1px dashed #999;
display: inline-block; margin: 0 10px;
border: 1px solid #ebecef; overflow-x: hidden;
height: 32px; overflow-y: auto;
line-height: 30px; .draggable-item {
border-radius: 4px; cursor: move;
.draggable-item-handle { margin: 5px 5px;
background-color: #ecf5ff;
border-color: #d9ecff;
display: inline-block; display: inline-block;
border: 1px solid #ebecef;
height: 32px; height: 32px;
padding: 0 10px;
line-height: 30px; line-height: 30px;
font-size: 12px; border-radius: 4px;
color: #409EFF; .draggable-item-handle {
border-width: 1px; background-color: #ecf5ff;
border-style: solid; border-color: #d9ecff;
box-sizing: border-box; display: inline-block;
white-space: nowrap; height: 32px;
cursor: pointer; padding: 0 10px;
margin-left: -5px; line-height: 30px;
font-size: 12px;
color: #409EFF;
border-width: 1px;
border-style: solid;
box-sizing: border-box;
white-space: nowrap;
cursor: pointer;
margin-left: -5px;
}
} }
} }
</style> </style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment