feat: 增加数据导出中心
@ -557,17 +557,11 @@ public class ChartDataManage {
|
||||
} else if (StringUtils.containsIgnoreCase(view.getType(), "quadrant")) {
|
||||
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, transFields(allFields), crossDs, dsMap);
|
||||
yAxis.addAll(extBubble);
|
||||
if(ObjectUtils.isNotEmpty(view.getExtTooltip())){
|
||||
yAxis.addAll(new ArrayList<>(view.getExtTooltip()));
|
||||
}
|
||||
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, transFields(allFields), crossDs, dsMap);
|
||||
querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||
if (containDetailField(view) && ObjectUtils.isNotEmpty(viewFields)) {
|
||||
detailFieldList.addAll(xAxis);
|
||||
detailFieldList.addAll(viewFields);
|
||||
|
||||
Dimension2SQLObj.dimension2sqlObj(sqlMeta, detailFieldList, transFields(allFields), crossDs, dsMap);
|
||||
String originSql = SQLProvider.createQuerySQL(sqlMeta, false, needOrder, view);
|
||||
String limit = ((pageInfo.getGoPage() != null && pageInfo.getPageSize() != null) ? " LIMIT " + pageInfo.getPageSize() + " OFFSET " + (pageInfo.getGoPage() - 1) * pageInfo.getPageSize() : "");
|
||||
detailFieldSql = originSql + limit;
|
||||
}
|
||||
} else if (StringUtils.equalsIgnoreCase("bar-range", view.getType())) {
|
||||
sqlMeta.setChartType(view.getType());
|
||||
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, transFields(allFields), crossDs, dsMap);
|
||||
@ -791,7 +785,7 @@ public class ChartDataManage {
|
||||
} else if (StringUtils.containsIgnoreCase(view.getType(), "label")) {
|
||||
mapChart = ChartDataBuild.transLabelChartData(xAxis, yAxis, view, data, isDrill);
|
||||
} else if (StringUtils.containsIgnoreCase(view.getType(), "quadrant")) {
|
||||
mapChart = ChartDataBuild.transQuadrantDataAntV(xAxis, yAxis, view, data, extBubble, isDrill);
|
||||
mapChart = ChartDataBuild.transMixChartDataAntV(xAxis, yAxis, view, data, isDrill);
|
||||
} else if (StringUtils.equalsIgnoreCase(view.getType(), "bar-range")) {
|
||||
mapChart = ChartDataBuild.transBarRangeDataAntV(skipBarRange, barRangeDate, xAxisBase, xAxis, yAxis, view, data, isDrill);
|
||||
} else {
|
||||
|
@ -532,6 +532,13 @@ public class DatasetDataManage {
|
||||
boolean crossDs = false;
|
||||
Map<Long, DatasourceSchemaDTO> dsMap = null;
|
||||
|
||||
if (ObjectUtils.isNotEmpty(request.getSortId())) {
|
||||
// 如果排序字段和查询字段显示字段不一致,则加入到查询列表中
|
||||
if (!request.getSortId().equals(request.getQueryId()) && !request.getSortId().equals(request.getDisplayId())) {
|
||||
ids.add(request.getSortId());
|
||||
}
|
||||
}
|
||||
|
||||
for (Long id : ids) {
|
||||
DatasetTableFieldDTO field = datasetTableFieldManage.selectById(id);
|
||||
if (field == null) {
|
||||
|
@ -71,6 +71,9 @@ public class TemplateCenterManage {
|
||||
public String marketGet(String url, String accessKey) {
|
||||
HttpClientConfig config = new HttpClientConfig();
|
||||
config.addHeader("API-Authorization", accessKey);
|
||||
config.setConnectTimeout(5000);
|
||||
config.setSocketTimeout(10000);
|
||||
config.setConnectionRequestTimeout(5000);
|
||||
return HttpClientUtil.get(url, config);
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,7 @@ public class CoreVisualizationManage {
|
||||
|
||||
@XpackInteract(value = "visualizationResourceTree", before = false)
|
||||
public Long innerSave(DataVisualizationInfo visualizationInfo) {
|
||||
visualizationInfo.setVersion(3);
|
||||
return preInnerSave(visualizationInfo);
|
||||
}
|
||||
|
||||
@ -123,7 +124,6 @@ public class CoreVisualizationManage {
|
||||
visualizationInfo.setCreateTime(System.currentTimeMillis());
|
||||
visualizationInfo.setUpdateTime(System.currentTimeMillis());
|
||||
visualizationInfo.setOrgId(AuthUtils.getUser().getDefaultOid());
|
||||
visualizationInfo.setVersion(3);
|
||||
mapper.insert(visualizationInfo);
|
||||
coreOptRecentManage.saveOpt(visualizationInfo.getId(), OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION, OptConstants.OPT_TYPE.NEW);
|
||||
return visualizationInfo.getId();
|
||||
|
@ -15,7 +15,7 @@ INSERT INTO `core_sys_startup_job`
|
||||
VALUES ('chartFilterMerge', 'chartFilterMerge', 'ready');
|
||||
COMMIT;
|
||||
|
||||
|
||||
TRUNCATE TABLE `xpack_setting_authentication`;
|
||||
ALTER TABLE `xpack_setting_authentication`
|
||||
ADD COLUMN `plugin_json` longtext NULL COMMENT '插件配置' AFTER `relational_ids`;
|
||||
ALTER TABLE `xpack_setting_authentication`
|
||||
@ -41,3 +41,14 @@ CREATE TABLE `core_export_task`
|
||||
`params` longtext NOT NULL COMMENT '过滤参数',
|
||||
PRIMARY KEY (`id`)
|
||||
) COMMENT='导出任务表';
|
||||
|
||||
DROP TABLE IF EXISTS `xpack_platform_token`;
|
||||
CREATE TABLE `xpack_platform_token`
|
||||
(
|
||||
`id` int NOT NULL,
|
||||
`token` varchar(255) NOT NULL,
|
||||
`create_time` bigint NOT NULL,
|
||||
`exp_time` bigint NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
"axios": "^1.3.3",
|
||||
"crypto-js": "^4.1.1",
|
||||
"dayjs": "^1.11.9",
|
||||
"element-plus-secondary": "^0.5.8",
|
||||
"element-plus-secondary": "^0.5.9",
|
||||
"element-resize-detector": "^1.2.4",
|
||||
"file-saver": "^2.0.5",
|
||||
"flv.js": "^1.6.2",
|
||||
|
11
core/core-frontend/src/assets/svg/bidirectional-bar-dark.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M41 2.00391V53.0016V54.0016H38V2.00391H41Z" fill="#434343"/>
|
||||
<path d="M4.5 50C4.22386 50 4 49.7761 4 49.5L4 42.5C4 42.2239 4.22386 42 4.5 42H35.5C35.7761 42 36 42.2239 36 42.5V49.5C36 49.7761 35.7761 50 35.5 50H4.5Z" fill="#00D6B9"/>
|
||||
<path d="M12.5 38C12.2239 38 12 37.7761 12 37.5V30.5C12 30.2239 12.2239 30 12.5 30H35.5C35.7761 30 36 30.2239 36 30.5V37.5C36 37.7761 35.7761 38 35.5 38H12.5Z" fill="#00D6B9"/>
|
||||
<path d="M43.5 14C43.2239 14 43 13.7761 43 13.5V6.5C43 6.22386 43.2239 6 43.5 6L71.5 6C71.7761 6 72 6.22386 72 6.5V13.5C72 13.7761 71.7761 14 71.5 14L43.5 14Z" fill="#3370FF"/>
|
||||
<path d="M43.5 26C43.2239 26 43 25.7761 43 25.5V18.5C43 18.2239 43.2239 18 43.5 18H62.5C62.7761 18 63 18.2239 63 18.5V25.5C63 25.7761 62.7761 26 62.5 26H43.5Z" fill="#3370FF"/>
|
||||
<path d="M43.5 38C43.2239 38 43 37.7761 43 37.5V30.5C43 30.2239 43.2239 30 43.5 30H57.5C57.7761 30 58 30.2239 58 30.5V37.5C58 37.7761 57.7761 38 57.5 38H43.5Z" fill="#3370FF"/>
|
||||
<path d="M43.5 50C43.2239 50 43 49.7761 43 49.5V42.5C43 42.2239 43.2239 42 43.5 42H75.5C75.7761 42 76 42.2239 76 42.5V49.5C76 49.7761 75.7761 50 75.5 50H43.5Z" fill="#3370FF"/>
|
||||
<path d="M16.5 26C16.2239 26 16 25.7761 16 25.5V18.5C16 18.2239 16.2239 18 16.5 18H35.5C35.7761 18 36 18.2239 36 18.5V25.5C36 25.7761 35.7761 26 35.5 26H16.5Z" fill="#00D6B9"/>
|
||||
<path d="M8.5 14C8.22386 14 8 13.7761 8 13.5V6.5C8 6.22386 8.22386 6 8.5 6L35.5 6C35.7761 6 36 6.22386 36 6.5V13.5C36 13.7761 35.7761 14 35.5 14L8.5 14Z" fill="#00D6B9"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
11
core/core-frontend/src/assets/svg/bidirectional-bar.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M41 2.00391V53.0016V54.0016H38V2.00391H41Z" fill="#DEE0E3"/>
|
||||
<path d="M4.5 50C4.22386 50 4 49.7761 4 49.5L4 42.5C4 42.2239 4.22386 42 4.5 42H35.5C35.7761 42 36 42.2239 36 42.5V49.5C36 49.7761 35.7761 50 35.5 50H4.5Z" fill="#00D6B9"/>
|
||||
<path d="M12.5 38C12.2239 38 12 37.7761 12 37.5V30.5C12 30.2239 12.2239 30 12.5 30H35.5C35.7761 30 36 30.2239 36 30.5V37.5C36 37.7761 35.7761 38 35.5 38H12.5Z" fill="#00D6B9"/>
|
||||
<path d="M43.5 14C43.2239 14 43 13.7761 43 13.5V6.5C43 6.22386 43.2239 6 43.5 6L71.5 6C71.7761 6 72 6.22386 72 6.5V13.5C72 13.7761 71.7761 14 71.5 14L43.5 14Z" fill="#3370FF"/>
|
||||
<path d="M43.5 26C43.2239 26 43 25.7761 43 25.5V18.5C43 18.2239 43.2239 18 43.5 18H62.5C62.7761 18 63 18.2239 63 18.5V25.5C63 25.7761 62.7761 26 62.5 26H43.5Z" fill="#3370FF"/>
|
||||
<path d="M43.5 38C43.2239 38 43 37.7761 43 37.5V30.5C43 30.2239 43.2239 30 43.5 30H57.5C57.7761 30 58 30.2239 58 30.5V37.5C58 37.7761 57.7761 38 57.5 38H43.5Z" fill="#3370FF"/>
|
||||
<path d="M43.5 50C43.2239 50 43 49.7761 43 49.5V42.5C43 42.2239 43.2239 42 43.5 42H75.5C75.7761 42 76 42.2239 76 42.5V49.5C76 49.7761 75.7761 50 75.5 50H43.5Z" fill="#3370FF"/>
|
||||
<path d="M16.5 26C16.2239 26 16 25.7761 16 25.5V18.5C16 18.2239 16.2239 18 16.5 18H35.5C35.7761 18 36 18.2239 36 18.5V25.5C36 25.7761 35.7761 26 35.5 26H16.5Z" fill="#00D6B9"/>
|
||||
<path d="M8.5 14C8.22386 14 8 13.7761 8 13.5V6.5C8 6.22386 8.22386 6 8.5 6L35.5 6C35.7761 6 36 6.22386 36 6.5V13.5C36 13.7761 35.7761 14 35.5 14L8.5 14Z" fill="#00D6B9"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
1
core/core-frontend/src/assets/svg/de-refresh.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716540076970" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7068" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M912 480c-17.7 0-32 14.3-32 32 0 25-2.5 50-7.5 74.2-4.8 23.6-12 46.8-21.4 69-9.2 21.8-20.6 42.8-33.9 62.5-13.2 19.5-28.3 37.8-45 54.5s-35 31.8-54.5 45c-19.7 13.3-40.7 24.7-62.5 33.9-22.2 9.4-45.4 16.6-69 21.4-48.5 9.9-99.9 9.9-148.4 0-23.6-4.8-46.8-12-69-21.4-21.8-9.2-42.8-20.6-62.5-33.9-19.5-13.2-37.8-28.3-54.5-45s-31.8-35-45-54.5c-13.3-19.7-24.7-40.7-33.9-62.5-9.4-22.2-16.6-45.4-21.4-69-5-24.2-7.5-49.2-7.5-74.2s2.5-50 7.5-74.2c4.8-23.6 12-46.8 21.4-69 9.2-21.8 20.6-42.8 33.9-62.5 13.2-19.5 28.3-37.8 45-54.5s35-31.8 54.5-45c19.7-13.3 40.7-24.7 62.5-33.9 22.2-9.4 45.4-16.6 69-21.4 48.5-9.9 99.9-9.9 148.4 0 23.6 4.8 46.8 12 69 21.4 21.8 9.2 42.8 20.6 62.5 33.9 19.5 13.2 37.8 28.3 54.5 45 1.4 1.4 2.8 2.8 4.1 4.2H688c-17.7 0-32 14.3-32 32s14.3 32 32 32h160c17.7 0 32-14.3 32-32V128c0-17.7-14.3-32-32-32s-32 14.3-32 32v77.1c-19.2-19-40.1-36.2-62.4-51.3-23.1-15.6-47.8-29-73.4-39.8-26.1-11-53.4-19.5-81.1-25.2-56.9-11.6-117.1-11.6-174.1 0-27.8 5.7-55.1 14.2-81.1 25.2-25.6 10.8-50.3 24.2-73.4 39.8-22.9 15.4-44.4 33.2-63.9 52.7s-37.3 41-52.7 63.9c-15.6 23.1-29 47.8-39.8 73.4-11 26.1-19.5 53.4-25.2 81.1C83 453.4 80 482.7 80 512s3 58.6 8.8 87c5.7 27.8 14.2 55 25.2 81.1 10.8 25.6 24.2 50.3 39.8 73.4 15.4 22.9 33.2 44.4 52.7 63.9s41 37.3 63.9 52.7c23.1 15.6 47.8 29 73.4 39.8 26.1 11 53.4 19.5 81.1 25.2 28.5 5.8 57.7 8.8 87 8.8s58.6-3 87-8.8c27.8-5.7 55-14.2 81.1-25.2 25.6-10.8 50.3-24.2 73.4-39.8 22.9-15.5 44.4-33.2 63.9-52.7s37.3-41 52.7-63.9c15.6-23.1 29-47.8 39.8-73.4 11-26.1 19.5-53.4 25.2-81.1 5.8-28.5 8.8-57.7 8.8-87 0.2-17.7-14.1-32-31.8-32z" fill="#1875F0" p-id="7069"></path></svg>
|
After Width: | Height: | Size: 1.9 KiB |
1
core/core-frontend/src/assets/svg/dv-scroll-text.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716529317390" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1706" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M810.666667 128H213.333333c-46.933333 0-85.333333 38.4-85.333333 85.333333v597.333334c0 46.933333 38.4 85.333333 85.333333 85.333333h597.333334c46.933333 0 85.333333-38.4 85.333333-85.333333V213.333333c0-46.933333-38.4-85.333333-85.333333-85.333333z m0 640c0 23.466667-19.2 42.666667-42.666667 42.666667H256c-23.466667 0-42.666667-19.2-42.666667-42.666667V256c0-23.466667 19.2-42.666667 42.666667-42.666667h512c23.466667 0 42.666667 19.2 42.666667 42.666667v512z" fill="#297AFF" p-id="1707"></path><path d="M725.333333 317.866667c0-12.8-8.533333-21.333333-21.333333-21.333334H320c-12.8 0-21.333333 8.533333-21.333333 21.333334v42.666666c0 12.8 8.533333 21.333333 21.333333 21.333334h149.333333v234.666666c0 12.8 8.533333 21.333333 21.333334 21.333334h42.666666c12.8 0 21.333333-8.533333 21.333334-21.333334v-234.666666h149.333333c12.8 0 21.333333-8.533333 21.333333-21.333334v-42.666666zM714.666667 682.666667H358.4v-32c0-2.133333-4.266667-4.266667-6.4-2.133334l-40.533333 40.533334c-8.533333 8.533333-8.533333 21.333333 0 29.866666l40.533333 40.533334c2.133333 2.133333 6.4 0 6.4-2.133334V725.333333h356.266667c6.4 0 10.666667-4.266667 10.666666-10.666666v-21.333334c0-6.4-4.266667-10.666667-10.666666-10.666666z" fill="#297AFF" p-id="1708"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716538241941" class="icon" viewBox="0 0 1166 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4799" xmlns:xlink="http://www.w3.org/1999/xlink" width="227.734375" height="200"><path d="M1016.603881 149.959255A508.396905 508.396905 0 0 0 661.880392 0H47.123419a42.206376 42.206376 0 0 0-42.206376 42.206376 42.206376 42.206376 0 0 0 42.206376 42.206376h607.45527c235.764818 0 427.571694 191.806877 427.571695 427.571695S890.343507 939.577245 654.578689 939.577245s-427.571694-191.82798-427.571694-427.592798h105.51594a42.206376 42.206376 0 0 0 42.206376-42.206376 42.206376 42.206376 0 0 0-42.206376-42.206377H42.206376a42.206376 42.206376 0 0 0-42.206376 42.206377 42.206376 42.206376 0 0 0 42.206376 42.206376h100.387866a511.984447 511.984447 0 0 0 874.009639 362.046295 512.00555 512.00555 0 0 0 0-724.071487z" p-id="4800"></path><path d="M411.237827 298.166945a42.206376 42.206376 0 0 0 42.206376-42.206376 42.206376 42.206376 0 0 0-42.206376-42.206377H120.857958a42.206376 42.206376 0 0 0-42.206376 42.206377 42.206376 42.206376 0 0 0 42.206376 42.206376zM635.205962 232.388308a42.311892 42.311892 0 0 0-42.206376 42.206376v290.379868a42.311892 42.311892 0 0 0 42.206376 42.206377h228.737456a42.206376 42.206376 0 0 0 42.206377-42.206377 42.206376 42.206376 0 0 0-42.206377-42.206376h-186.657699V274.573581A42.206376 42.206376 0 0 0 635.205962 232.388308z" p-id="4801"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
69
core/core-frontend/src/assets/svg/flow-map-origin.svg
Normal file
After Width: | Height: | Size: 739 KiB |
79
core/core-frontend/src/assets/svg/flow-map.svg
Normal file
After Width: | Height: | Size: 742 KiB |
11
core/core-frontend/src/assets/svg/progress-bar-dark.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2.00391V53.0016V54.0016H4V2.00391H7Z" fill="#434343"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L71.5 6C71.7761 6 72 6.22386 72 6.5V13.5C72 13.7761 71.7761 14 71.5 14L9.5 14Z" fill="#434343"/>
|
||||
<path d="M9.5 26C9.22386 26 9 25.7761 9 25.5V18.5C9 18.2239 9.22386 18 9.5 18H71.5C71.7761 18 72 18.2239 72 18.5V25.5C72 25.7761 71.7761 26 71.5 26L9.5 26Z" fill="#434343"/>
|
||||
<path d="M9.5 38C9.22386 38 9 37.7761 9 37.5V30.5C9 30.2239 9.22386 30 9.5 30H71.5C71.7761 30 72 30.2239 72 30.5V37.5C72 37.7761 71.7761 38 71.5 38H9.5Z" fill="#434343"/>
|
||||
<path d="M9.5 50C9.22386 50 9 49.7761 9 49.5V42.5C9 42.2239 9.22386 42 9.5 42H71.5C71.7761 42 72 42.2239 72 42.5V49.5C72 49.7761 71.7761 50 71.5 50H9.5Z" fill="#434343"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L59.5 6C59.7761 6 60 6.22386 60 6.5V13.5C60 13.7761 59.7761 14 59.5 14L9.5 14Z" fill="#3370FF"/>
|
||||
<path d="M9.5 26C9.22386 26 9 25.7761 9 25.5V18.5C9 18.2239 9.22386 18 9.5 18H46.5C46.7761 18 47 18.2239 47 18.5V25.5C47 25.7761 46.7761 26 46.5 26H9.5Z" fill="#3370FF"/>
|
||||
<path d="M9.5 38C9.22386 38 9 37.7761 9 37.5V30.5C9 30.2239 9.22386 30 9.5 30H37.5C37.7761 30 38 30.2239 38 30.5V37.5C38 37.7761 37.7761 38 37.5 38H9.5Z" fill="#3370FF"/>
|
||||
<path d="M9.5 50C9.22386 50 9 49.7761 9 49.5V42.5C9 42.2239 9.22386 42 9.5 42H21.5C21.7761 42 22 42.2239 22 42.5V49.5C22 49.7761 21.7761 50 21.5 50H9.5Z" fill="#3370FF"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
11
core/core-frontend/src/assets/svg/progress-bar.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2.00391V53.0016V54.0016H4V2.00391H7Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L71.5 6C71.7761 6 72 6.22386 72 6.5V13.5C72 13.7761 71.7761 14 71.5 14L9.5 14Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 26C9.22386 26 9 25.7761 9 25.5V18.5C9 18.2239 9.22386 18 9.5 18H71.5C71.7761 18 72 18.2239 72 18.5V25.5C72 25.7761 71.7761 26 71.5 26L9.5 26Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 38C9.22386 38 9 37.7761 9 37.5V30.5C9 30.2239 9.22386 30 9.5 30H71.5C71.7761 30 72 30.2239 72 30.5V37.5C72 37.7761 71.7761 38 71.5 38H9.5Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 50C9.22386 50 9 49.7761 9 49.5V42.5C9 42.2239 9.22386 42 9.5 42H71.5C71.7761 42 72 42.2239 72 42.5V49.5C72 49.7761 71.7761 50 71.5 50H9.5Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L59.5 6C59.7761 6 60 6.22386 60 6.5V13.5C60 13.7761 59.7761 14 59.5 14L9.5 14Z" fill="#3370FF"/>
|
||||
<path d="M9.5 26C9.22386 26 9 25.7761 9 25.5V18.5C9 18.2239 9.22386 18 9.5 18H46.5C46.7761 18 47 18.2239 47 18.5V25.5C47 25.7761 46.7761 26 46.5 26H9.5Z" fill="#3370FF"/>
|
||||
<path d="M9.5 38C9.22386 38 9 37.7761 9 37.5V30.5C9 30.2239 9.22386 30 9.5 30H37.5C37.7761 30 38 30.2239 38 30.5V37.5C38 37.7761 37.7761 38 37.5 38H9.5Z" fill="#3370FF"/>
|
||||
<path d="M9.5 50C9.22386 50 9 49.7761 9 49.5V42.5C9 42.2239 9.22386 42 9.5 42H21.5C21.7761 42 22 42.2239 22 42.5V49.5C22 49.7761 21.7761 50 21.5 50H9.5Z" fill="#3370FF"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
1
core/core-frontend/src/assets/svg/scroll-text.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716529317390" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1706" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M810.666667 128H213.333333c-46.933333 0-85.333333 38.4-85.333333 85.333333v597.333334c0 46.933333 38.4 85.333333 85.333333 85.333333h597.333334c46.933333 0 85.333333-38.4 85.333333-85.333333V213.333333c0-46.933333-38.4-85.333333-85.333333-85.333333z m0 640c0 23.466667-19.2 42.666667-42.666667 42.666667H256c-23.466667 0-42.666667-19.2-42.666667-42.666667V256c0-23.466667 19.2-42.666667 42.666667-42.666667h512c23.466667 0 42.666667 19.2 42.666667 42.666667v512z" p-id="1707"></path><path d="M725.333333 317.866667c0-12.8-8.533333-21.333333-21.333333-21.333334H320c-12.8 0-21.333333 8.533333-21.333333 21.333334v42.666666c0 12.8 8.533333 21.333333 21.333333 21.333334h149.333333v234.666666c0 12.8 8.533333 21.333333 21.333334 21.333334h42.666666c12.8 0 21.333333-8.533333 21.333334-21.333334v-234.666666h149.333333c12.8 0 21.333333-8.533333 21.333333-21.333334v-42.666666zM714.666667 682.666667H358.4v-32c0-2.133333-4.266667-4.266667-6.4-2.133334l-40.533333 40.533334c-8.533333 8.533333-8.533333 21.333333 0 29.866666l40.533333 40.533334c2.133333 2.133333 6.4 0 6.4-2.133334V725.333333h356.266667c6.4 0 10.666667-4.266667 10.666666-10.666666v-21.333334c0-6.4-4.266667-10.666667-10.666666-10.666666z" p-id="1708"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -219,7 +219,7 @@ const openDataBoardSetting = () => {
|
||||
}
|
||||
|
||||
const openMobileSetting = () => {
|
||||
if (!dvInfo.value.id) {
|
||||
if (!dvInfo.value.id || dvInfo.value.dataState === 'prepare') {
|
||||
ElMessage.warning('请先保存当前页面')
|
||||
return
|
||||
}
|
||||
|
@ -91,7 +91,7 @@
|
||||
<el-tooltip class="item" :effect="toolTip" placement="bottom">
|
||||
<template #content>
|
||||
<div>
|
||||
{{ t('visualization.panel_view_result_tips') }}
|
||||
{{ t('visualization.panel_view_result_tips', [resourceType]) }}
|
||||
</div>
|
||||
</template>
|
||||
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
|
||||
|
@ -227,7 +227,7 @@ eventBus.on('clearCanvas', clearCanvas)
|
||||
>
|
||||
<query-group :dv-model="dvModel"></query-group>
|
||||
</component-group>
|
||||
<component-group is-label :base-width="115" icon-name="dv-text" title="文本">
|
||||
<component-group is-label :base-width="215" icon-name="dv-text" title="文本">
|
||||
<text-group></text-group>
|
||||
</component-group>
|
||||
<component-group
|
||||
@ -239,7 +239,7 @@ eventBus.on('clearCanvas', clearCanvas)
|
||||
>
|
||||
<media-group></media-group>
|
||||
</component-group>
|
||||
<component-group is-label :base-width="115" icon-name="dv-more-com" title="更多">
|
||||
<component-group is-label :base-width="215" icon-name="dv-more-com" title="更多">
|
||||
<more-com-group></more-com-group>
|
||||
</component-group>
|
||||
<component-group is-label :base-width="410" icon-name="dv-material" title="素材">
|
||||
|
@ -1450,7 +1450,7 @@ defineExpose({
|
||||
></canvas-opt-bar>
|
||||
<!-- 网格线 -->
|
||||
<drag-shadow
|
||||
v-if="infoBox && infoBox.moveItem"
|
||||
v-if="infoBox && infoBox.moveItem && editMode !== 'preview'"
|
||||
:base-height="baseHeight"
|
||||
:base-width="baseWidth"
|
||||
:cur-gap="curGap"
|
||||
|
@ -294,7 +294,7 @@ const active = computed(() => {
|
||||
})
|
||||
|
||||
const boardMoveActive = computed(() => {
|
||||
const CHARTS = ['map', 'bubble-map', 'table-info', 'table-normal', 'table-pivot']
|
||||
const CHARTS = ['flow-map', 'map', 'bubble-map', 'table-info', 'table-normal', 'table-pivot']
|
||||
return CHARTS.includes(element.value.innerType)
|
||||
})
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
trigger="click"
|
||||
>
|
||||
<div class="export-button">
|
||||
<el-select v-model="pixel" class="pixel-select" size="small">
|
||||
<el-select v-if="optType === 'enlarge'" v-model="pixel" class="pixel-select" size="small">
|
||||
<el-option-group v-for="group in pixelOptions" :key="group.label" :label="group.label">
|
||||
<el-option
|
||||
v-for="item in group.options"
|
||||
@ -95,6 +95,7 @@ const optType = ref(null)
|
||||
const chartComponentDetails = ref(null)
|
||||
const { dvInfo } = storeToRefs(dvMainStore)
|
||||
const exportLoading = ref(false)
|
||||
const sourceViewType = ref()
|
||||
const DETAIL_TABLE_ATTR: DeepPartial<ChartObj> = {
|
||||
render: 'antv',
|
||||
type: 'table-info',
|
||||
@ -165,6 +166,7 @@ const pixelOptions = [
|
||||
}
|
||||
]
|
||||
const dialogInit = (canvasStyle, view, item, opt) => {
|
||||
sourceViewType.value = view.type
|
||||
optType.value = opt
|
||||
dialogShow.value = true
|
||||
viewInfo.value = deepCopy(view) as DeepPartial<ChartObj>
|
||||
@ -193,7 +195,12 @@ const downloadViewImage = () => {
|
||||
const downloadViewDetails = () => {
|
||||
const viewDataInfo = dvMainStore.getViewDataDetails(viewInfo.value.id)
|
||||
const chartExtRequest = dvMainStore.getLastViewRequestInfo(viewInfo.value.id)
|
||||
const chart = { ...viewInfo.value, chartExtRequest, data: viewDataInfo }
|
||||
const chart = {
|
||||
...viewInfo.value,
|
||||
chartExtRequest,
|
||||
data: viewDataInfo,
|
||||
type: sourceViewType.value
|
||||
}
|
||||
exportLoading.value = true
|
||||
exportExcelDownload(chart, () => {
|
||||
console.log('aa')
|
||||
|
@ -84,7 +84,7 @@
|
||||
@change="changeStyle"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<el-icon :class="{ 'dark-icon': themes === 'dark' }">
|
||||
<Icon :name="styleOptionKey.icon" />
|
||||
</el-icon>
|
||||
</template>
|
||||
@ -266,12 +266,28 @@ const styleMounted = ref({
|
||||
opacity: 1,
|
||||
fontSize: 22,
|
||||
activeFontSize: 22,
|
||||
letterSpacing: 0,
|
||||
scrollSpeed: 0,
|
||||
fontWeight: 'normal',
|
||||
fontStyle: 'normal',
|
||||
textAlign: 'center',
|
||||
color: '#000000'
|
||||
})
|
||||
|
||||
const scrollSpeedList = [
|
||||
{ name: '停止', value: 0 },
|
||||
{ name: '1', value: 20 },
|
||||
{ name: '2', value: 18 },
|
||||
{ name: '3', value: 16 },
|
||||
{ name: '4', value: 14 },
|
||||
{ name: '5', value: 12 },
|
||||
{ name: '6', value: 10 },
|
||||
{ name: '7', value: 8 },
|
||||
{ name: '8', value: 6 },
|
||||
{ name: '9', value: 4 },
|
||||
{ name: '10', value: 2 }
|
||||
]
|
||||
|
||||
const opacitySizeList = [
|
||||
{ name: '0.1', value: 0.1 },
|
||||
{ name: '0.2', value: 0.2 },
|
||||
@ -310,6 +326,17 @@ const styleColorKeyArray = [
|
||||
{ value: 'backgroundColor', label: '背景色', width: 90, icon: 'dv-style-backgroundColor' }
|
||||
]
|
||||
|
||||
const letterSpacingList = computed(() => {
|
||||
const arr = []
|
||||
for (let i = 0; i <= 60; i = i + 1) {
|
||||
arr.push({
|
||||
name: i + '',
|
||||
value: i
|
||||
})
|
||||
}
|
||||
return arr
|
||||
})
|
||||
|
||||
const fontSizeList = computed(() => {
|
||||
const arr = []
|
||||
for (let i = 10; i <= 60; i = i + 1) {
|
||||
@ -351,6 +378,13 @@ const borderStyleList = [
|
||||
|
||||
//大小随画布缩放动态变化
|
||||
const styleOptionMountedKeyArray = [
|
||||
{
|
||||
value: 'letterSpacing',
|
||||
label: '字间距',
|
||||
customOption: letterSpacingList.value,
|
||||
width: '90px',
|
||||
icon: 'dv-style-letterSpacing'
|
||||
},
|
||||
{
|
||||
value: 'fontSize',
|
||||
label: '字体大小',
|
||||
@ -369,6 +403,13 @@ const styleOptionMountedKeyArray = [
|
||||
|
||||
//大小不变
|
||||
const styleOptionKeyArray = [
|
||||
{
|
||||
value: 'scrollSpeed',
|
||||
label: '滚动速度',
|
||||
customOption: scrollSpeedList,
|
||||
width: '90px',
|
||||
icon: 'dv-style-scroll-speed'
|
||||
},
|
||||
{
|
||||
value: 'opacity',
|
||||
label: '不透明度',
|
||||
|
@ -28,8 +28,8 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const { dvModel } = toRefs(props)
|
||||
const newComponent = () => {
|
||||
eventBus.emit('handleNew', { componentName: 'DeTimeClock', innerType: 'DeTimeClock' })
|
||||
const newComponent = params => {
|
||||
eventBus.emit('handleNew', { componentName: params, innerType: params })
|
||||
}
|
||||
|
||||
const handleDragStart = e => {
|
||||
@ -42,17 +42,20 @@ const handleDragEnd = e => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="group"
|
||||
@dragstart="handleDragStart"
|
||||
@dragend="handleDragEnd"
|
||||
v-on:click="newComponent"
|
||||
>
|
||||
<div class="group" @dragstart="handleDragStart" @dragend="handleDragEnd">
|
||||
<drag-component
|
||||
:themes="themes"
|
||||
name="YYYY-MM-DD 08:00:00"
|
||||
label="日期时间"
|
||||
drag-info="DeTimeClock&DeTimeClock"
|
||||
v-on:click="newComponent('DeTimeClock')"
|
||||
></drag-component>
|
||||
<drag-component
|
||||
:themes="themes"
|
||||
icon="db-more-web"
|
||||
label="网页"
|
||||
drag-info="DeFrame&DeFrame"
|
||||
v-on:click="newComponent('DeFrame')"
|
||||
></drag-component>
|
||||
</div>
|
||||
</template>
|
||||
@ -60,5 +63,6 @@ const handleDragEnd = e => {
|
||||
<style lang="less" scoped>
|
||||
.group {
|
||||
padding: 12px 8px;
|
||||
display: inline-flex;
|
||||
}
|
||||
</style>
|
||||
|
@ -11,7 +11,7 @@ const props = defineProps({
|
||||
},
|
||||
dvModel: {
|
||||
type: String,
|
||||
default: 'dv'
|
||||
default: 'dataV'
|
||||
},
|
||||
element: {
|
||||
type: Object,
|
||||
@ -37,23 +37,27 @@ const handleDragEnd = e => {
|
||||
commonHandleDragEnd(e, dvModel.value)
|
||||
}
|
||||
|
||||
const newComponent = () => {
|
||||
eventBus.emit('handleNew', { componentName: 'UserView', innerType: 'rich-text' })
|
||||
const newComponent = (componentName, innerType) => {
|
||||
eventBus.emit('handleNew', { componentName: componentName, innerType: innerType })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="group"
|
||||
@dragstart="handleDragStart"
|
||||
@dragend="handleDragEnd"
|
||||
v-on:click="newComponent"
|
||||
>
|
||||
<div class="group" @dragstart="handleDragStart" @dragend="handleDragEnd">
|
||||
<drag-component
|
||||
:themes="themes"
|
||||
icon="dv-richText"
|
||||
label="富文本"
|
||||
drag-info="UserView&rich-text"
|
||||
v-on:click="newComponent('UserView', 'rich-text')"
|
||||
></drag-component>
|
||||
<drag-component
|
||||
v-if="dvModel === 'dataV'"
|
||||
:themes="themes"
|
||||
icon="dv-scroll-text"
|
||||
label="跑马灯"
|
||||
drag-info="ScrollText&ScrollText"
|
||||
v-on:click="newComponent('ScrollText', 'ScrollText')"
|
||||
></drag-component>
|
||||
</div>
|
||||
</template>
|
||||
@ -61,10 +65,6 @@ const newComponent = () => {
|
||||
<style lang="less" scoped>
|
||||
.group {
|
||||
padding: 12px 8px;
|
||||
}
|
||||
.custom_img {
|
||||
width: 100px;
|
||||
height: 70px;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
}
|
||||
</style>
|
||||
|
@ -253,8 +253,8 @@ const list = [
|
||||
},
|
||||
{
|
||||
component: 'DeVideo',
|
||||
name: '媒体',
|
||||
label: '媒体',
|
||||
name: '视频',
|
||||
label: '视频',
|
||||
innerType: 'DeVideo',
|
||||
editing: false,
|
||||
canvasActive: false,
|
||||
@ -272,8 +272,8 @@ const list = [
|
||||
},
|
||||
{
|
||||
component: 'DeStreamMedia',
|
||||
name: '媒体',
|
||||
label: '媒体',
|
||||
name: '流媒体',
|
||||
label: '流媒体',
|
||||
innerType: 'DeStreamMedia',
|
||||
editing: false,
|
||||
canvasActive: false,
|
||||
@ -386,7 +386,7 @@ const list = [
|
||||
},
|
||||
{
|
||||
component: 'CanvasBoard',
|
||||
name: '图形',
|
||||
name: '边框',
|
||||
label: '边框',
|
||||
propValue: '',
|
||||
icon: 'other_material_board',
|
||||
@ -477,6 +477,29 @@ const list = [
|
||||
headFontColor: '#000000',
|
||||
headFontActiveColor: '#000000'
|
||||
}
|
||||
},
|
||||
{
|
||||
component: 'ScrollText',
|
||||
name: '跑马灯',
|
||||
label: '跑马灯',
|
||||
propValue: '双击编辑文字',
|
||||
innerType: 'ScrollText',
|
||||
icon: 'scroll-text',
|
||||
x: 1,
|
||||
y: 1,
|
||||
sizeX: 36,
|
||||
sizeY: 14,
|
||||
style: {
|
||||
width: 400,
|
||||
height: 80,
|
||||
fontSize: 14,
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
color: '',
|
||||
padding: 4,
|
||||
verticalAlign: 'middle',
|
||||
scrollSpeed: 0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<el-input v-model="state.linkInfoTemp.src" @blur="onBlur" />
|
||||
<el-input :effect="themes" v-model="state.linkInfoTemp.src" @blur="onBlur" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
|
@ -93,9 +93,10 @@ const result = computed(() => {
|
||||
const indicatorColor = ref(DEFAULT_INDICATOR_STYLE.color)
|
||||
|
||||
const thresholdColor = computed(() => {
|
||||
let color = indicatorColor.value
|
||||
let color: string = indicatorColor.value
|
||||
let backgroundColor: string = DEFAULT_INDICATOR_STYLE.backgroundColor
|
||||
if (result.value === '-') {
|
||||
return color
|
||||
return { color, backgroundColor }
|
||||
}
|
||||
const value = result.value
|
||||
if (
|
||||
@ -107,42 +108,47 @@ const thresholdColor = computed(() => {
|
||||
for (let i = 0; i < senior.threshold.labelThreshold.length; i++) {
|
||||
let flag = false
|
||||
const t = senior.threshold.labelThreshold[i]
|
||||
const tv = parseFloat(t.value)
|
||||
const tv = t.value
|
||||
if (t.term === 'eq') {
|
||||
if (value === tv) {
|
||||
color = t.color
|
||||
backgroundColor = t.backgroundColor
|
||||
flag = true
|
||||
}
|
||||
} else if (t.term === 'not_eq') {
|
||||
if (value !== tv) {
|
||||
color = t.color
|
||||
backgroundColor = t.backgroundColor
|
||||
flag = true
|
||||
}
|
||||
} else if (t.term === 'lt') {
|
||||
if (value < tv) {
|
||||
color = t.color
|
||||
backgroundColor = t.backgroundColor
|
||||
flag = true
|
||||
}
|
||||
} else if (t.term === 'gt') {
|
||||
if (value > tv) {
|
||||
color = t.color
|
||||
backgroundColor = t.backgroundColor
|
||||
flag = true
|
||||
}
|
||||
} else if (t.term === 'le') {
|
||||
if (value <= tv) {
|
||||
color = t.color
|
||||
backgroundColor = t.backgroundColor
|
||||
flag = true
|
||||
}
|
||||
} else if (t.term === 'ge') {
|
||||
if (value >= tv) {
|
||||
color = t.color
|
||||
backgroundColor = t.backgroundColor
|
||||
flag = true
|
||||
}
|
||||
} else if (t.term === 'between') {
|
||||
const min = parseFloat(t.min)
|
||||
const max = parseFloat(t.max)
|
||||
if (min <= value && value <= max) {
|
||||
if (t.min <= value && value <= t.max) {
|
||||
color = t.color
|
||||
backgroundColor = t.backgroundColor
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
@ -151,7 +157,7 @@ const thresholdColor = computed(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
return color
|
||||
return { color, backgroundColor }
|
||||
})
|
||||
|
||||
const formattedResult = computed(() => {
|
||||
@ -175,11 +181,12 @@ const contentStyle = ref<CSSProperties>({
|
||||
'flex-direction': 'column',
|
||||
'align-items': 'center',
|
||||
'justify-content': 'center',
|
||||
height: '100%'
|
||||
height: '100%',
|
||||
'background-color': thresholdColor.value.backgroundColor
|
||||
})
|
||||
|
||||
const indicatorClass = ref<CSSProperties>({
|
||||
color: thresholdColor.value,
|
||||
color: thresholdColor.value.color,
|
||||
'font-size': DEFAULT_INDICATOR_STYLE.fontSize + 'px',
|
||||
'font-family': defaultTo(
|
||||
CHART_FONT_FAMILY_MAP[DEFAULT_INDICATOR_STYLE.fontFamily],
|
||||
@ -280,7 +287,7 @@ const renderChart = async view => {
|
||||
}
|
||||
|
||||
indicatorClass.value = {
|
||||
color: thresholdColor.value,
|
||||
color: thresholdColor.value.color,
|
||||
'font-size': indicator.fontSize + 'px',
|
||||
'font-family': defaultTo(
|
||||
CHART_FONT_FAMILY_MAP[indicator.fontFamily],
|
||||
@ -292,6 +299,7 @@ const renderChart = async view => {
|
||||
'text-shadow': indicator.fontShadow ? '2px 2px 4px' : 'none',
|
||||
'font-synthesis': 'weight style'
|
||||
}
|
||||
contentStyle.value['background-color'] = thresholdColor.value.backgroundColor
|
||||
|
||||
indicatorSuffixClass.value = {
|
||||
color: suffixColor,
|
||||
|
56
core/core-frontend/src/custom-component/scroll-text/Attr.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import CommonAttr from '@/custom-component/common/CommonAttr.vue'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { toRefs } from 'vue'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { curComponent } = storeToRefs(dvMainStore)
|
||||
const props = defineProps({
|
||||
themes: {
|
||||
type: String,
|
||||
default: 'dark'
|
||||
}
|
||||
})
|
||||
|
||||
const { themes } = toRefs(props)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="attr-list de-collapse-style">
|
||||
<CommonAttr :themes="themes" :element="curComponent"></CommonAttr>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.content {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.de-collapse-style {
|
||||
:deep(.ed-collapse-item__header) {
|
||||
height: 34px !important;
|
||||
line-height: 34px !important;
|
||||
padding: 0 0 0 6px !important;
|
||||
font-size: 12px !important;
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
:deep(.ed-collapse-item__content) {
|
||||
padding: 16px !important;
|
||||
}
|
||||
:deep(.ed-form-item) {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
:deep(.ed-form-item__label) {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ed-textarea__inner) {
|
||||
color: #ffffff;
|
||||
background-color: #000000;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,197 @@
|
||||
<script lang="ts" setup>
|
||||
import { keycodes } from '@/utils/DeShortcutKey.js'
|
||||
import eventBus from '@/utils/eventBus'
|
||||
import { computed, nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
import { toRefs } from 'vue'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
const canEdit = ref(false)
|
||||
const ctrlKey = ref(17)
|
||||
const isCtrlDown = ref(false)
|
||||
|
||||
const emit = defineEmits(['input'])
|
||||
const text = ref(null)
|
||||
|
||||
const props = defineProps({
|
||||
propValue: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: ''
|
||||
},
|
||||
element: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
id: null,
|
||||
propValue: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { element } = toRefs(props)
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { editMode, curComponent } = storeToRefs(dvMainStore)
|
||||
|
||||
const onComponentClick = () => {
|
||||
if (curComponent.value.id !== element.value.id) {
|
||||
canEdit.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleInput = e => {
|
||||
emit('input', element.value, e.target.innerHTML)
|
||||
}
|
||||
|
||||
const handleKeydown = e => {
|
||||
// 阻止冒泡,防止触发复制、粘贴组件操作
|
||||
canEdit.value && e.stopPropagation()
|
||||
if (e.keyCode == ctrlKey.value) {
|
||||
isCtrlDown.value = true
|
||||
} else if (isCtrlDown.value && canEdit.value && keycodes.includes(e.keyCode)) {
|
||||
e.stopPropagation()
|
||||
} else if (e.keyCode == 46) {
|
||||
// deleteKey
|
||||
e.stopPropagation()
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyup = e => {
|
||||
// 阻止冒泡,防止触发复制、粘贴组件操作
|
||||
canEdit.value && e.stopPropagation()
|
||||
if (e.keyCode == ctrlKey.value) {
|
||||
isCtrlDown.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleMousedown = e => {
|
||||
if (canEdit.value) {
|
||||
e.stopPropagation()
|
||||
}
|
||||
}
|
||||
|
||||
const clearStyle = e => {
|
||||
e.preventDefault()
|
||||
const clp = e.clipboardData
|
||||
const text = clp.getData('text/plain') || ''
|
||||
if (text !== '') {
|
||||
document.execCommand('insertText', false, text)
|
||||
}
|
||||
|
||||
emit('input', element.value, e.target.innerHTML)
|
||||
}
|
||||
|
||||
const handleBlur = e => {
|
||||
element.value.propValue = e.target.innerHTML || ' '
|
||||
const html = e.target.innerHTML
|
||||
if (html !== '') {
|
||||
element.value.propValue = e.target.innerHTML
|
||||
} else {
|
||||
element.value.propValue = ''
|
||||
nextTick(function () {
|
||||
element.value.propValue = ' '
|
||||
})
|
||||
}
|
||||
canEdit.value = false
|
||||
}
|
||||
|
||||
const setEdit = () => {
|
||||
if (element.value['isLock']) return
|
||||
canEdit.value = true
|
||||
// 全选
|
||||
selectText(text.value)
|
||||
}
|
||||
const selectText = element => {
|
||||
const selection = window.getSelection()
|
||||
const range = document.createRange()
|
||||
range.selectNodeContents(element)
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
eventBus.off('componentClick', onComponentClick)
|
||||
})
|
||||
|
||||
const varStyle = computed(() => [{ '--scroll-speed': `${element.value.style.scrollSpeed}s` }])
|
||||
|
||||
const textStyle = computed(() => {
|
||||
return {
|
||||
verticalAlign: element.value['style'].verticalAlign
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="editMode == 'edit'"
|
||||
:style="varStyle"
|
||||
class="v-text"
|
||||
@keydown="handleKeydown"
|
||||
@keyup="handleKeyup"
|
||||
>
|
||||
<div
|
||||
ref="text"
|
||||
:contenteditable="canEdit"
|
||||
:class="{ 'can-edit': canEdit, 'marquee-txt': !canEdit }"
|
||||
tabindex="0"
|
||||
:style="textStyle"
|
||||
@dblclick="setEdit"
|
||||
@paste="clearStyle"
|
||||
@mousedown="handleMousedown"
|
||||
@blur="handleBlur"
|
||||
@input="handleInput"
|
||||
v-html="element['propValue']"
|
||||
></div>
|
||||
</div>
|
||||
<div v-else class="v-text preview">
|
||||
<div class="marquee-txt" :style="textStyle" v-html="element['propValue']"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.v-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: table;
|
||||
div {
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
outline: none;
|
||||
word-break: break-all;
|
||||
padding: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.can-edit {
|
||||
cursor: text;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.preview {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.marquee {
|
||||
margin-left: 100px;
|
||||
width: 300px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
border: 1px solid #4c7cee;
|
||||
}
|
||||
.marquee-txt {
|
||||
display: inline-block;
|
||||
padding-left: 100%; /* 从右至左开始滚动 */
|
||||
animation: marqueeAnimation var(--scroll-speed) linear infinite;
|
||||
}
|
||||
@keyframes marqueeAnimation {
|
||||
0% {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-100%, 0);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -108,22 +108,11 @@ const isIndeterminate = ref(false)
|
||||
const datasetTree = shallowRef([])
|
||||
const fields = ref<DatasetDetail[]>()
|
||||
const parameters = ref([])
|
||||
const parametersFilter = computed(() => {
|
||||
return parameters.value.filter(ele => {
|
||||
if (curComponent.value.displayType === '2') {
|
||||
return [2, 3].includes(ele.deType)
|
||||
}
|
||||
|
||||
if (curComponent.value.displayType === '7') {
|
||||
return [1, 7].includes(ele.deType)
|
||||
}
|
||||
return ele.deType === +curComponent.value.displayType
|
||||
})
|
||||
})
|
||||
const { queryElement } = toRefs(props)
|
||||
|
||||
const getDetype = (id, arr) => {
|
||||
return arr.find(ele => ele.id === id)?.deType
|
||||
return arr.flat().find(ele => ele.id === id)?.deType
|
||||
}
|
||||
const visiblePopover = ref(false)
|
||||
const handleVisiblePopover = ev => {
|
||||
@ -142,11 +131,19 @@ const showTypeError = computed(() => {
|
||||
if (!curComponent.value) return false
|
||||
if (!curComponent.value.checkedFields?.length) return false
|
||||
if (!fields.value?.length) return false
|
||||
if (!!curComponent.value.parameters.length) {
|
||||
const timeArr = curComponent.value.parameters.map(ele => ele.type[1])
|
||||
if (timeArr.length !== new Set(timeArr).size) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
let displayTypeField = null
|
||||
return curComponent.value.checkedFields.some(id => {
|
||||
const arr = fields.value.find(ele => ele.componentId === id)
|
||||
const checkId = curComponent.value.checkedFieldsMap?.[id]
|
||||
const field = (arr?.list || []).find(ele => checkId === ele.id)
|
||||
const field = Object.values(arr?.fields || {})
|
||||
.flat()
|
||||
.find(ele => checkId === ele.id)
|
||||
if (!field) return false
|
||||
if (displayTypeField === null) {
|
||||
displayTypeField = field?.deType
|
||||
@ -181,12 +178,32 @@ const handleCheckedFieldsChange = (value: string[]) => {
|
||||
|
||||
const inputCom = ref()
|
||||
|
||||
const setParameters = () => {
|
||||
const fieldArr = Object.values(curComponent.value.checkedFieldsMap).filter(ele => !!ele)
|
||||
curComponent.value.parameters = fields.value
|
||||
.map(ele => Object.values(ele?.fields || {}).flat())
|
||||
.flat()
|
||||
.filter(ele => fieldArr.includes(ele.id) && !!ele.variableName)
|
||||
nextTick(() => {
|
||||
if (isTimeParameter.value) {
|
||||
curComponent.value.timeGranularity = typeTimeMap[curComponent.value.parameters[0].type[1]]
|
||||
}
|
||||
|
||||
if (!!curComponent.value.parameters.length) {
|
||||
curComponent.value.conditionType = 0
|
||||
}
|
||||
})
|
||||
setType()
|
||||
}
|
||||
|
||||
const setType = () => {
|
||||
if (curComponent.value.checkedFields?.length) {
|
||||
const [id] = curComponent.value.checkedFields
|
||||
const arr = fields.value.find(ele => ele.componentId === id)
|
||||
const checkId = curComponent.value.checkedFieldsMap?.[id]
|
||||
const field = (arr?.list || []).find(ele => checkId === ele.id)
|
||||
const field = Object.values(arr?.fields || {})
|
||||
.flat()
|
||||
.find(ele => checkId === ele.id)
|
||||
|
||||
if (field?.deType !== undefined) {
|
||||
let displayType = curComponent.value.displayType
|
||||
@ -220,6 +237,47 @@ const setTypeChange = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const isTimeParameter = computed(() => {
|
||||
return curComponent.value.parameters?.some(ele => ele.deType === 1 && !!ele.variableName)
|
||||
})
|
||||
|
||||
const timeList = [
|
||||
{
|
||||
label: '年',
|
||||
value: 'year'
|
||||
},
|
||||
{
|
||||
label: '年月',
|
||||
value: 'month'
|
||||
},
|
||||
{
|
||||
label: '年月日',
|
||||
value: 'date'
|
||||
},
|
||||
{
|
||||
label: '年月日时分秒',
|
||||
value: 'datetime'
|
||||
}
|
||||
]
|
||||
|
||||
const typeTimeMap = {
|
||||
'DATETIME-YEAR': 'year',
|
||||
'YYYY-MM': 'month',
|
||||
'YYYY/MM': 'month',
|
||||
'YYYY-MM-DD': 'date',
|
||||
'YYYY/MM/DD': 'date',
|
||||
'YYYY-MM-DD HH:mm:ss': 'datetime',
|
||||
'YYYY/MM/DD HH:mm:ss': 'datetime'
|
||||
}
|
||||
|
||||
const timeParameterList = computed(() => {
|
||||
if (!isTimeParameter.value) return timeList
|
||||
const [_, y] = curComponent.value.parameters?.filter(
|
||||
ele => ele.deType === 1 && !!ele.variableName
|
||||
)[0].type
|
||||
return timeList.filter(ele => ele.value === typeTimeMap[y])
|
||||
})
|
||||
|
||||
const cancelClick = () => {
|
||||
visiblePopover.value = false
|
||||
dialogVisible.value = false
|
||||
@ -542,7 +600,9 @@ const validate = () => {
|
||||
ele.checkedFields.some(id => {
|
||||
const arr = fields.value.find(itx => itx.componentId === id)
|
||||
const checkId = ele.checkedFieldsMap?.[id]
|
||||
const field = (arr?.list || []).find(itx => checkId === itx.id)
|
||||
const field = Object.values(arr?.fields || {})
|
||||
.flat()
|
||||
.find(itx => checkId === itx.id)
|
||||
if (!field) return false
|
||||
if (displayTypeField === null) {
|
||||
displayTypeField = field?.deType
|
||||
@ -642,14 +702,6 @@ const init = (queryId: string) => {
|
||||
|
||||
const datasetMapKeyList = Object.keys(datasetMap)
|
||||
|
||||
nextTick(() => {
|
||||
getSqlParams([
|
||||
...new Set(datasetFieldList.value.map(ele => ele.tableId).filter(ele => !!ele))
|
||||
]).then(res => {
|
||||
parameters.value = res || []
|
||||
})
|
||||
})
|
||||
|
||||
if (datasetFieldIdList.every(ele => datasetMapKeyList.includes(ele))) {
|
||||
fields.value = datasetFieldList.value
|
||||
.map(ele => {
|
||||
@ -660,15 +712,14 @@ const init = (queryId: string) => {
|
||||
}
|
||||
const params = [...new Set(datasetFieldList.value.map(ele => ele.tableId).filter(ele => !!ele))]
|
||||
if (!params.length) return
|
||||
getDsDetailsWithPerm(params)
|
||||
.then(res => {
|
||||
res
|
||||
.filter(ele => !!ele)
|
||||
.forEach(ele => {
|
||||
const { dimensionList, quotaList } = ele.fields
|
||||
ele.list = [...dimensionList, ...quotaList]
|
||||
datasetMap[ele.id] = ele
|
||||
})
|
||||
Promise.all([getDsDetailsWithPerm(params), getSqlParams(params)])
|
||||
.then(([dq, p]) => {
|
||||
dq.filter(ele => !!ele).forEach(ele => {
|
||||
ele.activelist = 'dimensionList'
|
||||
ele.fields.parameterList = p.filter(itx => itx.datasetGroupId === ele.id)
|
||||
ele.hasParameter = !!ele.fields.parameterList.length
|
||||
datasetMap[ele.id] = ele
|
||||
})
|
||||
fields.value = datasetFieldList.value
|
||||
.map(ele => {
|
||||
if (!datasetMap[ele.tableId]) return null
|
||||
@ -1169,9 +1220,10 @@ defineExpose({
|
||||
>
|
||||
<span class="dataset ellipsis">{{ field.name }}</span>
|
||||
<el-select
|
||||
@change="setType"
|
||||
@change="setParameters"
|
||||
@focus="handleDialogClick"
|
||||
style="margin-left: 12px"
|
||||
popper-class="field-select--dqp"
|
||||
v-if="curComponent.checkedFields.includes(field.componentId)"
|
||||
v-model="curComponent.checkedFieldsMap[field.componentId]"
|
||||
clearable
|
||||
@ -1181,21 +1233,38 @@ defineExpose({
|
||||
<Icon
|
||||
:name="`field_${
|
||||
fieldType[
|
||||
getDetype(curComponent.checkedFieldsMap[field.componentId], field.list)
|
||||
getDetype(
|
||||
curComponent.checkedFieldsMap[field.componentId],
|
||||
Object.values(field.fields)
|
||||
)
|
||||
]
|
||||
}`"
|
||||
:className="`field-icon-${
|
||||
fieldType[
|
||||
getDetype(curComponent.checkedFieldsMap[field.componentId], field.list)
|
||||
getDetype(
|
||||
curComponent.checkedFieldsMap[field.componentId],
|
||||
Object.values(field.fields)
|
||||
)
|
||||
]
|
||||
}`"
|
||||
></Icon>
|
||||
</el-icon>
|
||||
</template>
|
||||
<template #header>
|
||||
<el-tabs stretch class="params-select--header" v-model="field.activelist">
|
||||
<el-tab-pane label="维度" name="dimensionList"></el-tab-pane>
|
||||
<el-tab-pane label="指标" name="quotaList"></el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-if="field.hasParameter"
|
||||
label="参数"
|
||||
name="parameterList"
|
||||
></el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
<el-option
|
||||
v-for="ele in field.list"
|
||||
v-for="ele in field.fields[field.activelist]"
|
||||
:key="ele.id"
|
||||
:label="ele.name"
|
||||
:label="ele.name || ele.variableName"
|
||||
:value="ele.id"
|
||||
:disabled="ele.desensitized"
|
||||
>
|
||||
@ -1209,8 +1278,8 @@ defineExpose({
|
||||
:className="`field-icon-${fieldType[ele.deType]}`"
|
||||
></Icon>
|
||||
</el-icon>
|
||||
<span>
|
||||
{{ ele.name }}
|
||||
<span :title="ele.name || ele.variableName" class="ellipsis">
|
||||
{{ ele.name || ele.variableName }}
|
||||
</span>
|
||||
</div>
|
||||
</el-option>
|
||||
@ -1276,7 +1345,7 @@ defineExpose({
|
||||
<div class="list-item" v-if="['1', '7'].includes(curComponent.displayType)">
|
||||
<div class="label">时间粒度</div>
|
||||
<div class="value">
|
||||
<template v-if="curComponent.displayType === '7'">
|
||||
<template v-if="curComponent.displayType === '7' && !isTimeParameter">
|
||||
<el-select
|
||||
@change="timeGranularityMultipleChange"
|
||||
placeholder="请选择时间粒度"
|
||||
@ -1295,10 +1364,12 @@ defineExpose({
|
||||
placeholder="请选择时间粒度"
|
||||
v-model="curComponent.timeGranularity"
|
||||
>
|
||||
<el-option label="年" value="year" />
|
||||
<el-option label="年月" value="month" />
|
||||
<el-option label="年月日" value="date" />
|
||||
<el-option label="年月日时分秒" value="datetime" />
|
||||
<el-option
|
||||
v-for="ele in timeParameterList"
|
||||
:key="ele.value"
|
||||
:label="ele.label"
|
||||
:value="ele.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</div>
|
||||
@ -1571,8 +1642,12 @@ defineExpose({
|
||||
<div class="value">
|
||||
<el-radio-group class="larger-radio" v-model="curComponent.conditionType">
|
||||
<el-radio :label="0">单条件</el-radio>
|
||||
<el-radio :label="1">与条件</el-radio>
|
||||
<el-radio :label="2">或条件</el-radio>
|
||||
<el-radio :label="1" :disabled="!!curComponent.parameters.length"
|
||||
>与条件</el-radio
|
||||
>
|
||||
<el-radio :label="2" :disabled="!!curComponent.parameters.length"
|
||||
>或条件</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
@ -1698,95 +1773,6 @@ defineExpose({
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!['8'].includes(curComponent.displayType)" class="list-item">
|
||||
<div class="label">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="空数据不支持传参数"
|
||||
:disabled="!curComponent.showEmpty"
|
||||
placement="top"
|
||||
>
|
||||
<el-checkbox
|
||||
:disabled="curComponent.showEmpty"
|
||||
v-model="curComponent.parametersCheck"
|
||||
label="绑定参数"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<template v-if="curComponent.parametersCheck">
|
||||
<div v-if="curComponent.displayType !== '7'" class="parameters">
|
||||
<el-select
|
||||
popper-class="dataset-parameters"
|
||||
value-key="id"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
:max-collapse-tags="3"
|
||||
@focus="handleDialogClick"
|
||||
v-model="curComponent.parameters"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in parametersFilter"
|
||||
:key="item.id"
|
||||
:label="item.variableName"
|
||||
:value="item"
|
||||
>
|
||||
<div class="variable-name ellipsis">{{ item.variableName }}</div>
|
||||
<el-tooltip effect="dark" :content="item.datasetFullName" placement="top">
|
||||
<div class="dataset-full-name ellipsis">{{ item.datasetFullName }}</div>
|
||||
</el-tooltip>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div v-else class="parameters-range">
|
||||
<div class="range-title">开始时间</div>
|
||||
<div class="range-title">结束时间</div>
|
||||
<div class="params-start">
|
||||
<el-select
|
||||
popper-class="dataset-parameters"
|
||||
value-key="id"
|
||||
@focus="handleDialogClick"
|
||||
v-model="curComponent.parametersStart"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in parametersFilter"
|
||||
:key="item.id"
|
||||
:label="item.variableName"
|
||||
:value="item"
|
||||
>
|
||||
<div class="variable-name ellipsis">{{ item.variableName }}</div>
|
||||
<el-tooltip effect="dark" :content="item.datasetFullName" placement="top">
|
||||
<div class="dataset-full-name ellipsis">{{ item.datasetFullName }}</div>
|
||||
</el-tooltip>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="params-end">
|
||||
<el-select
|
||||
popper-class="dataset-parameters"
|
||||
value-key="id"
|
||||
@focus="handleDialogClick"
|
||||
v-model="curComponent.parametersEnd"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in parametersFilter"
|
||||
:key="item.id"
|
||||
:label="item.variableName"
|
||||
:value="item"
|
||||
>
|
||||
<div class="variable-name ellipsis">{{ item.variableName }}</div>
|
||||
<el-tooltip effect="dark" :content="item.datasetFullName" placement="top">
|
||||
<div class="dataset-full-name ellipsis">{{ item.datasetFullName }}</div>
|
||||
</el-tooltip>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="!['8'].includes(curComponent.displayType)" class="list-item">
|
||||
<div class="label">
|
||||
<el-checkbox v-model="curComponent.defaultValueCheck" label="设置默认值" />
|
||||
@ -1963,6 +1949,19 @@ defineExpose({
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.field-select--dqp {
|
||||
width: 210px;
|
||||
}
|
||||
.ed-select-dropdown__header {
|
||||
padding: 0 8px;
|
||||
.params-select--header {
|
||||
--ed-tabs-header-height: 32px;
|
||||
.ed-tabs__item {
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.condition-value-select-popper {
|
||||
.ed-select-dropdown__item.selected::after {
|
||||
display: none;
|
||||
|
@ -180,7 +180,7 @@ const handleFieldIdChange = (val: EnumValue) => {
|
||||
oldArr = [...selectValue.value]
|
||||
oldEnumValueArr = setOldMapValue(oldArr)
|
||||
}
|
||||
enumValueArr = [...res, ...oldEnumValueArr] || []
|
||||
enumValueArr = [...(res || []), ...oldEnumValueArr] || []
|
||||
options.value = [
|
||||
...new Set(
|
||||
(res || [])
|
||||
|
@ -204,7 +204,6 @@ export const searchQuery = (queryComponentList, filter, curComponentId, firstLoa
|
||||
defaultMapValue,
|
||||
mapValue,
|
||||
parameters = [],
|
||||
parametersCheck = false,
|
||||
isTree = false,
|
||||
timeGranularity = 'date',
|
||||
displayType,
|
||||
@ -307,16 +306,7 @@ export const searchQuery = (queryComponentList, filter, curComponentId, firstLoa
|
||||
fieldId: item.checkedFieldsMap[curComponentId],
|
||||
operator,
|
||||
value: result,
|
||||
parameters: parametersCheck
|
||||
? +displayType === 7
|
||||
? [
|
||||
parametersStart,
|
||||
parametersEnd?.id
|
||||
? { ...parametersEnd, id: `${parametersEnd.id}_START_END_SPLIT` }
|
||||
: parametersEnd
|
||||
]
|
||||
: parameters
|
||||
: [],
|
||||
parameters,
|
||||
isTree
|
||||
})
|
||||
}
|
||||
|
@ -25,6 +25,9 @@ interface LinkItem {
|
||||
method?: string
|
||||
}
|
||||
const linkList = ref([{ id: 5, label: t('common.about'), method: 'toAbout' }] as LinkItem[])
|
||||
if (!appearanceStore.getShowAbout) {
|
||||
linkList.value.splice(0, 1)
|
||||
}
|
||||
|
||||
const inPlatformClient = computed(() => !!wsCache.get('de-platform-client'))
|
||||
|
||||
@ -118,7 +121,7 @@ if (uid.value === '1') {
|
||||
<el-popover
|
||||
ref="popoverRef"
|
||||
:virtual-ref="buttonRef"
|
||||
trigger="hover"
|
||||
trigger="click"
|
||||
title=""
|
||||
virtual-triggering
|
||||
placement="bottom-start"
|
||||
|
@ -19,6 +19,7 @@ import AiComponent from '@/layout/components/AiComponent.vue'
|
||||
import { findBaseParams } from '@/api/aiComponent'
|
||||
import ExportExcel from '@/views/visualized/data/dataset/ExportExcel.vue'
|
||||
import AiTips from '@/layout/components/AiTips.vue'
|
||||
|
||||
const appearanceStore = useAppearanceStoreWithOut()
|
||||
const { push } = useRouter()
|
||||
const route = useRoute()
|
||||
@ -40,6 +41,7 @@ const activeIndex = computed(() => {
|
||||
}
|
||||
return route.path
|
||||
})
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
const ExportExcelRef = ref()
|
||||
const downloadClick = () => {
|
||||
@ -117,19 +119,30 @@ onMounted(() => {
|
||||
</el-menu>
|
||||
<div class="operate-setting" v-if="!desktop">
|
||||
<XpackComponent jsname="c3dpdGNoZXI=" />
|
||||
<el-icon style="margin: 0 10px" class="ai-icon" v-if="aiBaseUrl && !showOverlay">
|
||||
<el-icon
|
||||
style="margin: 0 10px"
|
||||
class="ai-icon"
|
||||
v-if="aiBaseUrl && !showOverlay && appearanceStore.getShowAi"
|
||||
>
|
||||
<Icon name="dv-ai" @click="handleAiClick" />
|
||||
</el-icon>
|
||||
<el-icon style="margin: 0 10px">
|
||||
<Icon name="dv-preview-download" @click="downloadClick" />
|
||||
</el-icon>
|
||||
<ai-tips @confirm="aiTipsConfirm" v-if="showOverlay" class="ai-icon-tips"></ai-tips>
|
||||
<ai-tips
|
||||
@confirm="aiTipsConfirm"
|
||||
v-if="showOverlay && appearanceStore.getShowAi"
|
||||
class="ai-icon-tips"
|
||||
/>
|
||||
<ToolboxCfg v-if="showToolbox" />
|
||||
<TopDoc />
|
||||
<TopDoc v-if="appearanceStore.getShowDoc" />
|
||||
<SystemCfg v-if="showSystem" />
|
||||
<AccountOperator />
|
||||
<ai-component v-if="aiBaseUrl" :base-url="aiBaseUrl"></ai-component>
|
||||
<div v-if="showOverlay" class="overlay"></div>
|
||||
<ai-component
|
||||
v-if="aiBaseUrl && appearanceStore.getShowAi"
|
||||
:base-url="aiBaseUrl"
|
||||
></ai-component>
|
||||
<div v-if="showOverlay && appearanceStore.getShowAi" class="overlay"></div>
|
||||
</div>
|
||||
</el-header>
|
||||
<ExportExcel ref="ExportExcelRef"></ExportExcel>
|
||||
|
@ -2,8 +2,10 @@
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const appearanceStore = useAppearanceStoreWithOut()
|
||||
const navigateBg = computed(() => appearanceStore.getNavigateBg)
|
||||
const showDoc = computed(() => appearanceStore.getShowDoc)
|
||||
const { push, resolve } = useRouter()
|
||||
const redirectUser = () => {
|
||||
const sysMenu = resolve('/system')
|
||||
@ -14,7 +16,13 @@ const redirectUser = () => {
|
||||
|
||||
<template>
|
||||
<el-tooltip class="box-item" effect="dark" content="组织管理中心" placement="top">
|
||||
<div class="sys-setting" :class="{ 'is-light-setting': navigateBg && navigateBg === 'light' }">
|
||||
<div
|
||||
class="sys-setting"
|
||||
:class="{
|
||||
'is-light-setting': navigateBg && navigateBg === 'light',
|
||||
'in-iframe-setting': !showDoc
|
||||
}"
|
||||
>
|
||||
<el-icon @click="redirectUser">
|
||||
<Icon class="icon-setting" name="icon-setting" />
|
||||
</el-icon>
|
||||
@ -35,6 +43,9 @@ const redirectUser = () => {
|
||||
background-color: #1e2738;
|
||||
}
|
||||
}
|
||||
.in-iframe-setting {
|
||||
margin-left: 10px !important;
|
||||
}
|
||||
.is-light-setting {
|
||||
&:hover {
|
||||
background-color: var(--ed-menu-hover-bg-color) !important;
|
||||
|
@ -2170,7 +2170,7 @@ export default {
|
||||
link_add_tips_pre: '请在右侧配置网页信息..',
|
||||
web_add_tips_suf: '添加网页信息...',
|
||||
panel_view_result_show: '图表结果',
|
||||
panel_view_result_tips: '选择仪表板会覆盖图表的结果展示数量,取值范围1~10000',
|
||||
panel_view_result_tips: '选择{0}会覆盖图表的结果展示数量,取值范围1~10000',
|
||||
timeout_refresh: '请求超时,稍后刷新...',
|
||||
mobile_layout: '移动端布局',
|
||||
component_hidden: '隐藏的组件',
|
||||
|
@ -232,7 +232,7 @@ declare interface ChartBasicStyle {
|
||||
/**
|
||||
* 对称柱状图方向
|
||||
*/
|
||||
layout: 'horizontal' | 'vertical'
|
||||
layout?: 'horizontal' | 'vertical'
|
||||
}
|
||||
/**
|
||||
* 表头属性
|
||||
@ -482,6 +482,10 @@ declare interface ChartMiscAttr {
|
||||
* 地图线条宽度
|
||||
*/
|
||||
mapLineWidth: number
|
||||
/**
|
||||
* 流向地图动画
|
||||
*/
|
||||
mapLineAnimate?: boolean
|
||||
/**
|
||||
* 流向地图动画间隔
|
||||
*/
|
||||
@ -786,6 +790,10 @@ declare interface ChartIndicatorStyle {
|
||||
* 字体颜色
|
||||
*/
|
||||
color: string
|
||||
/**
|
||||
* 背景颜色
|
||||
*/
|
||||
backgroundColor: string
|
||||
/**
|
||||
* 水平位置
|
||||
*/
|
||||
|
@ -123,6 +123,10 @@ declare interface ChartThreshold {
|
||||
* 仪表盘阈值: x,y,z
|
||||
*/
|
||||
gaugeThreshold: string
|
||||
/**
|
||||
* 水波图阈值: x,y,z
|
||||
*/
|
||||
liquidThreshold: string
|
||||
/**
|
||||
* 指标卡阈值
|
||||
*/
|
||||
|
@ -117,6 +117,14 @@ declare interface Axis extends ChartViewField {
|
||||
* 维度/指标分组类型
|
||||
*/
|
||||
groupType: 'q' | 'd'
|
||||
/**
|
||||
* 排序规则
|
||||
*/
|
||||
sort: 'asc' | 'desc' | 'none' | 'custom_sort'
|
||||
/**
|
||||
* 自定义排序项
|
||||
*/
|
||||
customSort: string[]
|
||||
}
|
||||
declare interface ChartViewField {
|
||||
/**
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
|
||||
const VisualizationEditor = defineAsyncComponent(
|
||||
() => import('@/views/data-visualization/index.vue')
|
||||
@ -33,6 +34,15 @@ const componentMap = {
|
||||
DashboardPanel
|
||||
}
|
||||
|
||||
const changeCurrentComponent = val => {
|
||||
currentComponent.value = componentMap[val]
|
||||
}
|
||||
|
||||
useEmitt({
|
||||
name: 'changeCurrentComponent',
|
||||
callback: changeCurrentComponent
|
||||
})
|
||||
|
||||
currentComponent.value = componentMap[props.componentName]
|
||||
</script>
|
||||
<template>
|
||||
|
@ -47,7 +47,9 @@ onBeforeMount(async () => {
|
||||
// div嵌入
|
||||
if (embeddedStore.outerParams) {
|
||||
try {
|
||||
attachParam = JSON.parse(embeddedStore.outerParams)
|
||||
const outerPramsParse = JSON.parse(embeddedStore.outerParams)
|
||||
attachParam = outerPramsParse.attachParam
|
||||
dvMainStore.setEmbeddedCallBack(outerPramsParse.callBackFlag || 'no')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
ElMessage.error(t('visualization.outer_param_decode_error'))
|
||||
|
@ -66,7 +66,9 @@ onBeforeMount(async () => {
|
||||
// div嵌入
|
||||
if (embeddedStore.outerParams) {
|
||||
try {
|
||||
attachParam = JSON.parse(embeddedStore.outerParams)
|
||||
const outerPramsParse = JSON.parse(embeddedStore.outerParams)
|
||||
attachParam = outerPramsParse.attachParam
|
||||
dvMainStore.setEmbeddedCallBack(outerPramsParse.callBackFlag || 'no')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
ElMessage.error(t('visualization.outer_param_decode_error'))
|
||||
|
@ -6,12 +6,16 @@ import colorFunctions from 'less/lib/less/functions/color.js'
|
||||
import colorTree from 'less/lib/less/tree/color.js'
|
||||
const basePath = import.meta.env.VITE_API_BASEPATH
|
||||
const baseUrl = basePath + '/appearance/image/'
|
||||
import { isBtnShow } from '@/utils/utils'
|
||||
interface AppearanceState {
|
||||
themeColor?: string
|
||||
customColor?: string
|
||||
navigateBg?: string
|
||||
navigate?: string
|
||||
help?: string
|
||||
showAi?: string
|
||||
showDoc?: string
|
||||
showAbout?: string
|
||||
bg?: string
|
||||
login?: string
|
||||
slogan?: string
|
||||
@ -33,6 +37,9 @@ export const useAppearanceStore = defineStore('appearanceStore', {
|
||||
navigateBg: '',
|
||||
navigate: '',
|
||||
help: '',
|
||||
showDoc: '0',
|
||||
showAi: '0',
|
||||
showAbout: '0',
|
||||
bg: '',
|
||||
login: '',
|
||||
slogan: '',
|
||||
@ -106,6 +113,15 @@ export const useAppearanceStore = defineStore('appearanceStore', {
|
||||
},
|
||||
getCommunity(): boolean {
|
||||
return this.community
|
||||
},
|
||||
getShowAi(): boolean {
|
||||
return isBtnShow(this.showAi)
|
||||
},
|
||||
getShowDoc(): boolean {
|
||||
return isBtnShow(this.showDoc)
|
||||
},
|
||||
getShowAbout(): boolean {
|
||||
return isBtnShow(this.showAbout)
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@ -160,6 +176,9 @@ export const useAppearanceStore = defineStore('appearanceStore', {
|
||||
}
|
||||
this.navigate = data.navigate
|
||||
this.help = data.help
|
||||
this.showAi = data.showAi
|
||||
this.showDoc = data.showDoc
|
||||
this.showAbout = data.showAbout
|
||||
this.navigateBg = data.navigateBg
|
||||
this.themeColor = data.themeColor
|
||||
this.customColor = data.customColor
|
||||
|
@ -32,6 +32,7 @@ export const dvMainStore = defineStore('dataVisualization', {
|
||||
chartAreaCollapse: false,
|
||||
datasetAreaCollapse: false
|
||||
},
|
||||
embeddedCallBack: 'no', // 嵌入模式是否允许反馈参数
|
||||
editMode: 'edit', // 编辑器模式 edit preview
|
||||
mobileInPc: false,
|
||||
firstLoadMap: [],
|
||||
@ -173,6 +174,9 @@ export const dvMainStore = defineStore('dataVisualization', {
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setEmbeddedCallBack(value) {
|
||||
this.embeddedCallBack = value
|
||||
},
|
||||
setPublicLinkStatus(value) {
|
||||
this.publicLinkStatus = value
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { store } from '../index'
|
||||
import { clear } from '@/api/sync/syncTaskLog'
|
||||
interface AppState {
|
||||
type: string
|
||||
token: string
|
||||
@ -10,6 +11,9 @@ interface AppState {
|
||||
pid: string
|
||||
chartId: string
|
||||
resourceId: string
|
||||
opt: string
|
||||
createType: string
|
||||
templateParams: string
|
||||
}
|
||||
|
||||
export const userStore = defineStore('embedded', {
|
||||
@ -23,13 +27,22 @@ export const userStore = defineStore('embedded', {
|
||||
dvId: '',
|
||||
pid: '',
|
||||
chartId: '',
|
||||
resourceId: ''
|
||||
resourceId: '',
|
||||
opt: '',
|
||||
createType: '',
|
||||
templateParams: ''
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getType(): string {
|
||||
return this.type
|
||||
},
|
||||
getCreateType(): string {
|
||||
return this.createType
|
||||
},
|
||||
getTemplateParams(): string {
|
||||
return this.templateParams
|
||||
},
|
||||
getToken(): string {
|
||||
return this.token
|
||||
},
|
||||
@ -54,6 +67,9 @@ export const userStore = defineStore('embedded', {
|
||||
getResourceId(): string {
|
||||
return this.resourceId
|
||||
},
|
||||
getOpt(): string {
|
||||
return this.opt
|
||||
},
|
||||
getIframeData(): any {
|
||||
return {
|
||||
embeddedToken: this.token,
|
||||
@ -71,6 +87,12 @@ export const userStore = defineStore('embedded', {
|
||||
setType(type: string) {
|
||||
this.type = type
|
||||
},
|
||||
setCreateType(createType: string) {
|
||||
this.createType = createType
|
||||
},
|
||||
setTemplateParams(templateParams: string) {
|
||||
this.templateParams = templateParams
|
||||
},
|
||||
setToken(token: string) {
|
||||
this.token = token
|
||||
},
|
||||
@ -95,6 +117,9 @@ export const userStore = defineStore('embedded', {
|
||||
setResourceId(resourceId: string) {
|
||||
this.resourceId = resourceId
|
||||
},
|
||||
setOpt(opt: string) {
|
||||
this.opt = opt
|
||||
},
|
||||
setIframeData(data: any) {
|
||||
this.type = data['type']
|
||||
this.token = data['embeddedToken']
|
||||
@ -104,6 +129,14 @@ export const userStore = defineStore('embedded', {
|
||||
this.chartId = data['chartId']
|
||||
this.pid = data['pid']
|
||||
this.resourceId = data['resourceId']
|
||||
},
|
||||
clearState() {
|
||||
this.setPid('')
|
||||
this.setOpt('')
|
||||
this.setCreateType('')
|
||||
this.setTemplateParams('')
|
||||
this.setResourceId('')
|
||||
this.setDvId('')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -174,17 +174,30 @@ function move(keyCode) {
|
||||
if (curComponent.value) {
|
||||
if (keyCode === leftKey) {
|
||||
curComponent.value.style.left = --curComponent.value.style.left
|
||||
groupAreaAdaptor(-1, 0)
|
||||
} else if (keyCode === rightKey) {
|
||||
curComponent.value.style.left = ++curComponent.value.style.left
|
||||
groupAreaAdaptor(1, 0)
|
||||
} else if (keyCode === upKey) {
|
||||
curComponent.value.style.top = --curComponent.value.style.top
|
||||
groupAreaAdaptor(0, -1)
|
||||
} else if (keyCode === downKey) {
|
||||
curComponent.value.style.top = ++curComponent.value.style.top
|
||||
groupAreaAdaptor(0, 1)
|
||||
}
|
||||
snapshotStore.recordSnapshotCache('key-move')
|
||||
}
|
||||
}
|
||||
|
||||
function groupAreaAdaptor(leftOffset = 0, topOffset = 0) {
|
||||
if (curComponent.value.component === 'GroupArea') {
|
||||
composeStore.areaData.components.forEach(component => {
|
||||
component.style.top = component.style.top + topOffset
|
||||
component.style.left = component.style.left + leftOffset
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function cut() {
|
||||
copyStore.cut()
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import { groupSizeStyleAdaptor } from '@/utils/style'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { componentData, curComponentIndex, canvasStyleData } = storeToRefs(dvMainStore)
|
||||
|
||||
const needToChangeAttrs = ['top', 'left', 'width', 'height', 'fontSize']
|
||||
const needToChangeAttrs = ['top', 'left', 'width', 'height', 'fontSize', 'letterSpacing']
|
||||
|
||||
export function changeSizeWithScale(scale) {
|
||||
return changeComponentsSizeWithScale(scale)
|
||||
|
@ -31,6 +31,8 @@ import DeVideo from '@/custom-component/de-video/Component.vue'
|
||||
import DeVideoAttr from '@/custom-component/de-video/Attr.vue'
|
||||
import DeStreamMedia from '@/custom-component/de-stream-media/Component.vue'
|
||||
import DeStreamMediaAttr from '@/custom-component/de-stream-media/Attr.vue'
|
||||
import ScrollText from '@/custom-component/scroll-text/Component.vue'
|
||||
import ScrollTextAttr from '@/custom-component/scroll-text/Attr.vue'
|
||||
export const componentsMap = {
|
||||
VText: VText,
|
||||
VQuery,
|
||||
@ -64,7 +66,9 @@ export const componentsMap = {
|
||||
DeVideo: DeVideo,
|
||||
DeVideoAttr: DeVideoAttr,
|
||||
DeStreamMedia: DeStreamMedia,
|
||||
DeStreamMediaAttr: DeStreamMediaAttr
|
||||
DeStreamMediaAttr: DeStreamMediaAttr,
|
||||
ScrollText: ScrollText,
|
||||
ScrollTextAttr: ScrollTextAttr
|
||||
}
|
||||
|
||||
export default function findComponent(key) {
|
||||
|
@ -6,6 +6,7 @@ import { storeToRefs } from 'pinia'
|
||||
import { findResourceAsBase64 } from '@/api/staticResource'
|
||||
import FileSaver from 'file-saver'
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
import { toPng } from 'html-to-image'
|
||||
const embeddedStore = useEmbedded()
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { canvasStyleData, componentData, canvasViewInfo, canvasViewDataInfo, dvInfo } =
|
||||
@ -70,6 +71,35 @@ export function download2AppTemplate(downloadType, canvasDom, name, callBack?) {
|
||||
}
|
||||
}
|
||||
|
||||
export function downloadCanvas2(type, canvasDom, name, callBack?) {
|
||||
toPng(canvasDom)
|
||||
.then(dataUrl => {
|
||||
const a = document.createElement('a')
|
||||
a.setAttribute('download', name)
|
||||
a.href = dataUrl
|
||||
if (type === 'img') {
|
||||
const a = document.createElement('a')
|
||||
a.setAttribute('download', name)
|
||||
a.href = dataUrl
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
} else {
|
||||
const contentWidth = canvasDom.offsetWidth
|
||||
const contentHeight = canvasDom.offsetHeight
|
||||
const lp = contentWidth > contentHeight ? 'l' : 'p'
|
||||
const PDF = new JsPDF(lp, 'pt', [contentWidth, contentHeight])
|
||||
PDF.addImage(dataUrl, 'PNG', 0, 0, contentWidth, contentHeight)
|
||||
PDF.save(name + '.pdf')
|
||||
}
|
||||
if (callBack) {
|
||||
callBack()
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('oops, something went wrong!', error)
|
||||
})
|
||||
}
|
||||
|
||||
export function downloadCanvas(type, canvasDom, name, callBack?) {
|
||||
// const canvasDom = document.getElementById(canvasId)
|
||||
if (canvasDom) {
|
||||
|
@ -106,7 +106,24 @@ export const cleanPlatformFlag = () => {
|
||||
wsCache.delete(platformKey)
|
||||
return false
|
||||
}
|
||||
export const isInIframe = () => {
|
||||
try {
|
||||
return window.top !== window.self
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export const isBtnShow = (val: string) => {
|
||||
if (!val || val === '0') {
|
||||
return true
|
||||
} else if (val === '1') {
|
||||
return false
|
||||
} else {
|
||||
return !isInIframe()
|
||||
}
|
||||
}
|
||||
export function isMobile() {
|
||||
return (
|
||||
navigator.userAgent.match(
|
||||
|
@ -138,7 +138,9 @@ const canvasInit = (isFistLoad = true) => {
|
||||
}
|
||||
// afterInit
|
||||
dvMainStore.setDataPrepareState(true)
|
||||
isFistLoad && snapshotStore.recordSnapshotCache('renderChart')
|
||||
if (isMainCanvas(canvasId.value.id) && isFistLoad) {
|
||||
snapshotStore.recordSnapshotCache('renderChart')
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
|
||||
|
@ -61,10 +61,10 @@ const init = () => {
|
||||
const changeThreshold = () => {
|
||||
emit('onThresholdChange', state.thresholdForm)
|
||||
}
|
||||
const gaugeThresholdChange = () => {
|
||||
const changeSplitThreshold = (threshold: string) => {
|
||||
// check input
|
||||
if (state.thresholdForm.gaugeThreshold) {
|
||||
const arr = state.thresholdForm.gaugeThreshold.split(',')
|
||||
if (threshold) {
|
||||
const arr = threshold.split(',')
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const ele = arr[i]
|
||||
if (parseFloat(ele).toString() === 'NaN' || parseFloat(ele) <= 0 || parseFloat(ele) >= 100) {
|
||||
@ -246,7 +246,7 @@ init()
|
||||
style="width: 100px; margin: 0 10px"
|
||||
size="small"
|
||||
clearable
|
||||
@change="gaugeThresholdChange"
|
||||
@change="changeSplitThreshold"
|
||||
/>
|
||||
<span>,100</span>
|
||||
<el-tooltip effect="dark" placement="bottom">
|
||||
@ -260,6 +260,36 @@ init()
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col v-show="showProperty('liquidThreshold')">
|
||||
<el-form ref="thresholdForm" :model="state.thresholdForm" label-position="top">
|
||||
<el-form-item
|
||||
:label="t('chart.threshold_range') + '(%)'"
|
||||
class="form-item"
|
||||
label-width="auto"
|
||||
>
|
||||
<span>0,</span>
|
||||
<el-input
|
||||
:effect="themes"
|
||||
:placeholder="t('chart.threshold_range')"
|
||||
:disabled="!state.thresholdForm.enable"
|
||||
v-model="state.thresholdForm.liquidThreshold"
|
||||
style="width: 100px; margin: 0 10px"
|
||||
size="small"
|
||||
clearable
|
||||
@change="changeSplitThreshold"
|
||||
/>
|
||||
<span>,100</span>
|
||||
<el-tooltip effect="dark" placement="bottom">
|
||||
<el-icon style="margin-left: 10px"><InfoFilled /></el-icon>
|
||||
<template #content>
|
||||
阈值设置,决定水波图颜色,为空则不开启阈值,范围(0-100),逐级递增
|
||||
<br />
|
||||
例如:输入 30,70;表示:分为3段,分别为[0,30],(30,70],(70,100]
|
||||
</template>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
|
||||
<!--文本卡-->
|
||||
<el-col v-if="props.chart.type && props.chart.type === 'label'">
|
||||
@ -409,14 +439,14 @@ init()
|
||||
class="color-div"
|
||||
:class="{ 'color-div-dark': themes === 'dark' }"
|
||||
></div>
|
||||
<!-- <div
|
||||
<div
|
||||
:title="t('chart.backgroundColor')"
|
||||
:style="{
|
||||
backgroundColor: item.backgroundColor
|
||||
}"
|
||||
class="color-div"
|
||||
:class="{ 'color-div-dark': themes === 'dark' }"
|
||||
></div>-->
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
@ -24,6 +24,7 @@ const thresholdObj = {
|
||||
field: '0',
|
||||
value: '0',
|
||||
color: '#ff0000ff',
|
||||
backgroundColor: '#fff',
|
||||
min: '0',
|
||||
max: '1'
|
||||
}
|
||||
@ -175,7 +176,7 @@ init()
|
||||
@change="changeThreshold"
|
||||
/>
|
||||
</div>
|
||||
<!-- <div style="display: flex; align-items: center; justify-content: center; margin-left: 8px">
|
||||
<div style="display: flex; align-items: center; justify-content: center; margin-left: 8px">
|
||||
<div class="color-title">{{ t('chart.backgroundColor') }}</div>
|
||||
<el-color-picker
|
||||
is-custom
|
||||
@ -186,7 +187,7 @@ init()
|
||||
:predefine="predefineColors"
|
||||
@change="changeThreshold"
|
||||
/>
|
||||
</div>-->
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; justify-content: center; margin-left: 8px">
|
||||
<el-button
|
||||
class="circle-button"
|
||||
|
@ -221,6 +221,7 @@ watch(
|
||||
:themes="themes"
|
||||
:chart="chart"
|
||||
@onBasicStyleChange="onBasicStyleChange"
|
||||
@onMiscChange="onMiscChange"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
<collapse-switch-item
|
||||
|
@ -1,6 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, PropType, reactive, watch } from 'vue'
|
||||
import { COLOR_PANEL, DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||
import {
|
||||
COLOR_PANEL,
|
||||
DEFAULT_BASIC_STYLE,
|
||||
DEFAULT_MISC
|
||||
} from '@/views/chart/components/editor/util/chart'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import CustomColorStyleSelect from '@/views/chart/components/editor/editor-style/components/CustomColorStyleSelect.vue'
|
||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||
@ -28,6 +32,7 @@ const showProperty = prop => props.propertyInner?.includes(prop)
|
||||
const predefineColors = COLOR_PANEL
|
||||
const state = reactive({
|
||||
basicStyleForm: JSON.parse(JSON.stringify(DEFAULT_BASIC_STYLE)) as ChartBasicStyle,
|
||||
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)) as ChartMiscAttr,
|
||||
customColor: null,
|
||||
colorIndex: 0,
|
||||
fieldColumnWidth: {
|
||||
@ -38,6 +43,7 @@ const state = reactive({
|
||||
watch(
|
||||
[
|
||||
() => props.chart.customAttr.basicStyle,
|
||||
() => props.chart.customAttr.misc,
|
||||
() => props.chart.customAttr.tableHeader,
|
||||
() => props.chart.xAxis,
|
||||
() => props.chart.yAxis
|
||||
@ -47,14 +53,19 @@ watch(
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
const emit = defineEmits(['onBasicStyleChange'])
|
||||
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
|
||||
const changeBasicStyle = (prop?: string, requestData = false) => {
|
||||
emit('onBasicStyleChange', { data: state.basicStyleForm, requestData }, prop)
|
||||
}
|
||||
const changeMisc = prop => {
|
||||
emit('onMiscChange', { data: state.miscForm, requestData: true }, prop)
|
||||
}
|
||||
const init = () => {
|
||||
const basicStyle = cloneDeep(props.chart.customAttr.basicStyle)
|
||||
const miscStyle = cloneDeep(props.chart.customAttr.misc)
|
||||
configCompat(basicStyle)
|
||||
state.basicStyleForm = defaultsDeep(basicStyle, cloneDeep(DEFAULT_BASIC_STYLE)) as ChartBasicStyle
|
||||
state.miscForm = defaultsDeep(miscStyle, cloneDeep(DEFAULT_MISC)) as ChartMiscAttr
|
||||
if (!state.customColor) {
|
||||
state.customColor = state.basicStyleForm.colors[0]
|
||||
state.colorIndex = 0
|
||||
@ -177,6 +188,12 @@ const mapStyleOptions = [
|
||||
{ name: t('chart.map_style_wine'), value: 'wine' }
|
||||
]
|
||||
|
||||
const flowLineTypeOptions = [
|
||||
{ name: t('chart.map_line_type_line'), value: 'line' },
|
||||
{ name: t('chart.map_line_type_arc'), value: 'arc' },
|
||||
{ name: t('chart.map_line_type_arc_3d'), value: 'arc3d' }
|
||||
]
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
@ -268,7 +285,236 @@ onMounted(() => {
|
||||
<el-radio :effect="themes" label="vertical">{{ t('chart.vertical') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!--flow map begin-->
|
||||
<div class="map-setting" v-if="showProperty('mapStyle')">
|
||||
<div class="map-style">
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item
|
||||
:label="t('chart.chart_map') + t('chart.map_style')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-select
|
||||
:effect="themes"
|
||||
v-model="state.basicStyleForm.mapStyle"
|
||||
@change="changeBasicStyle('mapStyle')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in mapStyleOptions"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="alpha-setting">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.chart_map') + t('chart.map_pitch') }}
|
||||
</label>
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col>
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
:min="0"
|
||||
:max="90"
|
||||
v-model="state.miscForm.mapPitch"
|
||||
@change="changeMisc('mapPitch')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<div class="map-flow-style">
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item
|
||||
:label="t('chart.line') + t('chart.map_line_type')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-select
|
||||
:effect="themes"
|
||||
v-model="state.miscForm.mapLineType"
|
||||
@change="changeMisc('mapLineType')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in flowLineTypeOptions"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="alpha-setting">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.map_line_width') }}
|
||||
</label>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
:min="1"
|
||||
:max="10"
|
||||
v-model="state.miscForm.mapLineWidth"
|
||||
@change="changeMisc('mapLineWidth')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.miscForm.mapLineGradient"
|
||||
:predefine="predefineColors"
|
||||
@change="changeMisc('mapLineGradient')"
|
||||
>
|
||||
{{ t('chart.line') + t('chart.map_line_linear') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div v-if="state.miscForm.mapLineGradient">
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col :span="13">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
:label="t('chart.map_line_color_source_color')"
|
||||
>
|
||||
<el-color-picker
|
||||
is-custom
|
||||
class="color-picker-style"
|
||||
v-model="state.miscForm.mapLineSourceColor"
|
||||
:persistent="false"
|
||||
:effect="themes"
|
||||
:trigger-width="108"
|
||||
:predefine="predefineColors"
|
||||
@change="changeMisc('mapLineSourceColor')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
:label="t('chart.map_line_color_target_color')"
|
||||
>
|
||||
<el-color-picker
|
||||
is-custom
|
||||
class="color-picker-style"
|
||||
v-model="state.miscForm.mapLineTargetColor"
|
||||
:persistent="false"
|
||||
:effect="themes"
|
||||
:trigger-width="108"
|
||||
:predefine="predefineColors"
|
||||
@change="changeMisc('mapLineTargetColor')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div v-if="!state.miscForm.mapLineGradient">
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col>
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
:label="t('chart.color')"
|
||||
>
|
||||
<el-color-picker
|
||||
is-custom
|
||||
class="color-picker-style"
|
||||
v-model="state.miscForm.mapLineSourceColor"
|
||||
:persistent="false"
|
||||
:effect="themes"
|
||||
:trigger-width="108"
|
||||
:predefine="predefineColors"
|
||||
@change="changeMisc('mapLineSourceColor')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="alpha-setting">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.not_alpha') }}
|
||||
</label>
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col :span="13">
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
v-model="state.basicStyleForm.alpha"
|
||||
@change="changeBasicStyle('alpha')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11" style="padding-top: 2px">
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-input
|
||||
type="number"
|
||||
:effect="themes"
|
||||
v-model="state.basicStyleForm.alpha"
|
||||
:min="0"
|
||||
:max="100"
|
||||
class="basic-input-number"
|
||||
:controls="false"
|
||||
@change="changeBasicStyle('alpha')"
|
||||
>
|
||||
<template #suffix> % </template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.miscForm.mapLineAnimate"
|
||||
:predefine="predefineColors"
|
||||
@change="changeMisc('mapLineAnimate')"
|
||||
>
|
||||
{{ t('chart.line') + t('chart.map_line_animate') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="alpha-setting" v-if="state.miscForm.mapLineAnimate">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.map_line_animate_duration') }}
|
||||
</label>
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col>
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
:min="0"
|
||||
:max="20"
|
||||
v-model="state.miscForm.mapLineAnimateDuration"
|
||||
@change="changeMisc('mapLineAnimateDuration')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--flow map end-->
|
||||
<!--map start-->
|
||||
<el-row :gutter="8">
|
||||
<el-col :span="12" v-if="showProperty('areaBorderColor')">
|
||||
@ -658,27 +904,6 @@ onMounted(() => {
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!--radar end-->
|
||||
<!--flow map begin-->
|
||||
<el-form-item
|
||||
:label="t('chart.map_style')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('mapStyle')"
|
||||
>
|
||||
<el-select
|
||||
:effect="themes"
|
||||
v-model="state.basicStyleForm.mapStyle"
|
||||
@change="changeBasicStyle('mapStyle')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in mapStyleOptions"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!--flow map end-->
|
||||
<!--scatter start-->
|
||||
<el-form-item
|
||||
:label="t('chart.bubble_symbol')"
|
||||
|
@ -224,7 +224,11 @@ onMounted(() => {
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<div class="position-divider" :class="'position-divider--' + themes"></div>
|
||||
<div
|
||||
v-if="showProperty('orient')"
|
||||
class="position-divider"
|
||||
:class="'position-divider--' + themes"
|
||||
></div>
|
||||
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
|
@ -137,11 +137,13 @@ onMounted(() => {
|
||||
label-position="top"
|
||||
>
|
||||
<template v-if="showProperty('lineStyle')">
|
||||
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes"
|
||||
>{{ t('chart.quadrant') }}{{ t('chart.split_line') }}</label
|
||||
>
|
||||
<div style="display: flex">
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-right: 4px">
|
||||
<el-form-item
|
||||
:label="t('chart.split_line')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
style="padding-right: 4px"
|
||||
>
|
||||
<el-color-picker
|
||||
v-model="state.quadrantForm.lineStyle.stroke"
|
||||
class="color-picker-style"
|
||||
@ -152,6 +154,7 @@ onMounted(() => {
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
|
||||
<template #label> </template>
|
||||
<el-tooltip :content="t('chart.not_alpha')" :effect="toolTip" placement="top">
|
||||
<el-select
|
||||
style="width: 53px"
|
||||
@ -170,6 +173,7 @@ onMounted(() => {
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
|
||||
<template #label> </template>
|
||||
<el-tooltip :content="t('chart.funnel_width')" :effect="toolTip" placement="top">
|
||||
<el-input-number
|
||||
style="width: 108px"
|
||||
@ -229,18 +233,14 @@ onMounted(() => {
|
||||
:label="t('chart.quadrant') + (index + 1)"
|
||||
class="padding-tab"
|
||||
>
|
||||
<div style="flex-direction: row; justify-content: space-between">
|
||||
<div style="margin-top: 8px">
|
||||
<template v-if="showProperty('regionStyle')">
|
||||
<div style="display: flex">
|
||||
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes">{{
|
||||
t('chart.backgroundColor')
|
||||
}}</label>
|
||||
</div>
|
||||
<div style="display: flex">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
style="padding-right: 4px"
|
||||
:label="t('chart.backgroundColor')"
|
||||
>
|
||||
<el-color-picker
|
||||
v-model="state.quadrantForm.regionStyle[index].fill"
|
||||
@ -256,6 +256,7 @@ onMounted(() => {
|
||||
:class="'form-item-' + themes"
|
||||
style="padding-left: 4px"
|
||||
>
|
||||
<template #label> </template>
|
||||
<el-tooltip :content="t('chart.not_alpha')" :effect="toolTip" placement="top">
|
||||
<el-select
|
||||
style="width: 53px"
|
||||
@ -285,14 +286,12 @@ onMounted(() => {
|
||||
@blur="changeStyle()"
|
||||
/>
|
||||
</el-form-item>
|
||||
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes">
|
||||
{{ t('chart.text') }}{{ t('chart.chart_style') }}</label
|
||||
>
|
||||
<div style="display: flex">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
style="padding-right: 4px"
|
||||
:label="t('chart.chart_style')"
|
||||
>
|
||||
<el-color-picker
|
||||
v-model="l.style.fill"
|
||||
@ -308,6 +307,7 @@ onMounted(() => {
|
||||
:class="'form-item-' + themes"
|
||||
style="padding-left: 4px"
|
||||
>
|
||||
<template #label> </template>
|
||||
<el-tooltip :content="t('chart.not_alpha')" :effect="toolTip" placement="top">
|
||||
<el-select
|
||||
style="width: 53px"
|
||||
@ -330,6 +330,7 @@ onMounted(() => {
|
||||
:class="'form-item-' + themes"
|
||||
style="padding-left: 4px"
|
||||
>
|
||||
<template #label> </template>
|
||||
<el-tooltip :content="t('chart.font_size')" :effect="toolTip" placement="top">
|
||||
<el-select
|
||||
style="width: 108px"
|
||||
|
@ -153,15 +153,12 @@ onMounted(() => {
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes"
|
||||
>{{ t('chart.name') }}{{ t('chart.text') }}</label
|
||||
>
|
||||
<div style="display: flex">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('color')"
|
||||
style="padding-right: 4px"
|
||||
:label="t('chart.chart_style')"
|
||||
>
|
||||
<el-color-picker
|
||||
v-model="state.axisForm.color"
|
||||
@ -178,6 +175,7 @@ onMounted(() => {
|
||||
v-if="showProperty('fontSize')"
|
||||
style="padding-left: 4px"
|
||||
>
|
||||
<template #label> </template>
|
||||
<el-tooltip content="字号" :effect="toolTip" placement="top">
|
||||
<el-select
|
||||
style="width: 108px"
|
||||
|
@ -129,15 +129,13 @@ onMounted(() => {
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes"
|
||||
>{{ t('chart.name') }}{{ t('chart.text') }}</label
|
||||
>
|
||||
<div style="display: flex">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('color')"
|
||||
style="padding-right: 4px"
|
||||
:label="t('chart.chart_style')"
|
||||
>
|
||||
<el-color-picker
|
||||
v-model="state.axisForm.color"
|
||||
@ -154,6 +152,7 @@ onMounted(() => {
|
||||
v-if="showProperty('fontSize')"
|
||||
style="padding-left: 4px"
|
||||
>
|
||||
<template #label> </template>
|
||||
<el-tooltip content="字号" :effect="toolTip" placement="top">
|
||||
<el-select
|
||||
style="width: 108px"
|
||||
|
@ -209,12 +209,7 @@ onMounted(() => {
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item
|
||||
:label="t('chart.table_show_index')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('showIndex')"
|
||||
>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes" v-if="showProperty('showIndex')">
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
|
@ -3044,6 +3044,35 @@ const drop = (ev: MouseEvent, type = 'xAxis') => {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
:deep(.ed-tabs__nav-wrap::after) {
|
||||
background-color: rgba(31, 35, 41, 0.15);
|
||||
}
|
||||
:deep(.ed-tabs__nav-scroll) {
|
||||
.ed-tabs__item {
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
color: var(--ed-color-primary, #3370ff);
|
||||
font-family: '阿里巴巴普惠体 3.0 55 Regular L3';
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
.query-style-tab {
|
||||
width: 100%;
|
||||
border-top: solid 1px @side-outline-border-color-light !important;
|
||||
|
||||
.tab-container {
|
||||
.border-bottom-tab(8px);
|
||||
}
|
||||
|
||||
margin-left: 0px !important;
|
||||
|
||||
:deep(.ed-tabs__header) {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
:deep(.ed-tabs__nav-wrap::after) {
|
||||
background-color: rgba(31, 35, 41, 0.15);
|
||||
}
|
||||
@ -3082,6 +3111,35 @@ const drop = (ev: MouseEvent, type = 'xAxis') => {
|
||||
box-shadow: 0 0 0 1px var(--ed-color-primary, #3370ff) inset !important;
|
||||
}
|
||||
}
|
||||
.query-style-tab {
|
||||
width: 100%;
|
||||
border-top: solid 1px @main-collapse-border-dark !important;
|
||||
|
||||
.tab-container {
|
||||
.border-bottom-tab(8px);
|
||||
}
|
||||
|
||||
margin-left: 0px !important;
|
||||
|
||||
:deep(.ed-tabs__header) {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
:deep(.ed-tabs__nav-wrap::after) {
|
||||
background-color: rgba(31, 35, 41, 0.15);
|
||||
}
|
||||
:deep(.ed-tabs__nav-scroll) {
|
||||
.ed-tabs__item {
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
color: var(--ed-color-primary, #3370ff);
|
||||
font-family: '阿里巴巴普惠体 3.0 55 Regular L3';
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chart-edit {
|
||||
|
@ -388,6 +388,7 @@ export const DEFAULT_INDICATOR_STYLE: ChartIndicatorStyle = {
|
||||
fontFamily: 'Microsoft YaHei',
|
||||
letterSpace: 0,
|
||||
fontShadow: false,
|
||||
backgroundColor: '#fff',
|
||||
|
||||
suffixEnable: true,
|
||||
suffix: '',
|
||||
@ -675,6 +676,7 @@ export const DEFAULT_ASSIST_LINE_CFG: ChartAssistLineCfg = {
|
||||
export const DEFAULT_THRESHOLD: ChartThreshold = {
|
||||
enable: false,
|
||||
gaugeThreshold: '',
|
||||
liquidThreshold: '',
|
||||
labelThreshold: [],
|
||||
tableThreshold: [],
|
||||
textLabelThreshold: []
|
||||
@ -1223,14 +1225,14 @@ export const CHART_TYPE_CONFIGS = [
|
||||
category: 'compare',
|
||||
value: 'bidirectional-bar',
|
||||
title: t('chart.chart_bidirectional_bar'),
|
||||
icon: 'percentage-bar-stack-horizontal'
|
||||
icon: 'bidirectional-bar'
|
||||
},
|
||||
{
|
||||
render: 'antv',
|
||||
category: 'compare',
|
||||
value: 'progress-bar',
|
||||
title: t('chart.chart_progress_bar'),
|
||||
icon: 'percentage-bar-stack-horizontal'
|
||||
icon: 'progress-bar'
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -1308,6 +1310,13 @@ export const CHART_TYPE_CONFIGS = [
|
||||
value: 'bubble-map',
|
||||
title: t('chart.chart_bubble_map'),
|
||||
icon: 'bubble-map'
|
||||
},
|
||||
{
|
||||
render: 'antv',
|
||||
category: 'map',
|
||||
value: 'flow-map',
|
||||
title: t('chart.chart_flow_map'),
|
||||
icon: 'flow-map'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -19,7 +19,8 @@ export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
|
||||
'basic-style-selector',
|
||||
'label-selector',
|
||||
'misc-selector',
|
||||
'title-selector'
|
||||
'title-selector',
|
||||
'threshold'
|
||||
]
|
||||
propertyInner: EditorPropertyInner = {
|
||||
'background-overall-component': ['all'],
|
||||
@ -37,7 +38,8 @@ export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
|
||||
'fontFamily',
|
||||
'letterSpace',
|
||||
'fontShadow'
|
||||
]
|
||||
],
|
||||
threshold: ['liquidThreshold']
|
||||
}
|
||||
axis: AxisType[] = ['yAxis', 'filter']
|
||||
axisConfig: AxisConfig = {
|
||||
@ -147,6 +149,31 @@ export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
|
||||
}
|
||||
}
|
||||
|
||||
protected configThreshold(chart: Chart, options: LiquidOptions): LiquidOptions {
|
||||
const senior = parseJson(chart.senior)
|
||||
if (senior?.threshold?.enable) {
|
||||
const { liquidThreshold } = senior?.threshold
|
||||
if (liquidThreshold) {
|
||||
const { paletteQualitative10: colors } = (options.theme as any).styleSheet
|
||||
const liquidStyle = () => {
|
||||
const thresholdArr = liquidThreshold.split(',')
|
||||
let index = 0
|
||||
thresholdArr.forEach((v, i) => {
|
||||
if (options.percent > parseFloat(v) / 100) {
|
||||
index = i + 1
|
||||
}
|
||||
})
|
||||
return {
|
||||
fill: colors[index % colors.length],
|
||||
stroke: colors[index % colors.length]
|
||||
}
|
||||
}
|
||||
return { ...options, liquidStyle }
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
setupDefaultOptions(chart: ChartObj): ChartObj {
|
||||
chart.customAttr.label = {
|
||||
...chart.customAttr.label,
|
||||
@ -162,7 +189,12 @@ export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, options: LiquidOptions): LiquidOptions {
|
||||
return flow(this.configTheme, this.configMisc, this.configLabel)(chart, options)
|
||||
return flow(
|
||||
this.configTheme,
|
||||
this.configMisc,
|
||||
this.configLabel,
|
||||
this.configThreshold
|
||||
)(chart, options)
|
||||
}
|
||||
constructor() {
|
||||
super('liquid', DEFAULT_LIQUID_DATA)
|
||||
|
@ -0,0 +1,138 @@
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import {
|
||||
L7ChartView,
|
||||
L7Config,
|
||||
L7DrawConfig,
|
||||
L7Wrapper
|
||||
} from '@/views/chart/components/js/panel/types/impl/l7'
|
||||
import { MAP_EDITOR_PROPERTY_INNER } from '@/views/chart/components/js/panel/charts/map/common'
|
||||
import { flow, parseJson } from '@/views/chart/components/js/util'
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
import { GaodeMap } from '@antv/l7-maps'
|
||||
import { Scene } from '@antv/l7-scene'
|
||||
import { LineLayer } from '@antv/l7-layers'
|
||||
import { queryMapKeyApi } from '@/api/setting/sysParameter'
|
||||
const { t } = useI18n()
|
||||
|
||||
/**
|
||||
* 流向地图
|
||||
*/
|
||||
export class FlowMap extends L7ChartView<Scene, L7Config> {
|
||||
properties: EditorProperty[] = [
|
||||
'background-overall-component',
|
||||
'basic-style-selector',
|
||||
'title-selector'
|
||||
]
|
||||
propertyInner: EditorPropertyInner = {
|
||||
...MAP_EDITOR_PROPERTY_INNER,
|
||||
'basic-style-selector': ['mapStyle', 'zoom']
|
||||
}
|
||||
axis: AxisType[] = ['xAxis', 'xAxisExt', 'filter']
|
||||
axisConfig: AxisConfig = {
|
||||
xAxis: {
|
||||
name: `起点经纬度 / ${t('chart.dimension')}`,
|
||||
type: 'd',
|
||||
limit: 2
|
||||
},
|
||||
xAxisExt: {
|
||||
name: `终点经纬度 / ${t('chart.dimension')}`,
|
||||
type: 'd',
|
||||
limit: 2
|
||||
}
|
||||
}
|
||||
constructor() {
|
||||
super('flow-map', [])
|
||||
}
|
||||
|
||||
async drawChart(drawOption: L7DrawConfig<L7Config>) {
|
||||
const { chart, container } = drawOption
|
||||
const xAxis = deepCopy(chart.xAxis)
|
||||
const xAxisExt = deepCopy(chart.xAxisExt)
|
||||
let basicStyle
|
||||
let miscStyle
|
||||
if (chart.customAttr) {
|
||||
basicStyle = parseJson(chart.customAttr).basicStyle
|
||||
miscStyle = parseJson(chart.customAttr).misc
|
||||
}
|
||||
const flowLineStyle = {
|
||||
type: miscStyle.mapLineType,
|
||||
size: miscStyle.mapLineWidth,
|
||||
animate: miscStyle.mapLineAnimate,
|
||||
animateDuration: miscStyle.mapLineAnimateDuration,
|
||||
gradient: miscStyle.mapLineGradient,
|
||||
sourceColor: miscStyle.mapLineSourceColor,
|
||||
targetColor: miscStyle.mapLineTargetColor,
|
||||
alpha: basicStyle.alpha
|
||||
}
|
||||
const mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}`
|
||||
const key = await this.getMapKey()
|
||||
// 底层
|
||||
const scene = new Scene({
|
||||
id: container,
|
||||
logoVisible: false,
|
||||
map: new GaodeMap({
|
||||
token: key ?? undefined,
|
||||
style: mapStyle,
|
||||
pitch: miscStyle.mapPitch,
|
||||
zoom: 2.5
|
||||
})
|
||||
})
|
||||
if (xAxis?.length < 2 || xAxisExt?.length < 2) {
|
||||
return new L7Wrapper(scene, undefined)
|
||||
}
|
||||
const config: L7Config = new LineLayer({
|
||||
name: 'line',
|
||||
blend: 'normal',
|
||||
autoFit: true
|
||||
})
|
||||
.source(chart.data?.tableRow ? chart.data.tableRow : [], {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: xAxis[0].dataeaseName,
|
||||
y: xAxis[1].dataeaseName,
|
||||
x1: xAxisExt[0].dataeaseName,
|
||||
y1: xAxisExt[1].dataeaseName
|
||||
}
|
||||
})
|
||||
.size(flowLineStyle.size)
|
||||
.shape(flowLineStyle.type)
|
||||
.animate({
|
||||
enable: flowLineStyle.animate,
|
||||
duration: flowLineStyle.animateDuration,
|
||||
interval: 1,
|
||||
trailLength: 1
|
||||
})
|
||||
if (flowLineStyle.gradient) {
|
||||
config.style({
|
||||
sourceColor: flowLineStyle.sourceColor,
|
||||
targetColor: flowLineStyle.targetColor,
|
||||
opacity: flowLineStyle.alpha / 100
|
||||
})
|
||||
} else {
|
||||
config
|
||||
.style({
|
||||
opacity: flowLineStyle.alpha / 100
|
||||
})
|
||||
.color(flowLineStyle.sourceColor)
|
||||
}
|
||||
this.configZoomButton(chart, scene)
|
||||
return new L7Wrapper(scene, config)
|
||||
}
|
||||
|
||||
getMapKey = async () => {
|
||||
const key = 'online-map-key'
|
||||
if (!localStorage.getItem(key)) {
|
||||
await queryMapKeyApi().then(res => localStorage.setItem(key, res.data))
|
||||
}
|
||||
return localStorage.getItem(key)
|
||||
}
|
||||
|
||||
setupDefaultOptions(chart: ChartObj): ChartObj {
|
||||
chart.customAttr.misc.mapLineAnimate = true
|
||||
return chart
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, config: L7Config): L7Config {
|
||||
return flow(this.configEmptyDataStrategy)(chart, config)
|
||||
}
|
||||
}
|
@ -4,9 +4,10 @@ import {
|
||||
} from '@/views/chart/components/js/panel/types/impl/g2plot'
|
||||
import { ScatterOptions, Scatter as G2Scatter } from '@antv/g2plot/esm/plots/scatter'
|
||||
import { flow, parseJson } from '../../../util'
|
||||
import { valueFormatter } from '../../../formatter'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { isEmpty } from 'lodash-es'
|
||||
import { isEmpty, map } from 'lodash-es'
|
||||
import { cloneDeep, defaultTo } from 'lodash-es'
|
||||
|
||||
const { t } = useI18n()
|
||||
/**
|
||||
@ -119,58 +120,40 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
||||
if (!chart.data?.data) {
|
||||
return
|
||||
}
|
||||
const { colorFieldObj, sizeFieldObj, xFieldObj, yFieldObj } = this.getFieldObject(chart)
|
||||
if (!xFieldObj.id || !yFieldObj.id || yFieldObj.id === xFieldObj.id) {
|
||||
return
|
||||
}
|
||||
const data: any[] = []
|
||||
// 根据指标字段对数据列表进行分组
|
||||
const groupedData = chart.data?.data
|
||||
?.filter(item => item['category'] != null)
|
||||
.reduce((result, item) => {
|
||||
;(result[item['field']] = result[item['field']] || []).push(item)
|
||||
return result
|
||||
}, {})
|
||||
// 维度字段数据分组
|
||||
chart.data?.data
|
||||
?.filter(item => item['category'] === null)
|
||||
.forEach(item => {
|
||||
;(groupedData[colorFieldObj.name] = groupedData[colorFieldObj.name] || []).push(
|
||||
item['field']
|
||||
)
|
||||
})
|
||||
// 去掉groupedData每个key中集合的对象重复项
|
||||
Object.keys(groupedData).forEach(key => {
|
||||
groupedData[key] = Array.from(this.getUniqueObjects(groupedData[key]))
|
||||
// data
|
||||
const sourceData: Array<any> = cloneDeep(chart.data.data)
|
||||
const data1 = defaultTo(sourceData[0]?.data, [])
|
||||
const data2 = defaultTo(sourceData[1]?.data, [])
|
||||
const data3 = defaultTo(sourceData[2]?.data, [])
|
||||
const xData = data1.map(item => {
|
||||
return {
|
||||
...item,
|
||||
id: item.quotaList[0]?.id,
|
||||
field: item.field,
|
||||
value: item.value
|
||||
}
|
||||
})
|
||||
// 一个指标字段的数据长度,视为数据长度,也就是有多少数据
|
||||
const dataLength = chart.data?.data.length / chart.data?.fields.length
|
||||
for (let index = 0; index < dataLength; index++) {
|
||||
const tmpData = {
|
||||
dimensionList: groupedData[xFieldObj.name][index].dimensionList,
|
||||
quotaList: groupedData[xFieldObj.name][index].quotaList,
|
||||
[xFieldObj.name]: groupedData[xFieldObj.name][index].value
|
||||
const yData = data2.map(item => {
|
||||
return {
|
||||
...item,
|
||||
id: item.quotaList[0]?.id,
|
||||
field: item.field,
|
||||
value: item.value
|
||||
}
|
||||
if (groupedData[yFieldObj.name]) {
|
||||
tmpData[yFieldObj.name] = groupedData[yFieldObj.name][index].value
|
||||
})
|
||||
const eData = data3.map(item => {
|
||||
return {
|
||||
...item,
|
||||
id: item.quotaList[0]?.id,
|
||||
field: item.field,
|
||||
value: item.value
|
||||
}
|
||||
if (
|
||||
groupedData[sizeFieldObj.name] &&
|
||||
sizeFieldObj.name !== yFieldObj.name &&
|
||||
sizeFieldObj.name !== xFieldObj.name
|
||||
) {
|
||||
tmpData[sizeFieldObj.name] = groupedData[sizeFieldObj.name]?.[index].value
|
||||
}
|
||||
if (groupedData[colorFieldObj.name]) {
|
||||
tmpData[colorFieldObj.name] = groupedData[colorFieldObj.name][index]
|
||||
}
|
||||
data.push(tmpData)
|
||||
}
|
||||
})
|
||||
// x轴基准线 默认值
|
||||
const xValues = data.map(item => item[xFieldObj.name])
|
||||
const xValues = xData.map(item => item.value)
|
||||
const xBaseline = ((Math.max(...xValues) + Math.min(...xValues)) / 2).toFixed()
|
||||
// y轴基准线 默认值
|
||||
const yValues = data.map(item => item[yFieldObj.name])
|
||||
const yValues = yData.map(item => item.value)
|
||||
const yBaseline = ((Math.max(...yValues) + Math.min(...yValues)) / 2).toFixed()
|
||||
const defaultBaselineQuadrant = {
|
||||
...chart.customAttr['quadrant']
|
||||
@ -181,15 +164,25 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
||||
defaultBaselineQuadrant.xBaseline = xBaseline
|
||||
defaultBaselineQuadrant.yBaseline = yBaseline
|
||||
}
|
||||
const colorField = colorFieldObj.name ? { colorField: colorFieldObj.name } : {}
|
||||
const data = map(defaultTo(xData, []), d => {
|
||||
return {
|
||||
...d,
|
||||
yAxis: d.value,
|
||||
quotaList: d.quotaList
|
||||
.concat(yData.find(item => item.field === d.field)?.quotaList)
|
||||
.concat(eData.find(item => item.field === d.field)?.quotaList),
|
||||
yAxisExt: yData.find(item => item.field === d.field)?.value,
|
||||
extBubble: eData.find(item => item.field === d.field)?.value
|
||||
}
|
||||
})
|
||||
const baseOptions: ScatterOptions = {
|
||||
...colorField,
|
||||
colorField: 'field',
|
||||
quadrant: {
|
||||
...defaultBaselineQuadrant
|
||||
},
|
||||
data: data,
|
||||
xField: xFieldObj.name,
|
||||
yField: yFieldObj.name,
|
||||
xField: 'yAxis',
|
||||
yField: 'yAxisExt',
|
||||
appendPadding: 30,
|
||||
pointStyle: {
|
||||
fillOpacity: 0.8,
|
||||
@ -208,12 +201,11 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
||||
protected configBasicStyle(chart: Chart, options: ScatterOptions): ScatterOptions {
|
||||
const customAttr = parseJson(chart.customAttr)
|
||||
const basicStyle = customAttr.basicStyle
|
||||
const extBubbleObj = { id: chart.extBubble[0]?.id, name: chart.extBubble[0]?.['originName'] }
|
||||
if (chart.extBubble?.length) {
|
||||
return {
|
||||
...options,
|
||||
size: [4, 30],
|
||||
sizeField: extBubbleObj.name,
|
||||
sizeField: 'extBubble',
|
||||
shape: basicStyle.scatterSymbol
|
||||
}
|
||||
}
|
||||
@ -296,7 +288,7 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
||||
fontSize: l.fontSize
|
||||
},
|
||||
content: datum => {
|
||||
return datum[chart.xAxis[0]?.['originName']]
|
||||
return datum['name']
|
||||
},
|
||||
layout: [{ type: 'limit-in-shape' }]
|
||||
}
|
||||
@ -326,35 +318,47 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
||||
pre[next['seriesId']] = next
|
||||
return pre
|
||||
}, {}) as Record<string, SeriesFormatter>
|
||||
const optionsData = cloneDeep(options.data)
|
||||
const tooltip: ScatterOptions['tooltip'] = {
|
||||
showTitle: true,
|
||||
title: (_title, datum) => {
|
||||
return datum?.[xAxisTitle['originName']]
|
||||
return datum?.['name']
|
||||
},
|
||||
customItems(originalItems) {
|
||||
if (!tooltipAttr.seriesTooltipFormatter?.length) {
|
||||
return originalItems
|
||||
}
|
||||
const result = []
|
||||
originalItems
|
||||
?.filter(i => i.name !== xAxisTitle['originName'])
|
||||
.forEach(item => {
|
||||
Object.keys(formatterMap).forEach(key => {
|
||||
if (formatterMap[key]['originName'] === item.name) {
|
||||
const formatter = formatterMap[key]
|
||||
if (formatter) {
|
||||
const value =
|
||||
formatter.groupType === 'q'
|
||||
? valueFormatter(parseFloat(item.value as string), formatter.formatterCfg)
|
||||
: item.value
|
||||
const name = isEmpty(formatter.chartShowName)
|
||||
? formatter.name
|
||||
: formatter.chartShowName
|
||||
result.push({ color: item.color, name, value })
|
||||
}
|
||||
originalItems.forEach(item => {
|
||||
Object.keys(formatterMap).forEach(key => {
|
||||
if (key.endsWith(item.name)) {
|
||||
const formatter = formatterMap[key]
|
||||
if (formatter) {
|
||||
const value =
|
||||
formatter.groupType === 'q'
|
||||
? valueFormatter(parseFloat(item.value as string), formatter.formatterCfg)
|
||||
: item.value
|
||||
const name = isEmpty(formatter.chartShowName)
|
||||
? formatter.name
|
||||
: formatter.chartShowName
|
||||
result.push({ color: item.color, name, value })
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
const dynamicTooltipValue = optionsData.find(
|
||||
d => d.field === originalItems[0]['title']
|
||||
)?.dynamicTooltipValue
|
||||
if (dynamicTooltipValue.length > 0) {
|
||||
dynamicTooltipValue.forEach(dy => {
|
||||
const q = tooltipAttr.seriesTooltipFormatter.filter(i => i.id === dy.fieldId)
|
||||
if (q && q.length > 0) {
|
||||
const value = valueFormatter(parseFloat(dy.value as string), q[0].formatterCfg)
|
||||
const name = isEmpty(q[0].chartShowName) ? q[0].name : q[0].chartShowName
|
||||
result.push({ color: 'grey', name, value })
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import type { Plot as L7Plot, PlotOptions } from '@antv/l7plot/dist/esm'
|
||||
import { Zoom } from '@antv/l7'
|
||||
import { createL7Icon } from '@antv/l7-component/es/utils/icon'
|
||||
import { DOM } from '@antv/l7-utils'
|
||||
import { Scene } from '@antv/l7-scene'
|
||||
|
||||
export function getPadding(chart: Chart): number[] {
|
||||
if (chart.drill) {
|
||||
@ -1023,7 +1024,7 @@ class CustomZoom extends Zoom {
|
||||
this['updateDisabled']()
|
||||
}
|
||||
}
|
||||
export function configL7Zoom(chart: Chart, plot: L7Plot<PlotOptions>) {
|
||||
export function configL7Zoom(chart: Chart, plot: L7Plot<PlotOptions> | Scene) {
|
||||
const { basicStyle } = parseJson(chart.customAttr)
|
||||
if (
|
||||
(basicStyle.suspension === false && basicStyle.showZoom === undefined) ||
|
||||
@ -1031,14 +1032,15 @@ export function configL7Zoom(chart: Chart, plot: L7Plot<PlotOptions>) {
|
||||
) {
|
||||
return
|
||||
}
|
||||
plot.once('loaded', () => {
|
||||
const plotScene = plot instanceof Scene ? plot : plot.scene
|
||||
plotScene.once('loaded', () => {
|
||||
const zoomOptions = {
|
||||
initZoom: plot.scene.getZoom(),
|
||||
center: plot.scene.getCenter(),
|
||||
initZoom: plotScene.getZoom(),
|
||||
center: plotScene.getCenter(),
|
||||
buttonColor: basicStyle.zoomButtonColor,
|
||||
buttonBackground: basicStyle.zoomBackground
|
||||
} as any
|
||||
plot.scene.addControl(new CustomZoom(zoomOptions))
|
||||
plotScene.addControl(new CustomZoom(zoomOptions))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,95 @@
|
||||
import { Scene } from '@antv/l7-scene'
|
||||
import {
|
||||
AntVAbstractChartView,
|
||||
AntVDrawOptions,
|
||||
ChartLibraryType,
|
||||
ChartWrapper
|
||||
} from '@/views/chart/components/js/panel/types'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { parseJson } from '@/views/chart/components/js/util'
|
||||
import { ILayer } from '@antv/l7plot'
|
||||
import { configL7Zoom } from '@/views/chart/components/js/panel/common/common_antv'
|
||||
|
||||
export type L7DrawConfig<P> = AntVDrawOptions<P>
|
||||
export interface L7Config extends ILayer {
|
||||
handleConfig?: (arg0: Scene) => void
|
||||
[key: string]: string | any
|
||||
}
|
||||
export class L7Wrapper<
|
||||
O extends L7Config | Array<L7Config>,
|
||||
S extends Scene
|
||||
> extends ChartWrapper<S> {
|
||||
private readonly config: O | Array<O>
|
||||
private readonly scene: S | null = null
|
||||
constructor(scene: S, l7config: O | Array<O> | undefined) {
|
||||
super()
|
||||
this.chartInstance = scene
|
||||
this.config = l7config
|
||||
this.scene = scene
|
||||
}
|
||||
destroy = () => {
|
||||
if (!this.chartInstance) {
|
||||
return
|
||||
}
|
||||
this.chartInstance?.destroy()
|
||||
}
|
||||
render = () => {
|
||||
if (this.scene && this.config) {
|
||||
this.scene.on('loaded', () => {
|
||||
if (Array.isArray(this.config)) {
|
||||
this.config?.forEach(p => {
|
||||
this.handleConfig(p)
|
||||
})
|
||||
} else {
|
||||
this.handleConfig(this.config)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleConfig = (config: L7Config) => {
|
||||
if (config.handleConfig) {
|
||||
config.handleConfig?.(this.scene)
|
||||
} else {
|
||||
this.scene.addLayer(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
export abstract class L7ChartView<
|
||||
S extends Scene,
|
||||
O extends L7Config
|
||||
> extends AntVAbstractChartView {
|
||||
public abstract drawChart(drawOption: L7DrawConfig<O>): L7Wrapper<O, S> | any
|
||||
|
||||
protected configEmptyDataStrategy(chart: Chart, options: O): O {
|
||||
const { functionCfg } = parseJson(chart.senior)
|
||||
const emptyDataStrategy = functionCfg.emptyDataStrategy
|
||||
if (!emptyDataStrategy || emptyDataStrategy === 'breakLine') {
|
||||
return options
|
||||
}
|
||||
const data = cloneDeep(options.sourceOption.data)
|
||||
if (emptyDataStrategy === 'setZero') {
|
||||
data.forEach(item => {
|
||||
item.value === null && (item.value = 0)
|
||||
})
|
||||
}
|
||||
if (emptyDataStrategy === 'ignoreData') {
|
||||
for (let i = data.length - 1; i >= 0; i--) {
|
||||
if (data[i].value === null) {
|
||||
data.splice(i, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
options.sourceOption.data = data
|
||||
return options
|
||||
}
|
||||
|
||||
protected configZoomButton(chart: Chart, plot: S) {
|
||||
configL7Zoom(chart, plot)
|
||||
}
|
||||
|
||||
protected constructor(name: string, defaultData: any[]) {
|
||||
super(ChartLibraryType.L7, name, defaultData)
|
||||
}
|
||||
protected abstract setupOptions(chart: Chart, options: O): O
|
||||
}
|
@ -11,6 +11,7 @@ export enum ChartRenderType {
|
||||
export enum ChartLibraryType {
|
||||
G2_PLOT = 'g2plot',
|
||||
L7_PLOT = 'l7plot',
|
||||
L7 = 'l7',
|
||||
ECHARTS = 'echarts',
|
||||
S2 = 's2',
|
||||
RICH_TEXT = 'rich-text',
|
||||
|
@ -17,9 +17,11 @@ import { customAttrTrans, customStyleTrans, recursionTransObj } from '@/utils/ca
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
import { trackBarStyleCheck } from '@/utils/canvasUtils'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { L7ChartView } from '@/views/chart/components/js/panel/types/impl/l7'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc } = storeToRefs(dvMainStore)
|
||||
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, embeddedCallBack } =
|
||||
storeToRefs(dvMainStore)
|
||||
const { emitter } = useEmitt()
|
||||
const props = defineProps({
|
||||
element: {
|
||||
@ -54,7 +56,13 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['onChartClick', 'onDrillFilters', 'onJumpClick', 'resetLoading'])
|
||||
const emit = defineEmits([
|
||||
'onPointClick',
|
||||
'onChartClick',
|
||||
'onDrillFilters',
|
||||
'onJumpClick',
|
||||
'resetLoading'
|
||||
])
|
||||
|
||||
const { view, showPosition, scale, terminal } = toRefs(props)
|
||||
|
||||
@ -109,7 +117,7 @@ const calcData = async (view, callback) => {
|
||||
callback?.()
|
||||
})
|
||||
} else {
|
||||
if (['bubble-map', 'map'].includes(view.type)) {
|
||||
if (['bubble-map', 'map', 'flow-map'].includes(view.type)) {
|
||||
await renderChart(view, callback)
|
||||
}
|
||||
callback?.()
|
||||
@ -134,6 +142,9 @@ const renderChart = async (view, callback?) => {
|
||||
case ChartLibraryType.L7_PLOT:
|
||||
await renderL7Plot(chart, chartView as L7PlotChartView<any, any>, callback)
|
||||
break
|
||||
case ChartLibraryType.L7:
|
||||
await renderL7(chart, chartView as L7ChartView<any, any>, callback)
|
||||
break
|
||||
case ChartLibraryType.G2_PLOT:
|
||||
renderG2Plot(chart, chartView as G2PlotChartView<any, any>)
|
||||
callback?.()
|
||||
@ -192,9 +203,34 @@ const renderL7Plot = async (chart: ChartObj, chartView: L7PlotChartView<any, any
|
||||
}, 500)
|
||||
}
|
||||
|
||||
let mapL7Timer: number
|
||||
const renderL7 = async (chart: ChartObj, chartView: L7ChartView<any, any>, callback) => {
|
||||
mapL7Timer && clearTimeout(mapL7Timer)
|
||||
mapL7Timer = setTimeout(async () => {
|
||||
myChart?.destroy()
|
||||
myChart = await chartView.drawChart({
|
||||
chartObj: myChart,
|
||||
container: containerId,
|
||||
chart: chart,
|
||||
action
|
||||
})
|
||||
myChart?.render()
|
||||
callback?.()
|
||||
emit('resetLoading')
|
||||
}, 500)
|
||||
}
|
||||
|
||||
const pointClickTrans = () => {
|
||||
if (embeddedCallBack.value === 'yes') {
|
||||
trackClick('pointClick')
|
||||
}
|
||||
}
|
||||
|
||||
const action = param => {
|
||||
// 下钻 联动 跳转
|
||||
state.pointParam = param.data
|
||||
// 点击
|
||||
pointClickTrans()
|
||||
// 下钻 联动 跳转
|
||||
state.linkageActiveParam = {
|
||||
category: state.pointParam.data.category ? state.pointParam.data.category : 'NO_DATA',
|
||||
name: state.pointParam.data.name ? state.pointParam.data.name : 'NO_DATA'
|
||||
@ -246,7 +282,18 @@ const trackClick = trackAction => {
|
||||
quotaList: quotaList
|
||||
}
|
||||
|
||||
const clickParams = {
|
||||
option: 'pointClick',
|
||||
name: checkName,
|
||||
viewId: view.value.id,
|
||||
dimensionList: state.pointParam.data.dimensionList,
|
||||
quotaList: quotaList
|
||||
}
|
||||
|
||||
switch (trackAction) {
|
||||
case 'pointClick':
|
||||
emit('onPointClick', clickParams)
|
||||
break
|
||||
case 'linkageAndDrill':
|
||||
dvMainStore.addViewTrackFilter(linkageParam)
|
||||
emit('onChartClick', param)
|
||||
@ -307,7 +354,7 @@ defineExpose({
|
||||
})
|
||||
let resizeObserver
|
||||
const TOLERANCE = 0.01
|
||||
const RESIZE_MONITOR_CHARTS = ['map', 'bubble-map']
|
||||
const RESIZE_MONITOR_CHARTS = ['map', 'bubble-map', 'flow-map']
|
||||
onMounted(() => {
|
||||
const containerDom = document.getElementById(containerId)
|
||||
const { offsetWidth, offsetHeight } = containerDom
|
||||
|
@ -29,7 +29,7 @@ import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { trackBarStyleCheck } from '@/utils/canvasUtils'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, canvasStyleData } =
|
||||
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, canvasStyleData, embeddedCallBack } =
|
||||
storeToRefs(dvMainStore)
|
||||
const { emitter } = useEmitt()
|
||||
|
||||
@ -66,7 +66,7 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['onChartClick', 'onDrillFilters', 'onJumpClick'])
|
||||
const emit = defineEmits(['onPointClick', 'onChartClick', 'onDrillFilters', 'onJumpClick'])
|
||||
|
||||
const { view, showPosition, scale, terminal } = toRefs(props)
|
||||
|
||||
@ -241,10 +241,17 @@ const handleCurrentChange = pageNum => {
|
||||
const chart = { ...view.value, chartExtRequest: extReq }
|
||||
calcData(chart, null, false)
|
||||
}
|
||||
const pointClickTrans = () => {
|
||||
if (embeddedCallBack.value === 'yes') {
|
||||
trackClick('pointClick')
|
||||
}
|
||||
}
|
||||
|
||||
const action = param => {
|
||||
// 下钻 联动 跳转
|
||||
state.pointParam = param
|
||||
// 点击
|
||||
pointClickTrans()
|
||||
// 下钻 联动 跳转
|
||||
if (trackMenu.value.length < 2) {
|
||||
// 只有一个事件直接调用
|
||||
trackClick(trackMenu.value[0])
|
||||
@ -282,7 +289,19 @@ const trackClick = trackAction => {
|
||||
quotaList: state.pointParam.data.quotaList,
|
||||
sourceType: state.pointParam.data.sourceType
|
||||
}
|
||||
|
||||
const clickParams = {
|
||||
option: 'pointClick',
|
||||
name: state.pointParam.data.name,
|
||||
viewId: view.value.id,
|
||||
dimensionList: state.pointParam.data.dimensionList,
|
||||
quotaList: state.pointParam.data.quotaList
|
||||
}
|
||||
|
||||
switch (trackAction) {
|
||||
case 'pointClick':
|
||||
emit('onPointClick', clickParams)
|
||||
break
|
||||
case 'linkageAndDrill':
|
||||
dvMainStore.addViewTrackFilter(linkageParam)
|
||||
emit('onChartClick', param)
|
||||
|
@ -3,6 +3,7 @@ import { useI18n } from '@/hooks/web/useI18n'
|
||||
import ChartComponentG2Plot from './components/ChartComponentG2Plot.vue'
|
||||
import DeIndicator from '@/custom-component/indicator/DeIndicator.vue'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import { useEmbedded } from '@/store/modules/embedded'
|
||||
import { XpackComponent } from '@/components/plugin'
|
||||
import {
|
||||
computed,
|
||||
@ -47,6 +48,9 @@ const { t } = useI18n()
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
|
||||
let innerRefreshTimer = null
|
||||
const appStore = useAppStoreWithOut()
|
||||
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
|
||||
const isIframe = computed(() => appStore.getIsIframe)
|
||||
|
||||
const { nowPanelJumpInfo, publicLinkStatus, dvInfo, curComponent, canvasStyleData, mobileInPc } =
|
||||
storeToRefs(dvMainStore)
|
||||
@ -101,7 +105,6 @@ const props = defineProps({
|
||||
})
|
||||
const dynamicAreaId = ref('')
|
||||
const { view, showPosition, element, active, searchCount, scale } = toRefs(props)
|
||||
const appStore = useAppStoreWithOut()
|
||||
|
||||
const titleShow = computed(
|
||||
() =>
|
||||
@ -176,6 +179,7 @@ const resultCount = computed(() => {
|
||||
return canvasStyleData.value.dashboard?.resultCount || null
|
||||
})
|
||||
|
||||
const embeddedStore = useEmbedded()
|
||||
// 编辑状态下 不启动刷新
|
||||
const buildInnerRefreshTimer = (
|
||||
refreshViewEnable = false,
|
||||
@ -238,7 +242,6 @@ watch([() => curComponent.value], () => {
|
||||
})
|
||||
}
|
||||
})
|
||||
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
|
||||
|
||||
const chartExtRequest = shallowRef(null)
|
||||
provide('chartExtRequest', chartExtRequest)
|
||||
@ -281,6 +284,21 @@ const drillJump = (index: number) => {
|
||||
calcData(view.value)
|
||||
}
|
||||
|
||||
const onPointClick = param => {
|
||||
try {
|
||||
console.info('de_inner_params send')
|
||||
const msg = {
|
||||
type: 'de_inner_params',
|
||||
sourceDvId: dvInfo.value.id,
|
||||
sourceViewId: view.value.id,
|
||||
message: Base64.encode(param)
|
||||
}
|
||||
window.parent.postMessage(msg, '*')
|
||||
} catch (e) {
|
||||
console.warn('de_inner_params send error')
|
||||
}
|
||||
}
|
||||
|
||||
const chartClick = param => {
|
||||
// 下钻字段第一个没有在维度中不允许下钻
|
||||
const xIds = view.value.xAxis.map(ele => ele.id)
|
||||
@ -332,7 +350,7 @@ const windowsJump = (url, jumpType) => {
|
||||
try {
|
||||
const newWindow = window.open(url, jumpType)
|
||||
initOpenHandler(newWindow)
|
||||
if (jumpType === '_self') {
|
||||
if (jumpType === '_self' && !embeddedStore.baseUrl) {
|
||||
location.reload()
|
||||
}
|
||||
} catch (e) {
|
||||
@ -549,7 +567,7 @@ const chartAreaShow = computed(() => {
|
||||
return true
|
||||
}
|
||||
if (view.value.customAttr.map.id) {
|
||||
const MAP_CHARTS = ['map', 'bubble-map']
|
||||
const MAP_CHARTS = ['map', 'bubble-map', 'flow-map']
|
||||
if (MAP_CHARTS.includes(view.value.type)) {
|
||||
return true
|
||||
}
|
||||
@ -707,9 +725,12 @@ const titleIconStyle = computed(() => {
|
||||
:view="view"
|
||||
:show-position="showPosition"
|
||||
:element="element"
|
||||
v-else-if="showChartView(ChartLibraryType.G2_PLOT, ChartLibraryType.L7_PLOT)"
|
||||
v-else-if="
|
||||
showChartView(ChartLibraryType.G2_PLOT, ChartLibraryType.L7_PLOT, ChartLibraryType.L7)
|
||||
"
|
||||
ref="chartComponent"
|
||||
@onChartClick="chartClick"
|
||||
@onPointClick="onPointClick"
|
||||
@onDrillFilters="onDrillFilters"
|
||||
@onJumpClick="jumpClick"
|
||||
@resetLoading="() => (loading = false)"
|
||||
@ -721,6 +742,7 @@ const titleIconStyle = computed(() => {
|
||||
:element="element"
|
||||
v-else-if="showChartView(ChartLibraryType.S2)"
|
||||
ref="chartComponent"
|
||||
@onPointClick="onPointClick"
|
||||
@onChartClick="chartClick"
|
||||
@onDrillFilters="onDrillFilters"
|
||||
@onJumpClick="jumpClick"
|
||||
|
@ -3,6 +3,7 @@ import { onMounted, reactive, ref, toRefs, watch, nextTick, computed } from 'vue
|
||||
import { copyResource, deleteLogic, ResourceOrFolder } from '@/api/visualization/dataVisualization'
|
||||
import { ElIcon, ElMessage, ElMessageBox, ElScrollbar } from 'element-plus-secondary'
|
||||
import { Icon } from '@/components/icon-custom'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { HandleMore } from '@/components/handle-more'
|
||||
import DeResourceGroupOpt from '@/views/common/DeResourceGroupOpt.vue'
|
||||
import { useEmbedded } from '@/store/modules/embedded'
|
||||
@ -283,11 +284,23 @@ const operation = (cmd: string, data: BusiTreeNode, nodeType: string) => {
|
||||
curCanvasType.value === 'dataV'
|
||||
? `#/dvCanvas?opt=copy&pid=${params.pid}&dvId=${data.data}`
|
||||
: `#/dashboard?opt=copy&pid=${params.pid}&resourceId=${data.data}`
|
||||
let embeddedBaseUrl = ''
|
||||
if (isDataEaseBi.value) {
|
||||
embeddedBaseUrl = embeddedStore.baseUrl
|
||||
embeddedStore.clearState()
|
||||
embeddedStore.setPid(params.pid as string)
|
||||
embeddedStore.setOpt('copy')
|
||||
if (curCanvasType.value === 'dataV') {
|
||||
embeddedStore.setDvId(data.data)
|
||||
} else {
|
||||
embeddedStore.setResourceId(data.data)
|
||||
}
|
||||
useEmitt().emitter.emit(
|
||||
'changeCurrentComponent',
|
||||
curCanvasType.value === 'dataV' ? 'VisualizationEditor' : 'Dashboard'
|
||||
)
|
||||
return
|
||||
}
|
||||
const newWindow = window.open(embeddedBaseUrl + baseUrl, '_blank')
|
||||
|
||||
const newWindow = window.open(baseUrl, '_blank')
|
||||
initOpenHandler(newWindow)
|
||||
})
|
||||
} else {
|
||||
@ -306,14 +319,22 @@ const addOperation = (
|
||||
const baseUrl =
|
||||
curCanvasType.value === 'dataV' ? '#/dvCanvas?opt=create' : '#/dashboard?opt=create'
|
||||
let newWindow = null
|
||||
let embeddedBaseUrl = ''
|
||||
if (isDataEaseBi.value) {
|
||||
embeddedBaseUrl = embeddedStore.baseUrl
|
||||
embeddedStore.clearState()
|
||||
embeddedStore.setOpt('create')
|
||||
if (data?.id) {
|
||||
embeddedStore.setPid(data?.id as string)
|
||||
}
|
||||
useEmitt().emitter.emit(
|
||||
'changeCurrentComponent',
|
||||
curCanvasType.value === 'dataV' ? 'VisualizationEditor' : 'Dashboard'
|
||||
)
|
||||
return
|
||||
}
|
||||
if (data?.id) {
|
||||
newWindow = window.open(embeddedBaseUrl + baseUrl + `&pid=${data.id}`, '_blank')
|
||||
newWindow = window.open(baseUrl + `&pid=${data.id}`, '_blank')
|
||||
} else {
|
||||
newWindow = window.open(embeddedBaseUrl + baseUrl, '_blank')
|
||||
newWindow = window.open(baseUrl, '_blank')
|
||||
}
|
||||
initOpenHandler(newWindow)
|
||||
} else if (cmd === 'newFromTemplate') {
|
||||
@ -334,11 +355,20 @@ function createNewObject() {
|
||||
|
||||
const resourceEdit = resourceId => {
|
||||
const baseUrl = curCanvasType.value === 'dataV' ? '#/dvCanvas?dvId=' : '#/dashboard?resourceId='
|
||||
let embeddedBaseUrl = ''
|
||||
if (isDataEaseBi.value) {
|
||||
embeddedBaseUrl = embeddedStore.baseUrl
|
||||
embeddedStore.clearState()
|
||||
if (curCanvasType.value === 'dataV') {
|
||||
embeddedStore.setDvId(resourceId)
|
||||
} else {
|
||||
embeddedStore.setResourceId(resourceId)
|
||||
}
|
||||
useEmitt().emitter.emit(
|
||||
'changeCurrentComponent',
|
||||
curCanvasType.value === 'dataV' ? 'VisualizationEditor' : 'Dashboard'
|
||||
)
|
||||
return
|
||||
}
|
||||
const newWindow = window.open(embeddedBaseUrl + baseUrl + resourceId, '_blank')
|
||||
const newWindow = window.open(baseUrl + resourceId, '_blank')
|
||||
initOpenHandler(newWindow)
|
||||
}
|
||||
|
||||
@ -354,14 +384,23 @@ const resourceCreateFinish = templateData => {
|
||||
? '#/dvCanvas?opt=create&createType=template'
|
||||
: '#/dashboard?opt=create&createType=template'
|
||||
let newWindow = null
|
||||
let embeddedBaseUrl = ''
|
||||
if (isDataEaseBi.value) {
|
||||
embeddedBaseUrl = embeddedStore.baseUrl
|
||||
embeddedStore.clearState()
|
||||
embeddedStore.setOpt('create')
|
||||
embeddedStore.setCreateType('template')
|
||||
if (state.templateCreatePid) {
|
||||
embeddedStore.setPid(state.templateCreatePid as unknown as string)
|
||||
}
|
||||
useEmitt().emitter.emit(
|
||||
'changeCurrentComponent',
|
||||
curCanvasType.value === 'dataV' ? 'VisualizationEditor' : 'Dashboard'
|
||||
)
|
||||
return
|
||||
}
|
||||
if (state.templateCreatePid) {
|
||||
newWindow = window.open(embeddedBaseUrl + baseUrl + `&pid=${state.templateCreatePid}`, '_blank')
|
||||
newWindow = window.open(baseUrl + `&pid=${state.templateCreatePid}`, '_blank')
|
||||
} else {
|
||||
newWindow = window.open(embeddedBaseUrl + baseUrl, '_blank')
|
||||
newWindow = window.open(baseUrl, '_blank')
|
||||
}
|
||||
initOpenHandler(newWindow)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import { useRequestStoreWithOut } from '@/store/modules/request'
|
||||
import { usePermissionStoreWithOut } from '@/store/modules/permission'
|
||||
import { useMoveLine } from '@/hooks/web/useMoveLine'
|
||||
import { Icon } from '@/components/icon-custom'
|
||||
import { download2AppTemplate, downloadCanvas } from '@/utils/imgUtils'
|
||||
import { download2AppTemplate, downloadCanvas, downloadCanvas2 } from '@/utils/imgUtils'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const previewCanvasContainer = ref(null)
|
||||
@ -98,7 +98,7 @@ const downloadH2 = type => {
|
||||
downloadStatus.value = true
|
||||
nextTick(() => {
|
||||
const vueDom = previewCanvasContainer.value.querySelector('.canvas-container')
|
||||
downloadCanvas(type, vueDom, state.dvInfo.name, () => {
|
||||
downloadCanvas2(type, vueDom, state.dvInfo.name, () => {
|
||||
downloadStatus.value = false
|
||||
})
|
||||
})
|
||||
|
@ -34,7 +34,7 @@ const canvasCacheOutRef = ref(null)
|
||||
const eventCheck = e => {
|
||||
if (e.key === 'panel-weight' && !compareStorage(e.oldValue, e.newValue)) {
|
||||
const resourceId = embeddedStore.resourceId || router.currentRoute.value.query.resourceId
|
||||
const { opt } = router.currentRoute.value.query
|
||||
const opt = embeddedStore.opt || router.currentRoute.value.query.opt
|
||||
if (!(opt && opt === 'create')) {
|
||||
check(wsCache.get('panel-weight'), resourceId as string, 4)
|
||||
}
|
||||
@ -137,6 +137,13 @@ const initLocalCanvasData = () => {
|
||||
dvInfo.value.pid = sourcePid
|
||||
setTimeout(() => {
|
||||
snapshotStore.recordSnapshotCache()
|
||||
// 复制时,初始化的保存按钮为激活状态
|
||||
if (opt === 'copy') {
|
||||
// 使用缓存时,初始化的保存按钮为激活状态
|
||||
setTimeout(() => {
|
||||
snapshotStore.recordSnapshotCache('renderChart')
|
||||
}, 1000)
|
||||
}
|
||||
}, 1500)
|
||||
}
|
||||
})
|
||||
@ -156,7 +163,10 @@ onMounted(async () => {
|
||||
window.addEventListener('storage', eventCheck)
|
||||
const resourceId = embeddedStore.resourceId || router.currentRoute.value.query.resourceId
|
||||
const pid = embeddedStore.pid || router.currentRoute.value.query.pid
|
||||
const { opt, createType, templateParams } = router.currentRoute.value.query
|
||||
const opt = embeddedStore.opt || router.currentRoute.value.query.opt
|
||||
const createType = embeddedStore.createType || router.currentRoute.value.query.createType
|
||||
const templateParams =
|
||||
embeddedStore.templateParams || router.currentRoute.value.query.templateParams
|
||||
const checkResult = await checkPer(resourceId)
|
||||
if (!checkResult) {
|
||||
return
|
||||
@ -269,12 +279,15 @@ onUnmounted(() => {
|
||||
>
|
||||
<DbCanvasAttr></DbCanvasAttr>
|
||||
</dv-sidebar>
|
||||
<div v-show="viewEditorShow" style="height: 100%">
|
||||
<div
|
||||
v-show="viewEditorShow"
|
||||
style="height: 100%"
|
||||
:class="{ 'preview-aside': editMode === 'preview' }"
|
||||
>
|
||||
<view-editor
|
||||
:themes="'light'"
|
||||
:view="canvasViewInfo[curComponent ? curComponent.id : 'default']"
|
||||
:dataset-tree="state.datasetTree"
|
||||
:class="{ 'preview-aside': editMode === 'preview' }"
|
||||
></view-editor>
|
||||
</div>
|
||||
<dv-sidebar
|
||||
|
@ -105,11 +105,12 @@ let p = null
|
||||
const XpackLoaded = () => p(true)
|
||||
onMounted(async () => {
|
||||
await new Promise(r => (p = r))
|
||||
const { dvId, dvType } = router.currentRoute.value.query
|
||||
const { dvId, dvType, callBackFlag } = router.currentRoute.value.query
|
||||
if (dvId) {
|
||||
loadCanvasDataAsync(dvId, dvType)
|
||||
return
|
||||
}
|
||||
dvMainStore.setEmbeddedCallBack(callBackFlag || 'no')
|
||||
dvMainStore.setPublicLinkStatus(props.publicLinkStatus)
|
||||
})
|
||||
|
||||
|
@ -13,7 +13,7 @@ import { useRequestStoreWithOut } from '@/store/modules/request'
|
||||
import { usePermissionStoreWithOut } from '@/store/modules/permission'
|
||||
import { useMoveLine } from '@/hooks/web/useMoveLine'
|
||||
import { Icon } from '@/components/icon-custom'
|
||||
import { download2AppTemplate, downloadCanvas } from '@/utils/imgUtils'
|
||||
import { download2AppTemplate, downloadCanvas, downloadCanvas2 } from '@/utils/imgUtils'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { dvInfo } = storeToRefs(dvMainStore)
|
||||
@ -86,7 +86,7 @@ const download = type => {
|
||||
downloadStatus.value = true
|
||||
setTimeout(() => {
|
||||
const vueDom = previewCanvasContainer.value.querySelector('.canvas-container')
|
||||
downloadCanvas(type, vueDom, state.dvInfo.name, () => {
|
||||
downloadCanvas2(type, vueDom, state.dvInfo.name, () => {
|
||||
downloadStatus.value = false
|
||||
})
|
||||
}, 200)
|
||||
|
@ -43,7 +43,7 @@ const embeddedStore = useEmbedded()
|
||||
const { wsCache } = useCache()
|
||||
const eventCheck = e => {
|
||||
if (e.key === 'screen-weight' && !compareStorage(e.oldValue, e.newValue)) {
|
||||
const { opt } = router.currentRoute.value.query
|
||||
const opt = embeddedStore.opt || router.currentRoute.value.query.opt
|
||||
if (!(opt && opt === 'create')) {
|
||||
check(
|
||||
wsCache.get('screen-weight'),
|
||||
@ -270,7 +270,10 @@ onMounted(async () => {
|
||||
}
|
||||
const dvId = embeddedStore.dvId || router.currentRoute.value.query.dvId
|
||||
const pid = embeddedStore.pid || router.currentRoute.value.query.pid
|
||||
const { opt, createType, templateParams } = router.currentRoute.value.query
|
||||
const templateParams =
|
||||
embeddedStore.templateParams || router.currentRoute.value.query.templateParams
|
||||
const createType = embeddedStore.createType || router.currentRoute.value.query.createType
|
||||
const opt = embeddedStore.opt || router.currentRoute.value.query.opt
|
||||
const checkResult = await checkPer(dvId)
|
||||
if (!checkResult) {
|
||||
return
|
||||
@ -429,12 +432,15 @@ eventBus.on('handleNew', handleNew)
|
||||
>
|
||||
<canvas-attr></canvas-attr>
|
||||
</dv-sidebar>
|
||||
<div v-show="viewsPropertiesShow" style="height: 100%">
|
||||
<div
|
||||
v-show="viewsPropertiesShow"
|
||||
style="height: 100%"
|
||||
:class="{ 'preview-aside': editMode === 'preview' }"
|
||||
>
|
||||
<editor
|
||||
:view="canvasViewInfo[curComponent ? curComponent.id : 'default']"
|
||||
themes="dark"
|
||||
:dataset-tree="state.datasetTree"
|
||||
:class="{ 'preview-aside': editMode === 'preview' }"
|
||||
></editor>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -327,6 +327,10 @@ const expChangeHandler = exp => {
|
||||
})
|
||||
}
|
||||
const beforeClose = async done => {
|
||||
if (!shareEnable.value) {
|
||||
done()
|
||||
return
|
||||
}
|
||||
const pwdValid = validatePwdFormat()
|
||||
const uuidValid = await validateUuid()
|
||||
if (pwdValid && uuidValid) {
|
||||
|
@ -167,6 +167,10 @@ watch(
|
||||
}
|
||||
)
|
||||
const hideShare = async () => {
|
||||
if (!shareEnable.value) {
|
||||
popoverVisible.value = false
|
||||
return
|
||||
}
|
||||
const pwdValid = validatePwdFormat()
|
||||
const uuidValid = await validateUuid()
|
||||
if (pwdValid && uuidValid) {
|
||||
|
@ -174,6 +174,7 @@ import { imgUrlTrans } from '@/utils/imgUtils'
|
||||
import CategoryTemplateV2 from '@/views/template-market/component/CategoryTemplateV2.vue'
|
||||
import { interactiveStoreWithOut } from '@/store/modules/interactive'
|
||||
import { XpackComponent } from '@/components/plugin'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { Base64 } from 'js-base64'
|
||||
const { t } = useI18n()
|
||||
const { wsCache } = useCache()
|
||||
@ -434,14 +435,29 @@ const apply = template => {
|
||||
'&templateParams=' +
|
||||
encodeURIComponent(Base64.encode(JSON.stringify(templateTemplate)))
|
||||
let newWindow = null
|
||||
let embeddedBaseUrl = ''
|
||||
if (isDataEaseBi.value) {
|
||||
embeddedBaseUrl = embeddedStore.baseUrl
|
||||
embeddedStore.clearState()
|
||||
embeddedStore.setCreateType('template')
|
||||
embeddedStore.setTemplateParams(
|
||||
encodeURIComponent(Base64.encode(JSON.stringify(templateTemplate)))
|
||||
)
|
||||
embeddedStore.setOpt('create')
|
||||
|
||||
if (state.pid) {
|
||||
embeddedStore.setPid(state.pid)
|
||||
}
|
||||
useEmitt().emitter.emit(
|
||||
'changeCurrentComponent',
|
||||
['dataV', 'SCREEN'].includes(state.dvCreateForm.nodeType)
|
||||
? 'VisualizationEditor'
|
||||
: 'Dashboard'
|
||||
)
|
||||
return
|
||||
}
|
||||
if (state.pid) {
|
||||
newWindow = window.open(embeddedBaseUrl + baseUrl + `&pid=${state.pid}`, '_blank')
|
||||
newWindow = window.open(baseUrl + `&pid=${state.pid}`, '_blank')
|
||||
} else {
|
||||
newWindow = window.open(embeddedBaseUrl + baseUrl, '_blank')
|
||||
newWindow = window.open(baseUrl, '_blank')
|
||||
}
|
||||
initOpenHandler(newWindow)
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ const confirmCustomTime = () => {
|
||||
}
|
||||
|
||||
watch(searchTable, val => {
|
||||
state.tableData = tableList.filter(ele => ele.name.toLowerCase().includes(val.toLowerCase()))
|
||||
state.tableData = tableList.filter(ele => ele.tableName.toLowerCase().includes(val.toLowerCase()))
|
||||
})
|
||||
const editeSave = () => {
|
||||
const union = []
|
||||
|
@ -693,7 +693,10 @@ defineExpose({
|
||||
<el-option v-for="item in schemas" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('datasource.extra_params')">
|
||||
<el-form-item
|
||||
:label="t('datasource.extra_params')"
|
||||
v-if="form.configuration.urlType !== 'jdbcUrl'"
|
||||
>
|
||||
<el-input
|
||||
:placeholder="t('common.inputText') + t('datasource.extra_params')"
|
||||
v-model="form.configuration.extraParams"
|
||||
@ -760,7 +763,7 @@ defineExpose({
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="form.type == 'oracle'"
|
||||
v-if="form.type == 'oracle' && form.configuration.urlType !== 'jdbcUrl'"
|
||||
:label="t('datasource.connection_mode')"
|
||||
prop="configuration.connectionType"
|
||||
>
|
||||
|
@ -1073,7 +1073,7 @@ const getMenuList = (val: boolean) => {
|
||||
placement="top"
|
||||
>
|
||||
<el-button
|
||||
@click.stop="createDataset(scope.row.name)"
|
||||
@click.stop="createDataset(scope.row.tableName)"
|
||||
text
|
||||
v-permission="['dataset']"
|
||||
>
|
||||
|
2
de-xpack
@ -1 +1 @@
|
||||
Subproject commit eac4bdc0d387c44088dbc7585a09f61b8e45ea12
|
||||
Subproject commit 690faa2e32bf71f23fdda04a83c3b7a1ed0d368c
|
53
pom.xml
@ -11,15 +11,19 @@
|
||||
<modules>
|
||||
<module>sdk</module>
|
||||
</modules>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<dataease.version>2.6.1</dataease.version>
|
||||
<java.version>17</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version>
|
||||
<spring-cloud.version>2022.0.0</spring-cloud.version>
|
||||
<spring-boot.version>3.0.2</spring-boot.version>
|
||||
<maven-compiler-plugin.version>3.9.0</maven-compiler-plugin.version>
|
||||
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
|
||||
<spring-cloud.version>2023.0.1</spring-cloud.version>
|
||||
<spring-boot.version>3.3.0</spring-boot.version>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<mybatis-plus.version>3.5.6</mybatis-plus.version>
|
||||
@ -30,17 +34,13 @@
|
||||
<antlr.version>3.5.2</antlr.version>
|
||||
<java-jwt.version>3.12.1</java-jwt.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<maven.antrun.version>3.1.0</maven.antrun.version>
|
||||
<ehcache.version>3.10.8</ehcache.version>
|
||||
<bcprov.version>1.78</bcprov.version>
|
||||
<junit.version>4.13.2</junit.version>
|
||||
<httpclient.version>4.5.14</httpclient.version>
|
||||
<httpcore.version>4.4.16</httpcore.version>
|
||||
<easyexcel.version>3.3.2</easyexcel.version>
|
||||
<maven.surefire.version>3.1.2</maven.surefire.version>
|
||||
<maven.clean.version>3.2.0</maven.clean.version>
|
||||
<easyexcel.version>3.3.4</easyexcel.version>
|
||||
<flatten-maven.version>1.3.0</flatten-maven.version>
|
||||
<maven.resources.version>3.3.1</maven.resources.version>
|
||||
<maven.exec.version>3.1.0</maven.exec.version>
|
||||
<guava.version>33.0.0-jre</guava.version>
|
||||
<selenium-java.version>4.19.1</selenium-java.version>
|
||||
@ -48,6 +48,7 @@
|
||||
<mysql-connector-j.version>8.2.0</mysql-connector-j.version>
|
||||
<itextpdf.version>8.0.4</itextpdf.version>
|
||||
<flexmark.version>0.62.2</flexmark.version>
|
||||
<mybatis-spring.version>3.0.3</mybatis-spring.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -73,6 +74,11 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
<version>${mybatis-spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
@ -144,35 +150,6 @@
|
||||
<version>${spring-boot.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>${maven.antrun.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven.surefire.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>${maven.clean.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>${maven.resources.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
|
@ -0,0 +1,41 @@
|
||||
package io.dataease.api.exportCenter;
|
||||
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.dataease.api.exportCenter.vo.ExportTaskDTO;
|
||||
import io.dataease.auth.DeApiPath;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.dataease.constant.AuthResourceEnum.DATASOURCE;
|
||||
|
||||
@Tag(name = "数据导出中心")
|
||||
@ApiSupport(order = 971)
|
||||
@DeApiPath(value = "/exportCenter", rt = DATASOURCE)
|
||||
public interface ExportCenterApi {
|
||||
|
||||
|
||||
@PostMapping("/exportTasks/{status}")
|
||||
public List<ExportTaskDTO> exportTasks(@PathVariable String status) ;
|
||||
|
||||
@GetMapping("/delete/{id}")
|
||||
public void delete(@PathVariable String id);
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestBody List<String> ids);
|
||||
|
||||
@PostMapping("/deleteAll/{type}")
|
||||
public void deleteAll(@PathVariable String type);
|
||||
|
||||
@GetMapping("/download/{id}")
|
||||
public void download(@PathVariable String id, HttpServletResponse response) throws Exception ;
|
||||
|
||||
@PostMapping("/retry/{id}")
|
||||
public void retry(@PathVariable String id);
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package io.dataease.api.exportCenter.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ExportTaskDTO {
|
||||
@JsonSerialize(using= ToStringSerializer.class)
|
||||
private String id;
|
||||
@JsonSerialize(using= ToStringSerializer.class)
|
||||
private Long userId;
|
||||
|
||||
private String fileName;
|
||||
|
||||
private Double fileSize;
|
||||
|
||||
private String fileSizeUnit;
|
||||
|
||||
private String exportFrom;
|
||||
|
||||
private String exportStatus;
|
||||
|
||||
private String exportFromType;
|
||||
|
||||
private Long exportTime;
|
||||
|
||||
private String exportProgress;
|
||||
|
||||
private String exportMachineName;
|
||||
|
||||
private String exportFromName;
|
||||
}
|
@ -93,8 +93,14 @@ public class HttpClientUtil {
|
||||
httpGet.addHeader(key, header.get(key));
|
||||
}
|
||||
HttpResponse response = httpClient.execute(httpGet);
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
return statusCode <= 400;
|
||||
if (response.getStatusLine().getStatusCode() >= 400) {
|
||||
String msg = EntityUtils.toString(response.getEntity(), config.getCharset());
|
||||
if (StringUtils.isEmpty(msg)) {
|
||||
msg = "StatusCode: " + response.getStatusLine().getStatusCode();
|
||||
}
|
||||
throw new Exception(msg);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error("HttpClient查询失败", e);
|
||||
throw new DEException(SYSTEM_INNER_ERROR.code(), "HttpClient查询失败: " + e.getMessage());
|
||||
|