Merge branch 'dev-v2' into pr@dev-v2@feat_platform_config

This commit is contained in:
fit2cloud-chenyw 2024-05-22 17:14:35 +08:00
commit ecaf1a4fd3
30 changed files with 777 additions and 120 deletions

View File

@ -115,7 +115,9 @@ public class ChartDataManage {
if (StringUtils.equalsIgnoreCase(view.getType(), "table-pivot") if (StringUtils.equalsIgnoreCase(view.getType(), "table-pivot")
|| StringUtils.containsIgnoreCase(view.getType(), "group") || StringUtils.containsIgnoreCase(view.getType(), "group")
|| ("antv".equalsIgnoreCase(view.getRender()) && "line".equalsIgnoreCase(view.getType())) || ("antv".equalsIgnoreCase(view.getRender()) && "line".equalsIgnoreCase(view.getType()))
|| StringUtils.equalsIgnoreCase(view.getType(), "flow-map")) { || StringUtils.equalsIgnoreCase(view.getType(), "flow-map")
|| StringUtils.equalsIgnoreCase(view.getType(), "sankey")
) {
xAxis.addAll(xAxisExt); xAxis.addAll(xAxisExt);
} }
List<ChartViewFieldDTO> yAxis = new ArrayList<>(view.getYAxis()); List<ChartViewFieldDTO> yAxis = new ArrayList<>(view.getYAxis());

View File

@ -59,7 +59,7 @@ public class ApiUtils {
if (apiDefinition == null) { if (apiDefinition == null) {
DEException.throwException("未找到"); DEException.throwException("未找到");
} }
String response = execHttpRequest(apiDefinition, 10); String response = execHttpRequest(apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout());
fieldList = getTableFields(apiDefinition); fieldList = getTableFields(apiDefinition);
result.put("fieldList", fieldList); result.put("fieldList", fieldList);
dataList = fetchResult(response, apiDefinition); dataList = fetchResult(response, apiDefinition);
@ -116,7 +116,7 @@ public class ApiUtils {
if (apiDefinition == null) { if (apiDefinition == null) {
DEException.throwException("未找到"); DEException.throwException("未找到");
} }
String response = execHttpRequest(apiDefinition, 10); String response = execHttpRequest(apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout());
return fetchResult(response, apiDefinition); return fetchResult(response, apiDefinition);
} }
@ -194,6 +194,26 @@ public class ApiUtils {
return response; return response;
} }
private static void previewNum(List<Map<String, Object>> field){
for (Map<String, Object> stringObjectMap : field) {
JSONArray newArray = new JSONArray();
if (stringObjectMap.get("value") != null) {
try {
TypeReference<JSONArray> listTypeReference = new TypeReference<JSONArray>() {
};
JSONArray array = objectMapper.readValue(stringObjectMap.get("value").toString(), listTypeReference);
if(array.size() > 100){
for (int i = 0; i < Math.min(100, array.size()); i++) {
newArray.add(array.get(i));
}
stringObjectMap.put("value", newArray);
}
} catch (Exception e) {
}
}
}
}
public static ApiDefinition checkApiDefinition(ApiDefinition apiDefinition, String response) throws DEException { public static ApiDefinition checkApiDefinition(ApiDefinition apiDefinition, String response) throws DEException {
if (StringUtils.isEmpty(response)) { if (StringUtils.isEmpty(response)) {
@ -217,6 +237,7 @@ public class ApiUtils {
rootPath = "$"; rootPath = "$";
handleStr(apiDefinition, response, fields, rootPath); handleStr(apiDefinition, response, fields, rootPath);
} }
previewNum(fields);
apiDefinition.setJsonFields(fields); apiDefinition.setJsonFields(fields);
return apiDefinition; return apiDefinition;
} else { } else {

View File

@ -117,7 +117,11 @@ public class CalciteProvider {
tableDesc.setDatasourceId(datasourceRequest.getDatasource().getId()); tableDesc.setDatasourceId(datasourceRequest.getDatasource().getId());
tableDesc.setType("db"); tableDesc.setType("db");
tableDesc.setTableName(resultSet.getString(1)); tableDesc.setTableName(resultSet.getString(1));
tableDesc.setName(resultSet.getString(1)); if(resultSet.getMetaData().getColumnCount() > 1){
tableDesc.setName(resultSet.getString(2));
}else {
tableDesc.setName(resultSet.getString(1));
}
return tableDesc; return tableDesc;
} }
@ -315,6 +319,7 @@ public class CalciteProvider {
private String getTableFiledSql(DatasourceRequest datasourceRequest) { private String getTableFiledSql(DatasourceRequest datasourceRequest) {
String sql = ""; String sql = "";
DatasourceConfiguration configuration = null; DatasourceConfiguration configuration = null;
String database="";
DatasourceType datasourceType = DatasourceType.valueOf(datasourceRequest.getDatasource().getType()); DatasourceType datasourceType = DatasourceType.valueOf(datasourceRequest.getDatasource().getType());
switch (datasourceType) { switch (datasourceType) {
case mysql: case mysql:
@ -324,7 +329,16 @@ public class CalciteProvider {
case StarRocks: case StarRocks:
case doris: case doris:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Mysql.class); configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Mysql.class);
sql = String.format("SELECT COLUMN_NAME,DATA_TYPE,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'", configuration.getDataBase(), datasourceRequest.getTable()); if (StringUtils.isEmpty(configuration.getUrlType()) || configuration.getUrlType().equalsIgnoreCase("hostName")) {
database = configuration.getDataBase();
} else {
Pattern WITH_SQL_FRAGMENT = Pattern.compile("jdbc:mysql://(.*):(\\d+)/(.*)");
Matcher matcher = WITH_SQL_FRAGMENT.matcher(configuration.getJdbcUrl());
matcher.find();
String[] databasePrams = matcher.group(3).split("\\?");
database = databasePrams[0];
}
sql = String.format("SELECT COLUMN_NAME,DATA_TYPE,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'", database, datasourceRequest.getTable());
break; break;
case oracle: case oracle:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Oracle.class); configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Oracle.class);
@ -396,6 +410,16 @@ public class CalciteProvider {
break; break;
case ck: case ck:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), CK.class); configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), CK.class);
if (StringUtils.isEmpty(configuration.getUrlType()) || configuration.getUrlType().equalsIgnoreCase("hostName")) {
database = configuration.getDataBase();
} else {
Pattern WITH_SQL_FRAGMENT = Pattern.compile("jdbc:clickhouse://(.*):(\\d+)/(.*)");
Matcher matcher = WITH_SQL_FRAGMENT.matcher(configuration.getJdbcUrl());
matcher.find();
String[] databasePrams = matcher.group(3).split("\\?");
database = databasePrams[0];
}
sql = String.format(" SELECT\n" + sql = String.format(" SELECT\n" +
" name,\n" + " name,\n" +
" type,\n" + " type,\n" +
@ -404,7 +428,7 @@ public class CalciteProvider {
" system.columns\n" + " system.columns\n" +
"WHERE\n" + "WHERE\n" +
" database = '%s' \n" + " database = '%s' \n" +
" AND table = '%s' ", configuration.getDataBase(), datasourceRequest.getTable()); " AND table = '%s' ", database, datasourceRequest.getTable());
break; break;
case impala: case impala:
sql = String.format("DESCRIBE `%s`", datasourceRequest.getTable()); sql = String.format("DESCRIBE `%s`", datasourceRequest.getTable());
@ -742,7 +766,7 @@ public class CalciteProvider {
case StarRocks: case StarRocks:
case doris: case doris:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Mysql.class); configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Mysql.class);
if (configuration.getUrlType().equalsIgnoreCase("")) { if (StringUtils.isEmpty(configuration.getUrlType()) || configuration.getUrlType().equalsIgnoreCase("hostName")) {
database = configuration.getDataBase(); database = configuration.getDataBase();
} else { } else {
Pattern WITH_SQL_FRAGMENT = Pattern.compile("jdbc:mysql://(.*):(\\d+)/(.*)"); Pattern WITH_SQL_FRAGMENT = Pattern.compile("jdbc:mysql://(.*):(\\d+)/(.*)");
@ -758,42 +782,76 @@ public class CalciteProvider {
if (StringUtils.isEmpty(configuration.getSchema())) { if (StringUtils.isEmpty(configuration.getSchema())) {
DEException.throwException(Translator.get("i18n_schema_is_empty")); DEException.throwException(Translator.get("i18n_schema_is_empty"));
} }
tableSqls.add("select table_name, owner, comments from all_tab_comments where owner='" + configuration.getSchema() + "' AND table_type = 'TABLE'"); tableSqls.add("select table_name, comments, owner from all_tab_comments where owner='" + configuration.getSchema() + "' AND table_type = 'TABLE'");
tableSqls.add("select table_name, owner, comments from all_tab_comments where owner='" + configuration.getSchema() + "' AND table_type = 'VIEW'"); tableSqls.add("select table_name, comments, owner from all_tab_comments where owner='" + configuration.getSchema() + "' AND table_type = 'VIEW'");
break; break;
case db2: case db2:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Db2.class); configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Db2.class);
if (StringUtils.isEmpty(configuration.getSchema())) { if (StringUtils.isEmpty(configuration.getSchema())) {
DEException.throwException(Translator.get("i18n_schema_is_empty")); DEException.throwException(Translator.get("i18n_schema_is_empty"));
} }
tableSqls.add("select TABNAME from syscat.tables WHERE TABSCHEMA ='DE_SCHEMA' AND \"TYPE\" = 'T'".replace("DE_SCHEMA", configuration.getSchema())); tableSqls.add("select TABNAME, REMARKS from syscat.tables WHERE TABSCHEMA ='DE_SCHEMA' AND \"TYPE\" = 'T'".replace("DE_SCHEMA", configuration.getSchema()));
break; break;
case sqlServer: case sqlServer:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Sqlserver.class); configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Sqlserver.class);
if (StringUtils.isEmpty(configuration.getSchema())) { if (StringUtils.isEmpty(configuration.getSchema())) {
DEException.throwException(Translator.get("i18n_schema_is_empty")); DEException.throwException(Translator.get("i18n_schema_is_empty"));
} }
tableSqls.add("SELECT TABLE_NAME FROM \"DATABASE\".INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = 'DS_SCHEMA' ;" tableSqls.add("SELECT \n" +
.replace("DATABASE", configuration.getDataBase()) " t.name AS TableName, \n" +
.replace("DS_SCHEMA", configuration.getSchema())); " ep.value AS TableDescription \n" +
tableSqls.add("SELECT TABLE_NAME FROM \"DATABASE\".INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA = 'DS_SCHEMA' ;" "FROM \n" +
.replace("DATABASE", configuration.getDataBase()) " sys.tables t \n" +
"LEFT OUTER JOIN sys.schemas sc ON sc.schema_id =t.schema_id \n" +
"LEFT OUTER JOIN \n" +
" sys.extended_properties ep ON t.object_id = ep.major_id \n" +
" AND ep.minor_id = 0 \n" +
" AND ep.class = 1 \n" +
" AND ep.name = 'MS_Description'\n" +
"where sc.name ='DS_SCHEMA'"
.replace("DS_SCHEMA", configuration.getSchema())); .replace("DS_SCHEMA", configuration.getSchema()));
tableSqls.add("SELECT \n" +
" t.name AS TableName, \n" +
" ep.value AS TableDescription \n" +
"FROM \n" +
" sys.views t \n" +
"LEFT OUTER JOIN sys.schemas sc ON sc.schema_id =t.schema_id \n" +
"LEFT OUTER JOIN \n" +
" sys.extended_properties ep ON t.object_id = ep.major_id \n" +
" AND ep.minor_id = 0 \n" +
" AND ep.class = 1 \n" +
" AND ep.name = 'MS_Description'\n" +
"where sc.name ='DS_SCHEMA'"
.replace("DS_SCHEMA", configuration.getSchema()));
break; break;
case pg: case pg:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Pg.class); configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Pg.class);
if (StringUtils.isEmpty(configuration.getSchema())) { if (StringUtils.isEmpty(configuration.getSchema())) {
DEException.throwException(Translator.get("i18n_schema_is_empty")); DEException.throwException(Translator.get("i18n_schema_is_empty"));
} }
tableSqls.add("SELECT tablename FROM pg_tables WHERE schemaname='SCHEMA' ;".replace("SCHEMA", configuration.getSchema())); tableSqls.add("SELECT \n" +
" relname AS TableName, \n" +
" obj_description(relfilenode::regclass, 'pg_class') AS TableDescription \n" +
"FROM \n" +
" pg_class \n" +
"WHERE \n" +
" relkind = 'r' \n" +
" AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'SCHEMA') ".replace("SCHEMA", configuration.getSchema()));
break; break;
case redshift: case redshift:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), CK.class); configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), CK.class);
tableSqls.add("SELECT tablename FROM pg_tables WHERE schemaname='SCHEMA' ;".replace("SCHEMA", configuration.getSchema())); tableSqls.add("SELECT \n" +
" relname AS TableName, \n" +
" obj_description(relfilenode::regclass, 'pg_class') AS TableDescription \n" +
"FROM \n" +
" pg_class \n" +
"WHERE \n" +
" relkind = 'r' \n" +
" AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'SCHEMA') ".replace("SCHEMA", configuration.getSchema()));
break; break;
case ck: case ck:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), CK.class); configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), CK.class);
if (configuration.getUrlType().equalsIgnoreCase("")) { if (StringUtils.isEmpty(configuration.getUrlType()) || configuration.getUrlType().equalsIgnoreCase("hostName")) {
database = configuration.getDataBase(); database = configuration.getDataBase();
} else { } else {
Pattern WITH_SQL_FRAGMENT = Pattern.compile("jdbc:clickhouse://(.*):(\\d+)/(.*)"); Pattern WITH_SQL_FRAGMENT = Pattern.compile("jdbc:clickhouse://(.*):(\\d+)/(.*)");
@ -802,7 +860,7 @@ public class CalciteProvider {
String[] databasePrams = matcher.group(3).split("\\?"); String[] databasePrams = matcher.group(3).split("\\?");
database = databasePrams[0]; database = databasePrams[0];
} }
tableSqls.add("SELECT name FROM system.tables where database='DATABASE';".replace("DATABASE", database)); tableSqls.add("SELECT name, comment FROM system.tables where database='DATABASE';".replace("DATABASE", database));
break; break;
default: default:

View File

@ -493,6 +493,9 @@ public class DatasourceServer implements DatasourceApi {
public DatasourceDTO get(Long datasourceId) throws DEException { public DatasourceDTO get(Long datasourceId) throws DEException {
DatasourceDTO datasourceDTO = new DatasourceDTO(); DatasourceDTO datasourceDTO = new DatasourceDTO();
CoreDatasource datasource = datasourceMapper.selectById(datasourceId); CoreDatasource datasource = datasourceMapper.selectById(datasourceId);
if(datasource == null){
DEException.throwException("不存在的数据源!");
}
BeanUtils.copyBean(datasourceDTO, datasource); BeanUtils.copyBean(datasourceDTO, datasource);
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() { TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
}; };
@ -834,10 +837,11 @@ public class DatasourceServer implements DatasourceApi {
public ApiDefinition checkApiDatasource(Map<String, String> request) throws DEException { public ApiDefinition checkApiDatasource(Map<String, String> request) throws DEException {
ApiDefinition apiDefinition = JsonUtil.parseObject(new String(java.util.Base64.getDecoder().decode(request.get("data"))), ApiDefinition.class); ApiDefinition apiDefinition = JsonUtil.parseObject(new String(java.util.Base64.getDecoder().decode(request.get("data"))), ApiDefinition.class);
String response = ApiUtils.execHttpRequest(apiDefinition, 10); String response = ApiUtils.execHttpRequest(apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout());
if (request.keySet().contains("type") && request.get("type").equals("apiStructure")) { if (request.keySet().contains("type") && request.get("type").equals("apiStructure")) {
apiDefinition.setShowApiStructure(true); apiDefinition.setShowApiStructure(true);
} }
ApiUtils.checkApiDefinition(apiDefinition, response); ApiUtils.checkApiDefinition(apiDefinition, response);
if (apiDefinition.getRequest().getAuthManager() != null && StringUtils.isNotBlank(apiDefinition.getRequest().getAuthManager().getUsername()) && StringUtils.isNotBlank(apiDefinition.getRequest().getAuthManager().getPassword()) && apiDefinition.getRequest().getAuthManager().getVerification().equals("Basic Auth")) { if (apiDefinition.getRequest().getAuthManager() != null && StringUtils.isNotBlank(apiDefinition.getRequest().getAuthManager().getUsername()) && StringUtils.isNotBlank(apiDefinition.getRequest().getAuthManager().getPassword()) && apiDefinition.getRequest().getAuthManager().getVerification().equals("Basic Auth")) {
apiDefinition.getRequest().getAuthManager().setUsername(new String(Base64.getEncoder().encode(apiDefinition.getRequest().getAuthManager().getUsername().getBytes()))); apiDefinition.getRequest().getAuthManager().setUsername(new String(Base64.getEncoder().encode(apiDefinition.getRequest().getAuthManager().getUsername().getBytes())));

View File

@ -0,0 +1,5 @@
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 32.7862C35.0501 32.7862 43.9248 11.0972 67.002 10.375C67.0341 17.043 66.8736 16.9467 67.002 23.2296C45.7703 23.2296 43.0421 45.6408 13 45.6408C13.0642 40.0801 13.0963 40.0159 13 32.7862Z" fill="#00D6B9"/>
<path d="M13 27.4899C34.6891 27.1288 37.1926 46.0576 67.002 47.9994C67.0341 41.0987 66.8736 51.4819 67.002 44.9744C38.7974 42.3826 36.4624 24.4648 13 24.4648C13.0642 30.2502 13.0963 20.0275 13 27.4899Z" fill="#3370FF"/>
<path d="M13 20.9829C35.0501 20.9829 43.9247 40.2086 67.002 40.9629C67.8204 33.2036 66.8736 34.327 67.002 27.9799C45.7703 27.9799 43.0421 8 13 8C13.0642 13.6249 13.0963 13.7212 13 20.9829Z" fill="#3370FF"/>
</svg>

After

Width:  |  Height:  |  Size: 748 B

View File

@ -146,13 +146,6 @@ const saveSelfSubject = () => {
> >
<filter-style-simple-selector /> <filter-style-simple-selector />
</el-collapse-item> </el-collapse-item>
<el-collapse-item
:title="t('visualization.filter_component')"
name="filterComponent"
class="no-padding no-border-bottom"
>
<filter-style-simple-selector />
</el-collapse-item>
<el-collapse-item <el-collapse-item
title="高级样式设置" title="高级样式设置"
name="seniorStyleSetting" name="seniorStyleSetting"

View File

@ -158,6 +158,21 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-form-item label="分页器配色" class="form-item">
<el-color-picker
:trigger-width="colorPickerWidth"
v-model="seniorForm.pagerColor"
size="small"
:predefine="predefineColors"
color-format="rgb"
:effect="themes"
show-alpha
is-custom
@change="changePagerColorChange"
/>
</el-form-item>
</el-col>
</el-row> </el-row>
</div> </div>
</el-collapse-item> </el-collapse-item>
@ -174,7 +189,10 @@ import eventBus from '@/utils/eventBus'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import CustomColorStyleSelect from '@/views/chart/components/editor/editor-style/components/CustomColorStyleSelect.vue' import CustomColorStyleSelect from '@/views/chart/components/editor/editor-style/components/CustomColorStyleSelect.vue'
import elementResizeDetectorMaker from 'element-resize-detector' import elementResizeDetectorMaker from 'element-resize-detector'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
const { t } = useI18n() const { t } = useI18n()
const snapshotStore = snapshotStoreWithOut()
const props = defineProps({ const props = defineProps({
themes: { themes: {
type: String as PropType<EditorTheme>, type: String as PropType<EditorTheme>,
@ -191,6 +209,9 @@ const colorFormRef = ref(null)
const colorForm = computed( const colorForm = computed(
() => canvasStyleData.value.component.chartColor as DeepPartial<ChartAttr> () => canvasStyleData.value.component.chartColor as DeepPartial<ChartAttr>
) )
const seniorForm = computed(() => canvasStyleData.value.component.seniorStyleSetting)
const predefineColors = COLOR_PANEL const predefineColors = COLOR_PANEL
const state = reactive({ const state = reactive({
@ -215,6 +236,10 @@ const changeColorOption = (modifyName = 'value') => {
changeColorCase(modifyName) changeColorCase(modifyName)
} }
const changePagerColorChange = () => {
snapshotStore.recordSnapshotCache()
}
const changeColorCase = modifyName => { const changeColorCase = modifyName => {
colorForm.value['modifyName'] = modifyName colorForm.value['modifyName'] = modifyName
emits('onColorChange', colorForm.value) emits('onColorChange', colorForm.value)

View File

@ -2,25 +2,37 @@
<div style="width: 100%; padding-bottom: 8px"> <div style="width: 100%; padding-bottom: 8px">
<el-form label-position="top" style="width: 100%"> <el-form label-position="top" style="width: 100%">
<div style="width: 100%; padding: 16px 8px 0"> <div style="width: 100%; padding: 16px 8px 0">
<el-col :span="12"> <el-col :span="24">
<el-form-item class="form-item" label="联动、钻取、调整的图标颜色"> <el-form-item
:effect="themes"
class="form-item"
:class="'form-item-' + themes"
label="联动、钻取、跳转的图标颜色"
>
<el-color-picker <el-color-picker
v-model="filterStyle.titleColor" :effect="themes"
v-model="seniorStyleSetting.linkageIconColor"
:trigger-width="197" :trigger-width="197"
is-custom is-custom
:predefine="state.predefineColors" :predefine="state.predefineColors"
@change="themeChange('titleColor')" @change="themeChange"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="24">
<el-form-item class="form-item" label="钻取层级展示颜色"> <el-form-item
:effect="themes"
class="form-item"
:class="'form-item-' + themes"
label="钻取层级展示颜色"
>
<el-color-picker <el-color-picker
v-model="filterStyle.labelColor" v-model="seniorStyleSetting.drillLayerColor"
:effect="themes"
:trigger-width="197" :trigger-width="197"
is-custom is-custom
:predefine="state.predefineColors" :predefine="state.predefineColors"
@change="themeChange('labelColor')" @change="themeChange"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -35,17 +47,21 @@ import { COLOR_PANEL } from '@/views/chart/components/editor/util/chart'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { adaptCurThemeFilterStyleAll } from '@/utils/canvasStyle'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import eventBus from '@/utils/eventBus' import eventBus from '@/utils/eventBus'
import { ElIcon } from 'element-plus-secondary'
const { t } = useI18n() const { t } = useI18n()
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const filterStyle = computed<any>(() => { const seniorStyleSetting = computed<any>(() => {
return dvMainStore.canvasStyleData.component.filterStyle return dvMainStore.canvasStyleData.component.seniorStyleSetting
}) })
const props = defineProps({
themes: {
type: String,
default: 'light'
}
})
const state = reactive({ const state = reactive({
fontSize: [], fontSize: [],
isSetting: false, isSetting: false,
@ -55,15 +71,9 @@ const state = reactive({
const initForm = () => { const initForm = () => {
// do // do
} }
const themeChange = styleKey => { const themeChange = () => {
dvMainStore.canvasStyleData.component.filterStyle = cloneDeep(filterStyle.value) dvMainStore.canvasStyleData.component.seniorStyleSetting = cloneDeep(seniorStyleSetting.value)
adaptCurThemeFilterStyleAll(styleKey) snapshotStore.recordSnapshotCache('seniorStyleSettingSimpleSelector-themeChange')
snapshotStore.recordSnapshotCache('filterStyleSimpleSelector-themeChange')
}
const handleHorizontalChange = (type, horizontal = 'titleLayout') => {
filterStyle.value[horizontal] = type
themeChange(horizontal)
} }
onMounted(() => { onMounted(() => {
@ -106,4 +116,12 @@ onMounted(() => {
line-height: 20px; line-height: 20px;
} }
} }
.form-item-dark {
:deep(.ed-form-item__label) {
color: #6a6a6a;
font-size: 12px;
font-weight: 400;
line-height: 20px;
}
}
</style> </style>

View File

@ -10,6 +10,7 @@ import { useEmitt } from '@/hooks/web/useEmitt'
import ComponentColorSelector from '@/components/dashboard/subject-setting/dashboard-style/ComponentColorSelector.vue' import ComponentColorSelector from '@/components/dashboard/subject-setting/dashboard-style/ComponentColorSelector.vue'
import OverallSetting from '@/components/dashboard/subject-setting/dashboard-style/OverallSetting.vue' import OverallSetting from '@/components/dashboard/subject-setting/dashboard-style/OverallSetting.vue'
import CanvasBackground from '@/components/visualization/component-background/CanvasBackground.vue' import CanvasBackground from '@/components/visualization/component-background/CanvasBackground.vue'
import SeniorStyleSetting from '@/components/dashboard/subject-setting/dashboard-style/SeniorStyleSetting.vue'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const { canvasStyleData, canvasViewInfo } = storeToRefs(dvMainStore) const { canvasStyleData, canvasViewInfo } = storeToRefs(dvMainStore)
@ -102,6 +103,14 @@ onMounted(() => {
<el-collapse-item effect="dark" title="刷新配置" name="overallSetting"> <el-collapse-item effect="dark" title="刷新配置" name="overallSetting">
<overall-setting themes="dark" /> <overall-setting themes="dark" />
</el-collapse-item> </el-collapse-item>
<el-collapse-item
effect="dark"
title="高级样式设置"
name="seniorStyleSetting"
class="no-padding no-border-bottom"
>
<senior-style-setting themes="dark"></senior-style-setting>
</el-collapse-item>
</el-collapse> </el-collapse>
</div> </div>
</template> </template>

View File

@ -236,6 +236,23 @@ const initWatermark = (waterDomId = 'preview-canvas-main') => {
} }
} }
// targetSourceId ID
const winMsgHandle = event => {
console.info('PostMessage Params Received')
const msgInfo = event.data
// targetSourceId
if (
msgInfo &&
msgInfo.type === 'attachParams' &&
msgInfo.targetSourceId === dvInfo.value.id + ''
) {
const attachParam = msgInfo.params
if (attachParam) {
dvMainStore.addOuterParamsFilter(attachParam, componentData.value, 'outer')
}
}
}
onMounted(() => { onMounted(() => {
initRefreshTimer() initRefreshTimer()
resetLayout() resetLayout()
@ -245,10 +262,12 @@ onMounted(() => {
restore() restore()
initWatermark() initWatermark()
}) })
window.addEventListener('message', winMsgHandle)
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
clearInterval(refreshTimer.value) clearInterval(refreshTimer.value)
window.removeEventListener('message', winMsgHandle)
}) })
const userViewEnlargeOpen = (opt, item) => { const userViewEnlargeOpen = (opt, item) => {

View File

@ -3,7 +3,7 @@
<div v-if="element.frameLinks.src" class="main-frame"> <div v-if="element.frameLinks.src" class="main-frame">
<iframe <iframe
v-if="state.frameShow" v-if="state.frameShow"
id="iframe" :id="'iframe-' + element.id"
:src="element.frameLinks.src" :src="element.frameLinks.src"
scrolling="auto" scrolling="auto"
frameborder="0" frameborder="0"

View File

@ -249,7 +249,7 @@ export default {
remark: '备注', remark: '备注',
column_name: '字段名', column_name: '字段名',
field_type: '字段类型', field_type: '字段类型',
field_description: '字段描述', field_description: '字段备注',
dl: '数据湖', dl: '数据湖',
other: '其他', other: '其他',
local_file: '本地文件', local_file: '本地文件',
@ -338,6 +338,7 @@ export default {
extract: '抽取模式', extract: '抽取模式',
all_compute_mode: '直连抽取模式', all_compute_mode: '直连抽取模式',
extra_params: '额外的JDBC连接字符串', extra_params: '额外的JDBC连接字符串',
jdbcUrl: 'JDBC 连接',
please_input_dataPath: '请输入 JsonPath 数据路径', please_input_dataPath: '请输入 JsonPath 数据路径',
show_api_data: '查看API数据结构', show_api_data: '查看API数据结构',
warning: '包含无效数据表', warning: '包含无效数据表',
@ -393,7 +394,7 @@ export default {
no_data_table: '暂无数据表', no_data_table: '暂无数据表',
on_the_left: '请在左侧选择数据源', on_the_left: '请在左侧选择数据源',
create_dataset: '创建数据集', create_dataset: '创建数据集',
table_description: '描述', table_description: '备注',
relational_database: '关系型数据库', relational_database: '关系型数据库',
data_warehouse_lake: '数仓/数据湖', data_warehouse_lake: '数仓/数据湖',
non_relational_database: '非关系型数据库', non_relational_database: '非关系型数据库',
@ -691,6 +692,7 @@ export default {
chart_pie_rose: '玫瑰图', chart_pie_rose: '玫瑰图',
chart_pie_donut_rose: '玫瑰环形图', chart_pie_donut_rose: '玫瑰环形图',
chart_funnel: '漏斗图', chart_funnel: '漏斗图',
chart_sankey: '桑基图',
chart_radar: '雷达图', chart_radar: '雷达图',
chart_gauge: '仪表盘', chart_gauge: '仪表盘',
chart_map: '地图', chart_map: '地图',
@ -765,6 +767,8 @@ export default {
chart_data: '数据', chart_data: '数据',
chart_style: '样式', chart_style: '样式',
drag_block_type_axis: '类别轴', drag_block_type_axis: '类别轴',
drag_block_type_axis_start: '源',
drag_block_type_axis_end: '目的',
drag_block_value_axis: '值轴', drag_block_value_axis: '值轴',
drag_block_value_start: '开始值', drag_block_value_start: '开始值',
drag_block_value_end: '结束值', drag_block_value_end: '结束值',

View File

@ -5,10 +5,15 @@ import { interactiveStoreWithOut } from '@/store/modules/interactive'
import { useEmbedded } from '@/store/modules/embedded' import { useEmbedded } from '@/store/modules/embedded'
import { check } from '@/utils/CrossPermission' import { check } from '@/utils/CrossPermission'
import { useCache } from '@/hooks/web/useCache' import { useCache } from '@/hooks/web/useCache'
import { getOuterParamsInfo } from '@/api/visualization/outerParams'
import { ElMessage } from 'element-plus-secondary'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { useI18n } from '@/hooks/web/useI18n'
const { wsCache } = useCache() const { wsCache } = useCache()
const interactiveStore = interactiveStoreWithOut() const interactiveStore = interactiveStoreWithOut()
const embeddedStore = useEmbedded() const embeddedStore = useEmbedded()
const dashboardPreview = ref(null) const dashboardPreview = ref(null)
const { t } = useI18n()
const state = reactive({ const state = reactive({
canvasDataPreview: null, canvasDataPreview: null,
canvasStylePreview: null, canvasStylePreview: null,
@ -16,6 +21,8 @@ const state = reactive({
dvInfo: null, dvInfo: null,
curPreviewGap: 0 curPreviewGap: 0
}) })
const dvMainStore = dvMainStoreWithOut()
const checkPer = async resourceId => { const checkPer = async resourceId => {
if (!window.DataEaseBi || !resourceId) { if (!window.DataEaseBi || !resourceId) {
return true return true
@ -30,6 +37,23 @@ onBeforeMount(async () => {
if (!checkResult) { if (!checkResult) {
return return
} }
//
let attachParam
await getOuterParamsInfo(embeddedStore.dvId).then(rsp => {
dvMainStore.setNowPanelOuterParamsInfo(rsp.data)
})
// div
if (embeddedStore.outerParams) {
try {
attachParam = JSON.parse(embeddedStore.outerParams)
} catch (e) {
console.error(e)
ElMessage.error(t('visualization.outer_param_decode_error'))
}
}
initCanvasData( initCanvasData(
embeddedStore.dvId, embeddedStore.dvId,
embeddedStore.busiFlag, embeddedStore.busiFlag,
@ -48,6 +72,9 @@ onBeforeMount(async () => {
nextTick(() => { nextTick(() => {
dashboardPreview.value.restore() dashboardPreview.value.restore()
}) })
if (attachParam) {
dvMainStore.addOuterParamsFilter(attachParam, canvasDataResult, 'outer')
}
} }
) )
}) })

View File

@ -5,21 +5,41 @@ import { interactiveStoreWithOut } from '@/store/modules/interactive'
import { useEmbedded } from '@/store/modules/embedded' import { useEmbedded } from '@/store/modules/embedded'
import { check } from '@/utils/CrossPermission' import { check } from '@/utils/CrossPermission'
import { useCache } from '@/hooks/web/useCache' import { useCache } from '@/hooks/web/useCache'
import { getOuterParamsInfo } from '@/api/visualization/outerParams'
import { ElMessage } from 'element-plus-secondary'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { useI18n } from '@/hooks/web/useI18n'
const { wsCache } = useCache() const { wsCache } = useCache()
const interactiveStore = interactiveStoreWithOut() const interactiveStore = interactiveStoreWithOut()
const embeddedStore = useEmbedded() const embeddedStore = useEmbedded()
const config = ref() const config = ref()
const viewInfo = ref() const viewInfo = ref()
const userViewEnlargeRef = ref() const userViewEnlargeRef = ref()
const dvMainStore = dvMainStoreWithOut()
const { t } = useI18n()
const state = reactive({ const state = reactive({
canvasDataPreview: null, canvasDataPreview: null,
canvasStylePreview: null, canvasStylePreview: null,
canvasViewInfoPreview: null, canvasViewInfoPreview: null,
dvInfo: null, dvInfo: null,
curPreviewGap: 0 curPreviewGap: 0,
chartId: null
}) })
// targetSourceId ID
const winMsgHandle = event => {
console.info('PostMessage Params Received')
const msgInfo = event.data
// targetSourceId
if (msgInfo && msgInfo.type === 'attachParams' && msgInfo.targetSourceId === state.chartId + '') {
const attachParam = msgInfo.params
if (attachParam) {
dvMainStore.addOuterParamsFilter(attachParam, state.canvasDataPreview, 'outer')
}
}
}
const checkPer = async resourceId => { const checkPer = async resourceId => {
if (!window.DataEaseBi || !resourceId) { if (!window.DataEaseBi || !resourceId) {
return true return true
@ -34,6 +54,25 @@ onBeforeMount(async () => {
if (!checkResult) { if (!checkResult) {
return return
} }
state.chartId = embeddedStore.dvId
window.addEventListener('message', winMsgHandle)
//
let attachParam
await getOuterParamsInfo(embeddedStore.dvId).then(rsp => {
dvMainStore.setNowPanelOuterParamsInfo(rsp.data)
})
// div
if (embeddedStore.outerParams) {
try {
attachParam = JSON.parse(embeddedStore.outerParams)
} catch (e) {
console.error(e)
ElMessage.error(t('visualization.outer_param_decode_error'))
}
}
initCanvasDataPrepare( initCanvasDataPrepare(
embeddedStore.dvId, embeddedStore.dvId,
embeddedStore.busiFlag, embeddedStore.busiFlag,
@ -49,6 +88,9 @@ onBeforeMount(async () => {
state.canvasViewInfoPreview = canvasViewInfoPreview state.canvasViewInfoPreview = canvasViewInfoPreview
state.dvInfo = dvInfo state.dvInfo = dvInfo
state.curPreviewGap = curPreviewGap state.curPreviewGap = curPreviewGap
if (attachParam) {
dvMainStore.addOuterParamsFilter(attachParam, canvasDataResult)
}
viewInfo.value = canvasViewInfoPreview[embeddedStore.chartId] viewInfo.value = canvasViewInfoPreview[embeddedStore.chartId]
;( ;(

View File

@ -70,6 +70,7 @@ const setupAll = async (
dom: string, dom: string,
type: string, type: string,
busiFlag: string, busiFlag: string,
outerParams: string,
token: string, token: string,
baseUrl: string, baseUrl: string,
dvId: string, dvId: string,
@ -86,6 +87,7 @@ const setupAll = async (
const embeddedStore = useEmbedded() const embeddedStore = useEmbedded()
embeddedStore.setType(type) embeddedStore.setType(type)
embeddedStore.setBusiFlag(busiFlag) embeddedStore.setBusiFlag(busiFlag)
embeddedStore.setOuterParams(outerParams)
embeddedStore.setToken(token) embeddedStore.setToken(token)
embeddedStore.setBaseUrl(baseUrl) embeddedStore.setBaseUrl(baseUrl)
embeddedStore.setDvId(dvId) embeddedStore.setDvId(dvId)
@ -129,6 +131,7 @@ class DataEaseBi {
| 'DashboardPanel' | 'DashboardPanel'
dvId: string dvId: string
busiFlag: 'dashboard' | 'dataV' busiFlag: 'dashboard' | 'dataV'
outerParams: string
resourceId: string resourceId: string
pid: string pid: string
chartId: string chartId: string
@ -139,6 +142,7 @@ class DataEaseBi {
this.type = type this.type = type
this.token = options.token this.token = options.token
this.busiFlag = options.busiFlag this.busiFlag = options.busiFlag
this.outerParams = options.outerParams
this.baseUrl = options.baseUrl this.baseUrl = options.baseUrl
this.dvId = options.dvId this.dvId = options.dvId
this.pid = options.pid this.pid = options.pid
@ -152,6 +156,7 @@ class DataEaseBi {
this.deOptions.container, this.deOptions.container,
this.type, this.type,
this.busiFlag, this.busiFlag,
this.outerParams,
this.token, this.token,
this.baseUrl, this.baseUrl,
this.dvId, this.dvId,
@ -169,6 +174,7 @@ class DataEaseBi {
const embeddedStore = useEmbedded() const embeddedStore = useEmbedded()
embeddedStore.setType(null) embeddedStore.setType(null)
embeddedStore.setBusiFlag(null) embeddedStore.setBusiFlag(null)
embeddedStore.setOuterParams(null)
embeddedStore.setToken(null) embeddedStore.setToken(null)
embeddedStore.setBaseUrl(null) embeddedStore.setBaseUrl(null)
embeddedStore.setDvId(null) embeddedStore.setDvId(null)
@ -179,6 +185,7 @@ class DataEaseBi {
this.type = null this.type = null
this.token = null this.token = null
this.busiFlag = null this.busiFlag = null
this.outerParams = null
this.baseUrl = null this.baseUrl = null
this.dvId = null this.dvId = null
this.pid = null this.pid = null

View File

@ -850,10 +850,10 @@ export const dvMainStore = defineStore('dataVisualization', {
}) })
}, },
// 添加外部参数的过滤条件 // 添加外部参数的过滤条件
addOuterParamsFilter(params) { addOuterParamsFilter(params, curComponentData = this.componentData, source = 'inner') {
// params 结构 {key1:value1,key2:value2} // params 结构 {key1:value1,key2:value2}
const curComponentData = this.componentData
if (params) { if (params) {
const preActiveComponentIds = []
const trackInfo = this.nowPanelOuterParamsInfo const trackInfo = this.nowPanelOuterParamsInfo
for (let index = 0; index < curComponentData.length; index++) { for (let index = 0; index < curComponentData.length; index++) {
const element = curComponentData[index] const element = curComponentData[index]
@ -906,6 +906,7 @@ export const dvMainStore = defineStore('dataVisualization', {
// 不存在该条件 条件有效 直接保存该条件 // 不存在该条件 条件有效 直接保存该条件
// !filterExist && vValid && currentFilters.push(condition) // !filterExist && vValid && currentFilters.push(condition)
currentFilters.push(condition) currentFilters.push(condition)
preActiveComponentIds.push(element.id)
} }
if (element.component === 'VQuery') { if (element.component === 'VQuery') {
element.propValue.forEach(filterItem => { element.propValue.forEach(filterItem => {
@ -951,6 +952,11 @@ export const dvMainStore = defineStore('dataVisualization', {
curComponentData[index] = element curComponentData[index] = element
}) })
} }
if (source === 'outer') {
preActiveComponentIds.forEach(viewId => {
useEmitt().emitter.emit('query-data-' + viewId)
})
}
} }
}, },
trackFilterCursor(element, checkQDList, trackInfo, preActiveComponentIds, viewId) { trackFilterCursor(element, checkQDList, trackInfo, preActiveComponentIds, viewId) {

View File

@ -4,6 +4,7 @@ interface AppState {
type: string type: string
token: string token: string
busiFlag: string busiFlag: string
outerParams: string
baseUrl: string baseUrl: string
dvId: string dvId: string
pid: string pid: string
@ -17,6 +18,7 @@ export const userStore = defineStore('embedded', {
type: '', type: '',
token: '', token: '',
busiFlag: '', busiFlag: '',
outerParams: '',
baseUrl: '', baseUrl: '',
dvId: '', dvId: '',
pid: '', pid: '',
@ -34,6 +36,9 @@ export const userStore = defineStore('embedded', {
getBusiFlag(): string { getBusiFlag(): string {
return this.busiFlag return this.busiFlag
}, },
getOuterParams(): string {
return this.outerParams
},
getBaseUrl(): string { getBaseUrl(): string {
return this.baseUrl return this.baseUrl
}, },
@ -53,6 +58,7 @@ export const userStore = defineStore('embedded', {
return { return {
embeddedToken: this.token, embeddedToken: this.token,
busiFlag: this.busiFlag, busiFlag: this.busiFlag,
outerParams: this.outerParams,
type: this.type, type: this.type,
dvId: this.dvId, dvId: this.dvId,
chartId: this.chartId, chartId: this.chartId,
@ -71,6 +77,9 @@ export const userStore = defineStore('embedded', {
setBusiFlag(busiFlag: string) { setBusiFlag(busiFlag: string) {
this.busiFlag = busiFlag this.busiFlag = busiFlag
}, },
setOuterParams(outerParams: string) {
this.outerParams = outerParams
},
setBaseUrl(baseUrl: string) { setBaseUrl(baseUrl: string) {
this.baseUrl = baseUrl this.baseUrl = baseUrl
}, },
@ -90,6 +99,7 @@ export const userStore = defineStore('embedded', {
this.type = data['type'] this.type = data['type']
this.token = data['embeddedToken'] this.token = data['embeddedToken']
this.busiFlag = data['busiFlag'] this.busiFlag = data['busiFlag']
this.outerParams = data['outerParams']
this.dvId = data['dvId'] this.dvId = data['dvId']
this.chartId = data['chartId'] this.chartId = data['chartId']
this.pid = data['pid'] this.pid = data['pid']

View File

@ -2173,7 +2173,7 @@ const drop = (ev: MouseEvent, type = 'xAxis') => {
</div> </div>
<div <div
class="tree-btn" class="tree-btn"
:class="isFilterActive && 'active'" :class="{ 'tree-btn--dark': themes === 'dark', active: isFilterActive }"
@click="openTreeFilter" @click="openTreeFilter"
> >
<el-icon> <el-icon>
@ -3489,6 +3489,10 @@ span {
cursor: pointer; cursor: pointer;
justify-content: center; justify-content: center;
font-size: 12px; font-size: 12px;
&.tree-btn--dark {
background: rgba(235, 235, 235, 0.05);
border-color: #5f5f5f;
}
&.active { &.active {
color: #3370ff; color: #3370ff;

View File

@ -158,7 +158,8 @@ export const SENIOR_STYLE_SETTING_LIGHT = {
export const SENIOR_STYLE_SETTING_DARK = { export const SENIOR_STYLE_SETTING_DARK = {
linkageIconColor: '#ffffff', linkageIconColor: '#ffffff',
drillLayerColor: '#ffffff' drillLayerColor: '#ffffff',
pagerColor: '#ffffff'
} }
export const FILTER_COMMON_STYLE_BASE = { export const FILTER_COMMON_STYLE_BASE = {
@ -1335,6 +1336,13 @@ export const CHART_TYPE_CONFIGS = [
value: 'funnel', value: 'funnel',
title: t('chart.chart_funnel'), title: t('chart.chart_funnel'),
icon: 'funnel' icon: 'funnel'
},
{
render: 'antv',
category: 'relation',
value: 'sankey',
title: t('chart.chart_sankey'),
icon: 'sankey'
} }
] ]
}, },

View File

@ -0,0 +1,38 @@
export const SANKEY_EDITOR_PROPERTY: EditorProperty[] = [
'background-overall-component',
'basic-style-selector',
'label-selector',
'tooltip-selector',
'title-selector',
'jump-set',
'linkage'
]
export const SANKEY_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
'background-overall-component': ['all'],
'basic-style-selector': ['colors', 'alpha', 'gradient'],
'label-selector': ['fontSize', 'color', 'labelFormatter'],
'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter'],
'title-selector': [
'title',
'fontSize',
'color',
'hPosition',
'isItalic',
'isBolder',
'remarkShow',
'fontFamily',
'letterSpace',
'fontShadow'
],
'function-cfg': ['slider', 'emptyDataStrategy']
}
export const SANKEY_AXIS_TYPE: AxisType[] = [
'xAxis',
'xAxisExt',
'yAxis',
'filter',
'extLabel',
'extTooltip'
]

View File

@ -0,0 +1,280 @@
import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Sankey, SankeyOptions } from '@antv/g2plot/esm/plots/sankey'
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
import { cloneDeep, get } from 'lodash-es'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n'
import {
SANKEY_AXIS_TYPE,
SANKEY_EDITOR_PROPERTY,
SANKEY_EDITOR_PROPERTY_INNER
} from '@/views/chart/components/js/panel/charts/others/sankey-common'
const { t } = useI18n()
const DEFAULT_DATA = []
/**
* 区间条形图
*/
export class RangeBar extends G2PlotChartView<SankeyOptions, Sankey> {
axisConfig = {
...this['axisConfig'],
xAxis: {
name: `${t('chart.drag_block_type_axis_start')} / ${t('chart.dimension')}`,
limit: 1,
type: 'd'
},
xAxisExt: {
name: `${t('chart.drag_block_type_axis_end')} / ${t('chart.dimension')}`,
limit: 1,
type: 'd'
},
yAxis: {
name: `${t('chart.chart_data')} / ${t('chart.quota')}`,
limit: 1,
type: 'q'
}
}
properties = SANKEY_EDITOR_PROPERTY
propertyInner = {
...SANKEY_EDITOR_PROPERTY_INNER,
'label-selector': ['color', 'fontSize'],
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter']
}
axis: AxisType[] = [...SANKEY_AXIS_TYPE]
protected baseOptions: SankeyOptions = {
data: [],
sourceField: 'source',
targetField: 'target',
weightField: 'value',
rawFields: ['dimensionList', 'quotaList'],
interactions: [
{
type: 'legend-active',
cfg: {
start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }],
end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }]
}
},
{
type: 'legend-filter',
cfg: {
start: [
{
trigger: 'legend-item:click',
action: [
'list-unchecked:toggle',
'data-filter:filter',
'element-active:reset',
'element-highlight:reset'
]
}
]
}
},
{
type: 'tooltip',
cfg: {
start: [{ trigger: 'interval:mousemove', action: 'tooltip:show' }],
end: [{ trigger: 'interval:mouseleave', action: 'tooltip:hide' }]
}
},
{
type: 'active-region',
cfg: {
start: [{ trigger: 'interval:mousemove', action: 'active-region:show' }],
end: [{ trigger: 'interval:mouseleave', action: 'active-region:hide' }]
}
}
]
}
drawChart(drawOptions: G2PlotDrawOptions<Sankey>): Sankey {
const { chart, container, action } = drawOptions
if (!chart.data?.data?.length) {
return
}
// data
const data: Array<any> = cloneDeep(chart.data.data)
data.forEach(d => {
if (d.dimensionList) {
if (d.dimensionList[0]) {
d.source = d.dimensionList[0].value
}
if (d.dimensionList[1]) {
d.target = d.dimensionList[1].value
}
}
})
// options
const initOptions: SankeyOptions = {
...this.baseOptions,
appendPadding: getPadding(chart),
data,
nodeSort: (a, b) => {
// 这里是前端自己排序
if (chart.yAxis && chart.yAxis[0]) {
if (chart.yAxis[0].sort === 'asc') {
return a.value - b.value
} else if (chart.yAxis[0].sort === 'desc') {
return b.value - a.value
}
}
if (chart.xAxis && chart.xAxis[0] && a.sourceLinks.length > 0) {
if (chart.xAxis[0].sort === 'custom_sort' && chart.xAxis[0].customSort) {
return (
chart.xAxis[0].customSort.indexOf(a.name) - chart.xAxis[0].customSort.indexOf(b.name)
)
} else if (chart.xAxis[0].sort === 'asc') {
return a.name.localeCompare(b.name)
} else if (chart.xAxis[0].sort === 'desc') {
return b.name.localeCompare(a.name)
}
}
if (chart.xAxisExt && chart.xAxisExt[0] && a.targetLinks.length > 0) {
if (chart.xAxisExt[0].sort === 'custom_sort' && chart.xAxisExt[0].customSort) {
return (
chart.xAxisExt[0].customSort.indexOf(a.name) -
chart.xAxisExt[0].customSort.indexOf(b.name)
)
} else if (chart.xAxisExt[0].sort === 'asc') {
return a.name.localeCompare(b.name)
} else if (chart.xAxisExt[0].sort === 'desc') {
return b.name.localeCompare(a.name)
}
}
return b.value - a.value
}
}
const options = this.setupOptions(chart, initOptions)
// 开始渲染
const newChart = new Sankey(container, options)
newChart.on('edge:click', action)
return newChart
}
protected configTooltip(chart: Chart, options: SankeyOptions): SankeyOptions {
let tooltip
let customAttr: DeepPartial<ChartAttr>
if (chart.customAttr) {
customAttr = parseJson(chart.customAttr)
// tooltip
if (customAttr.tooltip) {
const t = JSON.parse(JSON.stringify(customAttr.tooltip))
if (t.show) {
tooltip = {
showTitle: false,
showMarkers: false,
shared: false,
// 内置node 不显示 tooltipedge 显示 tooltip
showContent: items => {
return !get(items, [0, 'data', 'isNode'])
},
formatter: (datum: Datum) => {
const { source, target, value } = datum
return {
name: source + ' -> ' + target,
value: valueFormatter(value, t.tooltipFormatter)
}
}
}
} else {
tooltip = false
}
}
}
return { ...options, tooltip }
}
protected configBasicStyle(chart: Chart, options: SankeyOptions): SankeyOptions {
const basicStyle = parseJson(chart.customAttr).basicStyle
let color = basicStyle.colors
color = color.map(ele => {
const tmp = hexColorToRGBA(ele, basicStyle.alpha)
if (basicStyle.gradient) {
return setGradientColor(tmp, true)
} else {
return tmp
}
})
options = {
...options,
color
}
return options
}
setupDefaultOptions(chart: ChartObj): ChartObj {
const { customAttr, senior } = chart
const { label } = customAttr
if (!['left', 'middle', 'right'].includes(label.position)) {
label.position = 'middle'
}
senior.functionCfg.emptyDataStrategy = 'ignoreData'
return chart
}
protected configLabel(chart: Chart, options: SankeyOptions): SankeyOptions {
const labelAttr = parseJson(chart.customAttr).label
if (labelAttr.show) {
const label = {
//...tmpOptions.label,
formatter: ({ name }) => name,
callback: (x: number[]) => {
const isLast = x[1] === 1 // 最后一列靠边的节点
return {
style: {
fill: labelAttr.color,
fontSize: labelAttr.fontSize,
textAlign: isLast ? 'end' : 'start'
},
offsetX: isLast ? -8 : 8
}
},
layout: [{ type: 'hide-overlap' }, { type: 'limit-in-canvas' }]
}
return {
...options,
label
}
} else {
return {
...options,
label: false
}
}
}
protected setupOptions(chart: Chart, options: SankeyOptions): SankeyOptions {
return flow(
this.configTheme,
this.configBasicStyle,
this.configLabel,
this.configTooltip,
this.configLegend,
this.configSlider,
this.configAnalyseHorizontal,
this.configEmptyDataStrategy
)(chart, options)
}
constructor(name = 'sankey') {
super(name, DEFAULT_DATA)
}
}

View File

@ -159,7 +159,6 @@ const renderG2Plot = (chart, chartView: G2PlotChartView<any, any>) => {
const dynamicAreaId = ref('') const dynamicAreaId = ref('')
const country = ref('') const country = ref('')
const appStore = useAppStoreWithOut() const appStore = useAppStoreWithOut()
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
const chartContainer = ref<HTMLElement>(null) const chartContainer = ref<HTMLElement>(null)
let mapTimer: number let mapTimer: number
const renderL7Plot = async (chart: ChartObj, chartView: L7PlotChartView<any, any>, callback) => { const renderL7Plot = async (chart: ChartObj, chartView: L7PlotChartView<any, any>, callback) => {
@ -259,7 +258,7 @@ const trackClick = trackAction => {
dvMainStore.addViewTrackFilter(linkageParam) dvMainStore.addViewTrackFilter(linkageParam)
break break
case 'jump': case 'jump':
if (isDataEaseBi.value || mobileInPc.value) return if (mobileInPc.value) return
emit('onJumpClick', jumpParam) emit('onJumpClick', jumpParam)
break break
default: default:
@ -282,11 +281,7 @@ const trackMenu = computed(() => {
jumpCount++ jumpCount++
} }
}) })
jumpCount && jumpCount && view.value?.jumpActive && !mobileInPc.value && trackMenuInfo.push('jump')
view.value?.jumpActive &&
!isDataEaseBi.value &&
!mobileInPc.value &&
trackMenuInfo.push('jump')
linkageCount && view.value?.linkageActive && trackMenuInfo.push('linkage') linkageCount && view.value?.linkageActive && trackMenuInfo.push('linkage')
view.value.drillFields.length && trackMenuInfo.push('drill') view.value.drillFields.length && trackMenuInfo.push('drill')
// jump linkage drill '' '' // jump linkage drill '' ''

View File

@ -29,7 +29,8 @@ import { useEmitt } from '@/hooks/web/useEmitt'
import { trackBarStyleCheck } from '@/utils/canvasUtils' import { trackBarStyleCheck } from '@/utils/canvasUtils'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc } = storeToRefs(dvMainStore) const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, canvasStyleData } =
storeToRefs(dvMainStore)
const { emitter } = useEmitt() const { emitter } = useEmitt()
const props = defineProps({ const props = defineProps({
@ -261,8 +262,6 @@ const action = param => {
} }
const appStore = useAppStoreWithOut() const appStore = useAppStoreWithOut()
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
const trackClick = trackAction => { const trackClick = trackAction => {
const param = state.pointParam const param = state.pointParam
if (!param?.data?.dimensionList) { if (!param?.data?.dimensionList) {
@ -295,7 +294,7 @@ const trackClick = trackAction => {
dvMainStore.addViewTrackFilter(linkageParam) dvMainStore.addViewTrackFilter(linkageParam)
break break
case 'jump': case 'jump':
if (isDataEaseBi.value || mobileInPc.value) return if (mobileInPc.value) return
emit('onJumpClick', jumpParam) emit('onJumpClick', jumpParam)
break break
default: default:
@ -319,11 +318,7 @@ const trackMenu = computed(() => {
jumpCount++ jumpCount++
} }
}) })
jumpCount && jumpCount && view.value?.jumpActive && !mobileInPc.value && trackMenuInfo.push('jump')
view.value?.jumpActive &&
!isDataEaseBi.value &&
!mobileInPc.value &&
trackMenuInfo.push('jump')
linkageCount && view.value?.linkageActive && trackMenuInfo.push('linkage') linkageCount && view.value?.linkageActive && trackMenuInfo.push('linkage')
view.value.drillFields.length && trackMenuInfo.push('drill') view.value.drillFields.length && trackMenuInfo.push('drill')
// jump linkage drill '' '' // jump linkage drill '' ''
@ -420,6 +415,10 @@ const autoHeightStyle = computed(() => {
height: 20 * scale.value + 8 + 'px' height: 20 * scale.value + 8 + 'px'
} }
}) })
const tabStyle = computed(() => [
{ '--de-pager-color': canvasStyleData.value.component.seniorStyleSetting.pagerColor }
])
</script> </script>
<template> <template>
@ -435,7 +434,7 @@ const autoHeightStyle = computed(() => {
<div style="position: relative; height: 100%" :id="containerId"></div> <div style="position: relative; height: 100%" :id="containerId"></div>
</div> </div>
<el-row :style="autoStyle" v-if="showPage && !isError"> <el-row :style="autoStyle" v-if="showPage && !isError">
<div class="table-page-info"> <div class="table-page-info" :style="tabStyle">
<div>{{ state.pageInfo.total }}</div> <div>{{ state.pageInfo.total }}</div>
<el-pagination <el-pagination
class="table-page-content" class="table-page-content"
@ -474,16 +473,16 @@ const autoHeightStyle = computed(() => {
height: 20px; height: 20px;
display: flex; display: flex;
width: 100%; width: 100%;
color: grey; color: var(--de-pager-color);
:deep(.table-page-content) { :deep(.table-page-content) {
button, button,
button[disabled] { button[disabled] {
color: grey; color: var(--de-pager-color);
background: transparent !important; background: transparent !important;
} }
ul li { ul li {
&:not(.is-active) { &:not(.is-active) {
color: grey; color: var(--de-pager-color);
} }
background: transparent !important; background: transparent !important;
} }

View File

@ -1,8 +1,10 @@
<script lang="tsx" setup> <script lang="tsx" setup>
import { reactive, watch } from 'vue' import { computed, reactive, watch } from 'vue'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { reverseColor } from '../util/util' import { reverseColor } from '../util/util'
import { ArrowRight } from '@element-plus/icons-vue' import { ArrowRight } from '@element-plus/icons-vue'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
const dvMainStore = dvMainStoreWithOut()
const { t } = useI18n() const { t } = useI18n()
@ -24,14 +26,18 @@ const state = reactive({
textColor: '#bbbfc4' textColor: '#bbbfc4'
}) })
watch( const textColor = computed(
[() => props.themeStyle?.backgroundColorSelect, () => props.themeStyle?.color], () => dvMainStore.canvasStyleData.component.seniorStyleSetting.drillLayerColor
() => {
loadThemeStyle()
},
{ deep: true }
) )
// watch(
// [() => props.themeStyle?.backgroundColorSelect, () => props.themeStyle?.color],
// () => {
// loadThemeStyle()
// },
// { deep: true }
// )
const drillJump = index => { const drillJump = index => {
if (index < props.drillFilters.length) { if (index < props.drillFilters.length) {
emit('onDrillJump', index) emit('onDrillJump', index)
@ -67,7 +73,7 @@ const loadThemeStyle = () => {
<div v-if="props.drillFilters && props.drillFilters.length > 0" class="drill"> <div v-if="props.drillFilters && props.drillFilters.length > 0" class="drill">
<el-breadcrumb :separator-icon="ArrowRight" class="drill-style"> <el-breadcrumb :separator-icon="ArrowRight" class="drill-style">
<el-breadcrumb-item class="drill-item" @click="drillJump(0)"> <el-breadcrumb-item class="drill-item" @click="drillJump(0)">
<span :style="{ color: state.textColor }">{{ t('commons.all') }}</span> <span :style="{ color: textColor }">{{ t('commons.all') }}</span>
</el-breadcrumb-item> </el-breadcrumb-item>
<el-breadcrumb-item <el-breadcrumb-item
v-for="(filter, index) in props.drillFilters" v-for="(filter, index) in props.drillFilters"
@ -75,7 +81,7 @@ const loadThemeStyle = () => {
class="drill-item" class="drill-item"
@click="drillJump(index + 1)" @click="drillJump(index + 1)"
> >
<span :style="{ color: state.textColor }">{{ filter.value[0] }}</span> <span :style="{ color: textColor }">{{ filter.value[0] }}</span>
</el-breadcrumb-item> </el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
</div> </div>

View File

@ -2,6 +2,8 @@
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import ChartComponentG2Plot from './components/ChartComponentG2Plot.vue' import ChartComponentG2Plot from './components/ChartComponentG2Plot.vue'
import DeIndicator from '@/custom-component/indicator/DeIndicator.vue' import DeIndicator from '@/custom-component/indicator/DeIndicator.vue'
import { useAppStoreWithOut } from '@/store/modules/app'
import { XpackComponent } from '@/components/plugin'
import { import {
computed, computed,
CSSProperties, CSSProperties,
@ -99,6 +101,7 @@ const props = defineProps({
}) })
const dynamicAreaId = ref('') const dynamicAreaId = ref('')
const { view, showPosition, element, active, searchCount, scale } = toRefs(props) const { view, showPosition, element, active, searchCount, scale } = toRefs(props)
const appStore = useAppStoreWithOut()
const titleShow = computed( const titleShow = computed(
() => () =>
@ -235,6 +238,7 @@ watch([() => curComponent.value], () => {
}) })
} }
}) })
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
const chartExtRequest = shallowRef(null) const chartExtRequest = shallowRef(null)
provide('chartExtRequest', chartExtRequest) provide('chartExtRequest', chartExtRequest)
@ -313,10 +317,21 @@ const filter = (firstLoad?: boolean) => {
const onDrillFilters = param => { const onDrillFilters = param => {
state.drillFilters = param ? param : [] state.drillFilters = param ? param : []
} }
const openHandler = ref(null)
const initOpenHandler = newWindow => {
if (openHandler?.value) {
const pm = {
methodName: 'initOpenHandler',
args: newWindow
}
openHandler.value.invokeMethod(pm)
}
}
const windowsJump = (url, jumpType) => { const windowsJump = (url, jumpType) => {
try { try {
window.open(url, jumpType) const newWindow = window.open(url, jumpType)
initOpenHandler(newWindow)
if (jumpType === '_self') { if (jumpType === '_self') {
location.reload() location.reload()
} }
@ -350,15 +365,19 @@ const jumpClick = param => {
param.sourceDvId = dvInfo.value.id param.sourceDvId = dvInfo.value.id
param.sourceViewId = param.viewId param.sourceViewId = param.viewId
param.sourceFieldId = dimension.id param.sourceFieldId = dimension.id
let embeddedBaseUrl = ''
if (isDataEaseBi.value) {
embeddedBaseUrl = embeddedStore.baseUrl
}
// //
if (jumpInfo.linkType === 'inner') { if (jumpInfo.linkType === 'inner') {
if (jumpInfo.targetDvId) { if (jumpInfo.targetDvId) {
if (publicLinkStatus.value) { if (publicLinkStatus.value) {
// ID // ID
if (jumpInfo.publicJumpId) { if (jumpInfo.publicJumpId) {
const url = `#/de-link/${jumpInfo.publicJumpId}?jumpInfoParam=${encodeURIComponent( const url = `${embeddedBaseUrl}#/de-link/${
Base64.encode(JSON.stringify(param)) jumpInfo.publicJumpId
)}` }?jumpInfoParam=${encodeURIComponent(Base64.encode(JSON.stringify(param)))}`
const currentUrl = window.location.href const currentUrl = window.location.href
localStorage.setItem('beforeJumpUrl', currentUrl) localStorage.setItem('beforeJumpUrl', currentUrl)
windowsJump(url, jumpInfo.jumpType) windowsJump(url, jumpInfo.jumpType)
@ -366,9 +385,9 @@ const jumpClick = param => {
ElMessage.warning(t('visualization.public_link_tips')) ElMessage.warning(t('visualization.public_link_tips'))
} }
} else { } else {
const url = `#/preview?dvId=${jumpInfo.targetDvId}&jumpInfoParam=${encodeURIComponent( const url = `${embeddedBaseUrl}#/preview?dvId=${
Base64.encode(JSON.stringify(param)) jumpInfo.targetDvId
)}` }&jumpInfoParam=${encodeURIComponent(Base64.encode(JSON.stringify(param)))}`
windowsJump(url, jumpInfo.jumpType) windowsJump(url, jumpInfo.jumpType)
} }
} else { } else {
@ -713,6 +732,10 @@ const titleIconStyle = computed(() => {
:view-icon="view.type" :view-icon="view.type"
></chart-empty-info> ></chart-empty-info>
<drill-path :drill-filters="state.drillFilters" @onDrillJump="drillJump" /> <drill-path :drill-filters="state.drillFilters" @onDrillJump="drillJump" />
<XpackComponent
ref="openHandler"
jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI="
/>
</div> </div>
</template> </template>
@ -741,11 +764,11 @@ const titleIconStyle = computed(() => {
flex-wrap: nowrap; flex-wrap: nowrap;
gap: 8px; gap: 8px;
//color: #646a73; color: #646a73;
//
//&.icons-container__dark { &.icons-container__dark {
// color: #a6a6a6; color: #a6a6a6;
//} }
&.is-editing { &.is-editing {
gap: 6px; gap: 6px;

View File

@ -10,6 +10,7 @@ import { getOuterParamsInfo } from '@/api/visualization/outerParams'
import { ElMessage } from 'element-plus-secondary' import { ElMessage } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { XpackComponent } from '@/components/plugin' import { XpackComponent } from '@/components/plugin'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { t } = useI18n() const { t } = useI18n()
const state = reactive({ const state = reactive({
@ -55,14 +56,16 @@ const loadCanvasDataAsync = async (dvId, dvType) => {
} }
// //
const attachParamsEncode = router.currentRoute.value.query.attachParams
let attachParam let attachParam
await getOuterParamsInfo(dvId).then(rsp => {
dvMainStore.setNowPanelOuterParamsInfo(rsp.data)
})
// iframe iframe
const attachParamsEncode = router.currentRoute.value.query.attachParams
if (attachParamsEncode) { if (attachParamsEncode) {
try { try {
attachParam = JSON.parse(Base64.decode(decodeURIComponent(attachParamsEncode))) attachParam = JSON.parse(Base64.decode(decodeURIComponent(attachParamsEncode)))
await getOuterParamsInfo(dvId).then(rsp => {
dvMainStore.setNowPanelOuterParamsInfo(rsp.data)
})
} catch (e) { } catch (e) {
console.error(e) console.error(e)
ElMessage.error(t('visualization.outer_param_decode_error')) ElMessage.error(t('visualization.outer_param_decode_error'))
@ -97,6 +100,7 @@ const loadCanvasDataAsync = async (dvId, dvType) => {
} }
) )
} }
let p = null let p = null
const XpackLoaded = () => p(true) const XpackLoaded = () => p(true)
onMounted(async () => { onMounted(async () => {
@ -108,6 +112,7 @@ onMounted(async () => {
} }
dvMainStore.setPublicLinkStatus(props.publicLinkStatus) dvMainStore.setPublicLinkStatus(props.publicLinkStatus)
}) })
defineExpose({ defineExpose({
loadCanvasDataAsync loadCanvasDataAsync
}) })

View File

@ -708,12 +708,13 @@ const dragenter_handler = ev => {
const drop_handler = ev => { const drop_handler = ev => {
ev.preventDefault() ev.preventDefault()
let data = ev.dataTransfer.getData('text') let data = ev.dataTransfer.getData('text')
const { tableName, type, datasourceId } = JSON.parse(data) as Table const { tableName, type, datasourceId, name: noteName } = JSON.parse(data) as Table
const extraData = { const extraData = {
info: JSON.stringify({ info: JSON.stringify({
table: tableName, table: tableName,
sql: '' sql: ''
}), }),
noteName,
unionType: 'left', unionType: 'left',
unionFields: [], unionFields: [],
currentDsFields: [], currentDsFields: [],
@ -1029,10 +1030,19 @@ const emits = defineEmits(['addComplete', 'joinEditor', 'updateAllfields', 'chan
direction="rtl" direction="rtl"
> >
<template #header v-if="currentNode"> <template #header v-if="currentNode">
<div class="info"> <div class="info-content">
<span :title="currentNode.tableName" class="name ellipsis">{{ <div class="info">
currentNode.tableName <span class="label">表名</span>
}}</span> <span :title="currentNode.tableName" class="name ellipsis">{{
currentNode.tableName
}}</span>
</div>
<div class="info">
<span class="label">表备注</span>
<span :title="currentNode.noteName" class="name ellipsis">{{
currentNode.noteName || '-'
}}</span>
</div>
<span :title="getDsName(currentNode.datasourceId)" class="ds ellipsis" <span :title="getDsName(currentNode.datasourceId)" class="ds ellipsis"
>{{ t('auth.datasource') }}:{{ getDsName(currentNode.datasourceId) }}</span >{{ t('auth.datasource') }}:{{ getDsName(currentNode.datasourceId) }}</span
> >
@ -1082,15 +1092,25 @@ const emits = defineEmits(['addComplete', 'joinEditor', 'updateAllfields', 'chan
top: 26px; top: 26px;
} }
.info-content {
display: flex;
flex-wrap: wrap;
}
.info { .info {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.name { width: 50%;
.label {
font-weight: 500; font-weight: 500;
font-size: 16px; font-size: 16px;
color: #1f2329; color: #1f2329;
max-width: 500px; max-width: 500px;
} }
.name {
font-weight: 400;
font-size: 14px;
}
.ds { .ds {
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;

View File

@ -31,6 +31,7 @@ export interface ApiItem {
fields: Field[] fields: Field[]
jsonFields: JsonField[] jsonFields: JsonField[]
useJsonPath: boolean useJsonPath: boolean
apiQueryTimeout: number
showApiStructure: boolean showApiStructure: boolean
jsonPath: string jsonPath: string
serialNumber: number serialNumber: number
@ -81,6 +82,7 @@ let apiItem = reactive<ApiItem>({
fields: [], fields: [],
jsonFields: [], jsonFields: [],
useJsonPath: false, useJsonPath: false,
apiQueryTimeout: 10,
showApiStructure: false, showApiStructure: false,
jsonPath: '', jsonPath: '',
serialNumber: -1 serialNumber: -1
@ -95,6 +97,24 @@ const loading = ref(false)
const columns = shallowRef([]) const columns = shallowRef([])
const tableData = shallowRef([]) const tableData = shallowRef([])
const apiItemBasicInfo = ref<FormInstance>() const apiItemBasicInfo = ref<FormInstance>()
const isNumber = (rule, value, callback) => {
if (!value) {
callback(new Error(t('datasource.please_input_query_timeout')))
return
}
let isNumber = false
var reg = /^\d+$/
isNumber = reg.test(value)
if (!isNumber) {
callback(new Error(t('datasource.please_input_query_timeout')))
return
}
if (value <= 0 || value > 300) {
callback(new Error(t('datasource.please_input_query_timeout')))
return
}
callback()
}
const rule = reactive<FormRules>({ const rule = reactive<FormRules>({
name: [ name: [
{ {
@ -109,6 +129,13 @@ const rule = reactive<FormRules>({
trigger: 'blur' trigger: 'blur'
} }
], ],
apiQueryTimeout: [
{
required: true,
validator: isNumber,
trigger: ['blur', 'change']
}
],
url: [ url: [
{ {
required: true, required: true,
@ -266,8 +293,8 @@ const previewData = () => {
for (let i = 0; i < apiItem.fields.length; i++) { for (let i = 0; i < apiItem.fields.length; i++) {
for (let j = 0; j < apiItem.fields[i].value.length; j++) { for (let j = 0; j < apiItem.fields[i].value.length; j++) {
data[j][apiItem.fields[i].name] = apiItem.fields[i].value[j] data[j][apiItem.fields[i].name] = apiItem.fields[i].value[j]
data[j]['id'] = apiItem.fields[i].name
} }
columnTmp.push({ columnTmp.push({
key: apiItem.fields[i].name, key: apiItem.fields[i].name,
dataKey: apiItem.fields[i].name, dataKey: apiItem.fields[i].name,
@ -429,7 +456,11 @@ defineExpose({
/> />
</el-form-item> </el-form-item>
</div> </div>
<el-form-item :label="$t('datasource.query_timeout')" prop="apiQueryTimeout">
<el-input v-model="apiItem.apiQueryTimeout" autocomplete="off" type="number" :min="0">
<template v-slot:append>{{ $t('panel.second') }}</template>
</el-input>
</el-form-item>
<div class="title-form_primary request-info"> <div class="title-form_primary request-info">
<span>{{ t('datasource.isUseJsonPath') }}</span> <span>{{ t('datasource.isUseJsonPath') }}</span>
</div> </div>

View File

@ -91,7 +91,7 @@ const { width, node } = useMoveLine('DATASOURCE')
const dsTableDetail = reactive({ const dsTableDetail = reactive({
tableName: '', tableName: '',
remark: '' name: ''
}) })
const rootManage = ref(false) const rootManage = ref(false)
const nickName = ref('') const nickName = ref('')
@ -1122,14 +1122,14 @@ const getMenuList = (val: boolean) => {
</el-col> </el-col>
</el-row> </el-row>
<template v-if="!['Excel', 'API'].includes(nodeInfo.type)"> <template v-if="!['Excel', 'API'].includes(nodeInfo.type)">
<el-row :gutter="24" v-show="nodeInfo.configuration.urlType === 'hostName'"> <el-row :gutter="24" v-show="nodeInfo.configuration.urlType !== 'jdbcUrl'">
<el-col :span="12"> <el-col :span="12">
<BaseInfoItem :label="t('datasource.host')">{{ <BaseInfoItem :label="t('datasource.host')">{{
nodeInfo.configuration.host nodeInfo.configuration.host
}}</BaseInfoItem> }}</BaseInfoItem>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="24" v-show="nodeInfo.configuration.urlType === 'hostName'"> <el-row :gutter="24" v-show="nodeInfo.configuration.urlType !== 'jdbcUrl'">
<el-col :span="12"> <el-col :span="12">
<BaseInfoItem :label="t('datasource.port')">{{ <BaseInfoItem :label="t('datasource.port')">{{
nodeInfo.configuration.port nodeInfo.configuration.port
@ -1141,7 +1141,7 @@ const getMenuList = (val: boolean) => {
}}</BaseInfoItem> }}</BaseInfoItem>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="24" v-show="nodeInfo.configuration.urlType === 'hostName'"> <el-row :gutter="24" v-show="nodeInfo.configuration.urlType !== 'jdbcUrl'">
<el-col :span="12"> <el-col :span="12">
<BaseInfoItem :label="t('datasource.user_name')">{{ <BaseInfoItem :label="t('datasource.user_name')">{{
nodeInfo.configuration.username nodeInfo.configuration.username
@ -1153,14 +1153,14 @@ const getMenuList = (val: boolean) => {
}}</BaseInfoItem> }}</BaseInfoItem>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="24" v-show="nodeInfo.configuration.urlType !== 'hostName'"> <el-row :gutter="24" v-show="nodeInfo.configuration.urlType === 'jdbcUrl'">
<el-col :span="12"> <el-col :span="12">
<BaseInfoItem :label="t('datasource.jdbcUrl')">{{ <BaseInfoItem :label="t('datasource.jdbcUrl')">{{
nodeInfo.configuration.jdbcUrl nodeInfo.configuration.jdbcUrl
}}</BaseInfoItem> }}</BaseInfoItem>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="24" v-show="nodeInfo.configuration.urlType !== 'hostName'"> <el-row :gutter="24" v-show="nodeInfo.configuration.urlType === 'jdbcUrl'">
<el-col :span="12"> <el-col :span="12">
<BaseInfoItem :label="t('datasource.user_name')">{{ <BaseInfoItem :label="t('datasource.user_name')">{{
nodeInfo.configuration.username nodeInfo.configuration.username
@ -1356,7 +1356,7 @@ const getMenuList = (val: boolean) => {
{{ t('datasource.table_description') }} {{ t('datasource.table_description') }}
</p> </p>
<p class="table-value"> <p class="table-value">
{{ dsTableDetail.remark || '-' }} {{ dsTableDetail.name || '-' }}
</p> </p>
</el-col> </el-col>
</el-row> </el-row>

View File

@ -19,10 +19,8 @@ public class ApiDefinition {
private ApiDefinitionRequest request; private ApiDefinitionRequest request;
private String status; private String status;
private List<Map<String, Object>> data = new ArrayList<>(); private List<Map<String, Object>> data = new ArrayList<>();
private Integer apiQueryTimeout = 10;
private int previewNum = 100;
private int previewNum = 10;
private int maxPreviewNum = 10;
private int serialNumber; private int serialNumber;
private boolean useJsonPath; private boolean useJsonPath;
private String jsonPath; private String jsonPath;