merge: 合并代码解决冲突

This commit is contained in:
fit2cloud-chenyw 2024-11-12 17:34:07 +08:00
commit 3b7dd01eb9
220 changed files with 5293 additions and 1629 deletions

28
.github/workflows/llm-code-review.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: LLM Code Review
permissions:
contents: read
pull-requests: write
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
llm-code-review:
runs-on: ubuntu-latest
steps:
- uses: fit2cloud/LLM-CodeReview-Action@main
env:
GITHUB_TOKEN: ${{ secrets.FIT2CLOUDRD_LLM_CODE_REVIEW_TOKEN }}
OPENAI_API_KEY: ${{ secrets.ALIYUN_LLM_API_KEY }}
LANGUAGE: Chinese
OPENAI_API_ENDPOINT: https://dashscope.aliyuncs.com/compatible-mode/v1
MODEL: qwen2-1.5b-instruct
PROMPT: "请检查下面的代码差异是否有不规范、潜在的问题或者优化建议,用中文回答。"
top_p: 1
temperature: 1
# max_tokens: 10000
MAX_PATCH_LENGTH: 10000
IGNORE_PATTERNS: "/node_modules,*.md,/dist,/.github"
FILE_PATTERNS: "*.java,*.go,*.py,*.vue,*.ts,*.js,*.css,*.scss,*.html"

View File

@ -11,13 +11,12 @@
## 什么是 DataEase ## 什么是 DataEase
DataEase 是开源的数据可视化分析工具帮助用户快速分析数据并洞察业务趋势从而实现业务的改进与优化DataEase 支持丰富的数据源连接能够通过拖拉拽方式快速制作图表并可以方便的与他人分享 DataEase 是开源的 BI 工具帮助用户快速分析数据并洞察业务趋势从而实现业务的改进与优化DataEase 支持丰富的数据源连接能够通过拖拉拽方式快速制作图表并可以方便的与他人分享
**DataEase 的优势** **DataEase 的优势**
- 开源开放零门槛线上快速获取和安装按月迭代 - 开源开放零门槛线上快速获取和安装按月迭代
- 简单易用极易上手通过鼠标点击和拖拽即可完成分析 - 简单易用极易上手通过鼠标点击和拖拽即可完成分析
- AI Copilot借助生成式 AI 技术通过自然语言交互实现数据即问即答
- 全场景支持多平台安装和多样化嵌入支持 - 全场景支持多平台安装和多样化嵌入支持
- 安全分享支持多种数据分享方式确保数据安全 - 安全分享支持多种数据分享方式确保数据安全
@ -29,6 +28,8 @@ DataEase 是开源的数据可视化分析工具,帮助用户快速分析数
- 数据文件 ExcelCSV - 数据文件 ExcelCSV
- API 数据源 - API 数据源
如果您需要向团队介绍 DataEase可以使用这个 [官方 PPT 材料](https://fit2cloud.com/dataease/download/introduce-dataease_202411.pdf)
## 快速开始 ## 快速开始
``` ```

View File

@ -131,6 +131,22 @@
<artifactId>flexmark-all</artifactId> <artifactId>flexmark-all</artifactId>
<version>${flexmark.version}</version> <version>${flexmark.version}</version>
</dependency> </dependency>
<dependency>
<groupId>io.dataease</groupId>
<artifactId>xpack-base</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.dataease</groupId>
<artifactId>xpack-permissions</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.dataease</groupId>
<artifactId>xpack-sync</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -11,16 +11,20 @@ import io.dataease.engine.sql.SQLProvider;
import io.dataease.engine.trans.Dimension2SQLObj; import io.dataease.engine.trans.Dimension2SQLObj;
import io.dataease.engine.trans.Quota2SQLObj; import io.dataease.engine.trans.Quota2SQLObj;
import io.dataease.engine.utils.Utils; import io.dataease.engine.utils.Utils;
import io.dataease.exception.DEException;
import io.dataease.extensions.datasource.api.PluginManageApi; import io.dataease.extensions.datasource.api.PluginManageApi;
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO; import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
import io.dataease.extensions.datasource.dto.DatasourceRequest; import io.dataease.extensions.datasource.dto.DatasourceRequest;
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO; import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
import io.dataease.extensions.datasource.model.SQLMeta; import io.dataease.extensions.datasource.model.SQLMeta;
import io.dataease.extensions.datasource.provider.Provider; import io.dataease.extensions.datasource.provider.Provider;
import io.dataease.extensions.datasource.vo.DatasourceConfiguration;
import io.dataease.extensions.datasource.vo.XpackPluginsDatasourceVO;
import io.dataease.extensions.view.dto.*; import io.dataease.extensions.view.dto.*;
import io.dataease.extensions.view.plugin.AbstractChartPlugin; import io.dataease.extensions.view.plugin.AbstractChartPlugin;
import io.dataease.extensions.view.util.ChartDataUtil; import io.dataease.extensions.view.util.ChartDataUtil;
import io.dataease.extensions.view.util.FieldUtil; import io.dataease.extensions.view.util.FieldUtil;
import io.dataease.license.utils.LicenseUtil;
import io.dataease.utils.BeanUtils; import io.dataease.utils.BeanUtils;
import io.dataease.utils.JsonUtil; import io.dataease.utils.JsonUtil;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
@ -364,14 +368,45 @@ public class DefaultChartHandler extends AbstractChartPlugin {
return conditionField; return conditionField;
} }
protected String assistSQL(String sql, List<ChartViewFieldDTO> assistFields) { protected String assistSQL(String sql, List<ChartViewFieldDTO> assistFields, Map<Long, DatasourceSchemaDTO> dsMap) {
// get datasource prefix and suffix
String dsType = dsMap.entrySet().iterator().next().getValue().getType();
String prefix = "";
String suffix = "";
if (Arrays.stream(DatasourceConfiguration.DatasourceType.values()).map(DatasourceConfiguration.DatasourceType::getType).toList().contains(dsType)) {
DatasourceConfiguration.DatasourceType datasourceType = DatasourceConfiguration.DatasourceType.valueOf(dsType);
prefix = datasourceType.getPrefix();
suffix = datasourceType.getSuffix();
} else {
if (LicenseUtil.licenseValid()) {
List<XpackPluginsDatasourceVO> xpackPluginsDatasourceVOS = pluginManage.queryPluginDs();
List<XpackPluginsDatasourceVO> list = xpackPluginsDatasourceVOS.stream().filter(ele -> StringUtils.equals(ele.getType(), dsType)).toList();
if (ObjectUtils.isNotEmpty(list)) {
XpackPluginsDatasourceVO first = list.getFirst();
prefix = first.getPrefix();
suffix = first.getSuffix();
} else {
DEException.throwException("当前数据源插件不存在");
}
}
}
boolean crossDs = Utils.isCrossDs(dsMap);
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < assistFields.size(); i++) { for (int i = 0; i < assistFields.size(); i++) {
ChartViewFieldDTO dto = assistFields.get(i); ChartViewFieldDTO dto = assistFields.get(i);
if (i == (assistFields.size() - 1)) { if (crossDs) {
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + ")"); if (i == (assistFields.size() - 1)) {
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + ")");
} else {
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + "),");
}
} else { } else {
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + "),"); if (i == (assistFields.size() - 1)) {
stringBuilder.append(dto.getSummary() + "(" + prefix + dto.getOriginName() + suffix + ")");
} else {
stringBuilder.append(dto.getSummary() + "(" + prefix + dto.getOriginName() + suffix + "),");
}
} }
} }
return "SELECT " + stringBuilder + " FROM (" + sql + ") tmp"; return "SELECT " + stringBuilder + " FROM (" + sql + ") tmp";

View File

@ -53,7 +53,7 @@ public class BarHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) { if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest(); var req = new DatasourceRequest();
req.setDsList(dsMap); req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields); var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql); req.setQuery(assistSql);
logger.debug("calcite assistSql sql: " + assistSql); logger.debug("calcite assistSql sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data"); var assistData = (List<String[]>) provider.fetchResultField(req).get("data");

View File

@ -52,10 +52,10 @@ public class StackBarHandler extends BarHandler {
if (ObjectUtils.isNotEmpty(extStack) && if (ObjectUtils.isNotEmpty(extStack) &&
Objects.equals(drillFields.get(0).getId(), extStack.get(0).getId())) { Objects.equals(drillFields.get(0).getId(), extStack.get(0).getId())) {
fieldsToFilter.addAll(view.getXAxis()); fieldsToFilter.addAll(view.getXAxis());
groupStackDrill(noDrillFieldAxis, noDrillFilterList, fieldsToFilter, drillFields, drillRequestList);
formatResult.getAxisMap().put(ChartAxis.xAxis, noDrillFieldAxis);
result.setFilterList(noDrillFilterList);
} }
groupStackDrill(noDrillFieldAxis, noDrillFilterList, fieldsToFilter, drillFields, drillRequestList);
formatResult.getAxisMap().put(ChartAxis.xAxis, noDrillFieldAxis);
result.setFilterList(noDrillFilterList);
} }
return (T) result; return (T) result;
} }

View File

@ -64,7 +64,7 @@ public class LineHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) { if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest(); var req = new DatasourceRequest();
req.setDsList(dsMap); req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields); var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql); req.setQuery(assistSql);
logger.debug("calcite assistSql sql: " + assistSql); logger.debug("calcite assistSql sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data"); var assistData = (List<String[]>) provider.fetchResultField(req).get("data");

View File

@ -100,7 +100,7 @@ public class StackAreaHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) { if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest(); var req = new DatasourceRequest();
req.setDsList(dsMap); req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields); var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql); req.setQuery(assistSql);
logger.debug("calcite assist sql: " + assistSql); logger.debug("calcite assist sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data"); var assistData = (List<String[]>) provider.fetchResultField(req).get("data");

View File

@ -92,7 +92,7 @@ public class MixHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) { if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest(); var req = new DatasourceRequest();
req.setDsList(dsMap); req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields); var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql); req.setQuery(assistSql);
logger.debug("calcite assistSql sql: " + assistSql); logger.debug("calcite assistSql sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data"); var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
@ -144,7 +144,7 @@ public class MixHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) { if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest(); var req = new DatasourceRequest();
req.setDsList(dsMap); req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields); var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql); req.setQuery(assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data"); var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
rightResult.setAssistData(assistData); rightResult.setAssistData(assistData);

View File

@ -98,7 +98,7 @@ public class TableInfoHandler extends DefaultChartHandler {
} }
} }
assert fieldDTO != null; assert fieldDTO != null;
if (fieldDTO.isAgg()) { if (fieldDTO != null && fieldDTO.isAgg()) {
sqlMeta.getXFields().get(i).setFieldName("'-'"); sqlMeta.getXFields().get(i).setFieldName("'-'");
} }
} }
@ -154,7 +154,7 @@ public class TableInfoHandler extends DefaultChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) { if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest(); var req = new DatasourceRequest();
req.setDsList(dsMap); req.setDsList(dsMap);
var assistSql = assistSQL(querySql, assistFields); var assistSql = assistSQL(querySql, assistFields, dsMap);
req.setQuery(assistSql); req.setQuery(assistSql);
logger.debug("calcite assistSql sql: " + assistSql); logger.debug("calcite assistSql sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data"); var assistData = (List<String[]>) provider.fetchResultField(req).get("data");

View File

@ -34,7 +34,7 @@ public class TableNormalHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) { if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest(); var req = new DatasourceRequest();
req.setDsList(dsMap); req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields); var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql); req.setQuery(assistSql);
logger.debug("calcite assistSql sql: " + assistSql); logger.debug("calcite assistSql sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data"); var assistData = (List<String[]>) provider.fetchResultField(req).get("data");

View File

@ -33,7 +33,7 @@ public class TablePivotHandler extends GroupChartHandler {
@Override @Override
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider provider) { public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider provider) {
T result = super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider); T result = super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider);
Map<String, Object> customCalc = calcCustomExpr(view, filterResult, sqlMap, sqlMeta, provider); Map<String, Object> customCalc = calcCustomExpr(view, filterResult, sqlMap, sqlMeta, provider);
result.getData().put("customCalc", customCalc); result.getData().put("customCalc", customCalc);
try { try {
@ -45,7 +45,7 @@ public class TablePivotHandler extends GroupChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) { if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest(); var req = new DatasourceRequest();
req.setDsList(dsMap); req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields); var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql); req.setQuery(assistSql);
logger.debug("calcite assistSql sql: " + assistSql); logger.debug("calcite assistSql sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data"); var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
@ -98,7 +98,7 @@ public class TablePivotHandler extends GroupChartHandler {
var tmpData = new ArrayList<Map<String, Object>>(); var tmpData = new ArrayList<Map<String, Object>>();
dataMap.put("rowSubTotal", tmpData); dataMap.put("rowSubTotal", tmpData);
for (int i = 0; i < rowAxis.size(); i++) { for (int i = 0; i < rowAxis.size(); i++) {
if ( i == rowAxis.size() - 1) { if (i == rowAxis.size() - 1) {
break; break;
} }
var xAxis = new ArrayList<>(colAxis); var xAxis = new ArrayList<>(colAxis);
@ -137,7 +137,7 @@ public class TablePivotHandler extends GroupChartHandler {
var tmpData = new ArrayList<Map<String, Object>>(); var tmpData = new ArrayList<Map<String, Object>>();
dataMap.put("colSubTotal", tmpData); dataMap.put("colSubTotal", tmpData);
for (int i = 0; i < colAxis.size(); i++) { for (int i = 0; i < colAxis.size(); i++) {
if ( i == colAxis.size() - 1) { if (i == colAxis.size() - 1) {
break; break;
} }
var xAxis = new ArrayList<>(rowAxis); var xAxis = new ArrayList<>(rowAxis);
@ -181,7 +181,7 @@ public class TablePivotHandler extends GroupChartHandler {
var tmpData = new ArrayList<Map<String, Object>>(); var tmpData = new ArrayList<Map<String, Object>>();
dataMap.put("colSubInRowTotal", tmpData); dataMap.put("colSubInRowTotal", tmpData);
for (int i = 0; i < colAxis.size(); i++) { for (int i = 0; i < colAxis.size(); i++) {
if ( i == colAxis.size() - 1) { if (i == colAxis.size() - 1) {
break; break;
} }
var xAxis = colAxis.subList(0, i + 1); var xAxis = colAxis.subList(0, i + 1);
@ -202,7 +202,7 @@ public class TablePivotHandler extends GroupChartHandler {
var tmpData = new ArrayList<Map<String, Object>>(); var tmpData = new ArrayList<Map<String, Object>>();
dataMap.put("rowSubInColTotal", tmpData); dataMap.put("rowSubInColTotal", tmpData);
for (int i = 0; i < rowAxis.size(); i++) { for (int i = 0; i < rowAxis.size(); i++) {
if ( i == rowAxis.size() - 1) { if (i == rowAxis.size() - 1) {
break; break;
} }
var xAxis = rowAxis.subList(0, i + 1); var xAxis = rowAxis.subList(0, i + 1);
@ -223,7 +223,7 @@ public class TablePivotHandler extends GroupChartHandler {
var tmpData = new ArrayList<List<Map<String, Object>>>(); var tmpData = new ArrayList<List<Map<String, Object>>>();
dataMap.put("rowSubInColSub", tmpData); dataMap.put("rowSubInColSub", tmpData);
for (int i = 0; i < rowAxis.size(); i++) { for (int i = 0; i < rowAxis.size(); i++) {
if ( i == rowAxis.size() - 1) { if (i == rowAxis.size() - 1) {
break; break;
} }
var tmpList = new ArrayList<Map<String, Object>>(); var tmpList = new ArrayList<Map<String, Object>>();
@ -231,7 +231,7 @@ public class TablePivotHandler extends GroupChartHandler {
var subRow = rowAxis.subList(0, i + 1); var subRow = rowAxis.subList(0, i + 1);
var xAxis = new ArrayList<>(subRow); var xAxis = new ArrayList<>(subRow);
for (int j = 0; j < colAxis.size(); j++) { for (int j = 0; j < colAxis.size(); j++) {
if ( j == colAxis.size() - 1) { if (j == colAxis.size() - 1) {
break; break;
} }
var subCol = colAxis.subList(0, j + 1); var subCol = colAxis.subList(0, j + 1);
@ -284,8 +284,8 @@ public class TablePivotHandler extends GroupChartHandler {
} }
private Tuple2<String, List<String[]>> getData(SQLMeta sqlMeta, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, private Tuple2<String, List<String[]>> getData(SQLMeta sqlMeta, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis,
List<ChartViewFieldDTO> allFields, boolean crossDs, Map<Long, DatasourceSchemaDTO> dsMap, List<ChartViewFieldDTO> allFields, boolean crossDs, Map<Long, DatasourceSchemaDTO> dsMap,
ChartViewDTO view, Provider provider, boolean needOrder) { ChartViewDTO view, Provider provider, boolean needOrder) {
DatasourceRequest datasourceRequest = new DatasourceRequest(); DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setDsList(dsMap); datasourceRequest.setDsList(dsMap);
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage); Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
@ -298,6 +298,7 @@ public class TablePivotHandler extends GroupChartHandler {
nullToBlank(data); nullToBlank(data);
return Tuples.of(querySql, data); return Tuples.of(querySql, data);
} }
private void nullToBlank(List<String[]> data) { private void nullToBlank(List<String[]> data) {
data.forEach(r -> { data.forEach(r -> {
for (int i = 0; i < r.length; i++) { for (int i = 0; i < r.length; i++) {
@ -315,7 +316,7 @@ public class TablePivotHandler extends GroupChartHandler {
if (!quotaIds.contains(totalCfg.getDataeaseName())) { if (!quotaIds.contains(totalCfg.getDataeaseName())) {
continue; continue;
} }
if (StringUtils.equalsIgnoreCase(totalCfg.getAggregation(), "CUSTOM")){ if (StringUtils.equalsIgnoreCase(totalCfg.getAggregation(), "CUSTOM")) {
var field = new ChartViewFieldDTO(); var field = new ChartViewFieldDTO();
field.setDeType(DeTypeConstants.DE_FLOAT); field.setDeType(DeTypeConstants.DE_FLOAT);
BeanUtils.copyBean(field, totalCfg); BeanUtils.copyBean(field, totalCfg);

View File

@ -316,6 +316,11 @@ public class ChartDataManage {
dillAxis.add(nextDrillField); dillAxis.add(nextDrillField);
fields.add(nextDrillField.getId()); fields.add(nextDrillField.getId());
} else { } else {
Optional<ChartViewFieldDTO> axis = xAxis.stream().filter(x -> Objects.equals(x.getId(), nextDrillField.getId())).findFirst();
axis.ifPresent(field -> {
field.setSort(nextDrillField.getSort());
field.setCustomSort(nextDrillField.getCustomSort());
});
dillAxis.add(nextDrillField); dillAxis.add(nextDrillField);
} }
} }

View File

@ -362,9 +362,9 @@ public class ChartViewThresholdManage {
} }
} else { } else {
if (timeFlag == 4) { if (timeFlag == 4) {
return now.withDayOfMonth(1).format(formatter); return now.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).format(formatter);
} else if (timeFlag == 5) { } else if (timeFlag == 5) {
return now.plusMonths(1).withDayOfMonth(1).minusDays(1).format(formatter); return now.plusMonths(1).withDayOfMonth(1).minusDays(1).withHour(0).withMinute(0).withSecond(0).format(formatter);
} else { } else {
return getCustomTimeValue(format, 3, suffix, count, true); return getCustomTimeValue(format, 3, suffix, count, true);
} }
@ -381,7 +381,9 @@ public class ChartViewThresholdManage {
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
String fullFormat = "yyyy-MM-dd HH:mm:ss"; String fullFormat = "yyyy-MM-dd HH:mm:ss";
int len = format.length(); int len = format.length();
if (!hasTime) { if (hasTime) {
now = now.withHour(0).withMinute(0).withSecond(0);
} else {
len = Math.min(len, 10); len = Math.min(len, 10);
} }
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(fullFormat.substring(0, len)); DateTimeFormatter formatter = DateTimeFormatter.ofPattern(fullFormat.substring(0, len));

View File

@ -5,6 +5,7 @@ import io.dataease.api.chart.ChartDataApi;
import io.dataease.api.chart.dto.ViewDetailField; import io.dataease.api.chart.dto.ViewDetailField;
import io.dataease.api.chart.request.ChartExcelRequest; import io.dataease.api.chart.request.ChartExcelRequest;
import io.dataease.api.chart.request.ChartExcelRequestInner; import io.dataease.api.chart.request.ChartExcelRequestInner;
import io.dataease.auth.DeLinkPermit;
import io.dataease.chart.constant.ChartConstants; import io.dataease.chart.constant.ChartConstants;
import io.dataease.chart.manage.ChartDataManage; import io.dataease.chart.manage.ChartDataManage;
import io.dataease.constant.AuthConstant; import io.dataease.constant.AuthConstant;
@ -17,6 +18,7 @@ import io.dataease.exportCenter.manage.ExportCenterManage;
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO; import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
import io.dataease.extensions.view.dto.ChartViewDTO; import io.dataease.extensions.view.dto.ChartViewDTO;
import io.dataease.extensions.view.dto.ChartViewFieldDTO; import io.dataease.extensions.view.dto.ChartViewFieldDTO;
import io.dataease.extensions.view.dto.FormatterCfgDTO;
import io.dataease.license.manage.F2CLicLimitedManage; import io.dataease.license.manage.F2CLicLimitedManage;
import io.dataease.result.ResultCode; import io.dataease.result.ResultCode;
import io.dataease.utils.JsonUtil; import io.dataease.utils.JsonUtil;
@ -38,8 +40,10 @@ import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.OutputStream; import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -73,6 +77,7 @@ public class ChartDataServer implements ChartDataApi {
return Math.toIntExact(Math.min(f2CLicLimitedManage.checkDatasetLimit(), limit)); return Math.toIntExact(Math.min(f2CLicLimitedManage.checkDatasetLimit(), limit));
} }
@DeLinkPermit("#p0.sceneId")
@Override @Override
public ChartViewDTO getData(ChartViewDTO chartViewDTO) throws Exception { public ChartViewDTO getData(ChartViewDTO chartViewDTO) throws Exception {
try { try {
@ -123,13 +128,105 @@ public class ChartDataServer implements ChartDataApi {
request.setHeader(dsHeader); request.setHeader(dsHeader);
request.setExcelTypes(dsTypes); request.setExcelTypes(dsTypes);
} }
if (CollectionUtils.isNotEmpty(tableRow)) {
for (Object[] objects : tableRow) {
for (int i = 0; i < viewDTO.getXAxis().size(); i++) {
if (viewDTO.getXAxis().get(i).getDeType().equals(DeTypeConstants.DE_INT) || viewDTO.getXAxis().get(i).getDeType().equals(DeTypeConstants.DE_FLOAT)) {
try {
objects[i] = valueFormatter(BigDecimal.valueOf(Double.valueOf(objects[i].toString())), viewDTO.getXAxis().get(i).getFormatterCfg());
} catch (Exception ignore) {
}
}
}
}
}
request.setDetails(tableRow); request.setDetails(tableRow);
request.setData(chartViewInfo.getData());
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static String valueFormatter(BigDecimal value, FormatterCfgDTO formatter) {
if (value == null || formatter == null) {
return null;
}
String result;
if (formatter.getType().equals("auto")) {
result = transSeparatorAndSuffix(String.valueOf(transUnit(value, formatter)), formatter);
} else if (formatter.getType().equals("value")) {
result = transSeparatorAndSuffix(transDecimal(transUnit(value, formatter), formatter), formatter);
} else if (formatter.getType().equals("percent")) {
value = value.multiply(BigDecimal.valueOf(100));
result = transSeparatorAndSuffix(transDecimal(value, formatter), formatter);
} else {
result = value.toString();
}
return result;
}
private static BigDecimal transUnit(BigDecimal value, FormatterCfgDTO formatter) {
return value.divide(BigDecimal.valueOf(formatter.getUnit()));
}
private static String transDecimal(BigDecimal value, FormatterCfgDTO formatter) {
DecimalFormat df = new DecimalFormat("0." + new String(new char[formatter.getDecimalCount()]).replace('\0', '0'));
return df.format(value);
}
private static String transSeparatorAndSuffix(String value, FormatterCfgDTO formatter) {
StringBuilder sb = new StringBuilder(value);
if (formatter.getThousandSeparator()) {
String[] parts = value.split("\\.");
parts[0] = addThousandSeparators(parts[0]);
sb = new StringBuilder(String.join(".", parts));
}
if (formatter.getType().equals("percent")) {
sb.append('%');
} else {
switch (formatter.getUnit()) {
case 1000:
sb.append("");
break;
case 10000:
sb.append("");
break;
case 1000000:
sb.append("百万");
break;
case 100000000:
sb.append('亿');
break;
default:
break;
}
}
String suffix = formatter.getSuffix().trim();
if (!suffix.isEmpty()) {
sb.append(suffix);
}
return sb.toString();
}
private static String addThousandSeparators(String number) {
StringBuilder sb = new StringBuilder();
int len = number.length();
int count = 0;
for (int i = len - 1; i >= 0; i--) {
sb.append(number.charAt(i));
count++;
if (count == 3 && i != 0) {
sb.append(',');
count = 0;
}
}
return sb.reverse().toString();
}
@Override @Override
public void innerExportDetails(ChartExcelRequest request, HttpServletResponse response) throws Exception { public void innerExportDetails(ChartExcelRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

View File

@ -1,7 +1,10 @@
package io.dataease.config; package io.dataease.config;
import io.dataease.constant.AuthConstant; import io.dataease.constant.AuthConstant;
import io.dataease.share.interceptor.LinkInterceptor;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -11,6 +14,8 @@ import static io.dataease.utils.StaticResourceUtils.ensureSuffix;
@Configuration @Configuration
public class DeMvcConfig implements WebMvcConfigurer { public class DeMvcConfig implements WebMvcConfigurer {
@Resource
private LinkInterceptor linkInterceptor;
/** /**
* Configuring static resource path * Configuring static resource path
@ -33,4 +38,9 @@ public class DeMvcConfig implements WebMvcConfigurer {
registry.addResourceHandler(geoUrlPattern).addResourceLocations(geoDir); registry.addResourceHandler(geoUrlPattern).addResourceLocations(geoDir);
} }
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(linkInterceptor).addPathPatterns("/**");
}
} }

View File

@ -50,6 +50,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -259,6 +260,7 @@ public class DatasetDataManage {
public Long getDatasetTotal(Long datasetGroupId) throws Exception { public Long getDatasetTotal(Long datasetGroupId) throws Exception {
DatasetGroupInfoDTO dto = datasetGroupManage.getForCount(datasetGroupId); DatasetGroupInfoDTO dto = datasetGroupManage.getForCount(datasetGroupId);
if (ObjectUtils.isEmpty(dto)) return 0L;
if (StringUtils.equalsIgnoreCase(dto.getNodeType(), "dataset")) { if (StringUtils.equalsIgnoreCase(dto.getNodeType(), "dataset")) {
return getDatasetTotal(dto, null, new ChartExtRequest()); return getDatasetTotal(dto, null, new ChartExtRequest());
} }
@ -452,11 +454,17 @@ public class DatasetDataManage {
LinkedHashMap<String, Object> obj = new LinkedHashMap<>(); LinkedHashMap<String, Object> obj = new LinkedHashMap<>();
if (row.length > 0) { if (row.length > 0) {
for (int j = 0; j < fields.size(); j++) { for (int j = 0; j < fields.size(); j++) {
String res = row[j];
// 如果字段类型是数值类型的小数则去除科学计数
if (fields.get(j).getDeType() == 3 && StringUtils.containsIgnoreCase(res, "E")) {
BigDecimal bigDecimal = new BigDecimal(res);
res = String.format("%.8f", bigDecimal);
}
if (desensitizationList.keySet().contains(fields.get(j).getDataeaseName())) { if (desensitizationList.keySet().contains(fields.get(j).getDataeaseName())) {
obj.put(fields.get(j).getDataeaseName(), ChartDataBuild.desensitizationValue(desensitizationList.get(fields.get(j).getDataeaseName()), String.valueOf(row[j]))); obj.put(fields.get(j).getDataeaseName(), ChartDataBuild.desensitizationValue(desensitizationList.get(fields.get(j).getDataeaseName()), String.valueOf(res)));
} else { } else {
obj.put(ObjectUtils.isNotEmpty(fields.get(j).getDataeaseName()) ? obj.put(ObjectUtils.isNotEmpty(fields.get(j).getDataeaseName()) ?
fields.get(j).getDataeaseName() : fields.get(j).getOriginName(), row[j]); fields.get(j).getDataeaseName() : fields.get(j).getOriginName(), res);
} }
} }
} }

View File

@ -262,6 +262,9 @@ public class DatasetGroupManage {
List<CoreDatasetTable> coreDatasetTables = coreDatasetTableMapper.selectList(wrapper); List<CoreDatasetTable> coreDatasetTables = coreDatasetTableMapper.selectList(wrapper);
Set<Long> ids = new LinkedHashSet(); Set<Long> ids = new LinkedHashSet();
coreDatasetTables.forEach(ele -> ids.add(ele.getDatasourceId())); coreDatasetTables.forEach(ele -> ids.add(ele.getDatasourceId()));
if (CollectionUtils.isEmpty(ids)) {
DEException.throwException("数据集因异常导致无法使用,请重新创建");
}
QueryWrapper<CoreDatasource> datasourceQueryWrapper = new QueryWrapper<>(); QueryWrapper<CoreDatasource> datasourceQueryWrapper = new QueryWrapper<>();
datasourceQueryWrapper.in("id", ids); datasourceQueryWrapper.in("id", ids);

View File

@ -209,8 +209,6 @@ public class DatasetSQLManage {
String tablePrefix = ""; String tablePrefix = "";
String tableSuffix = ""; String tableSuffix = "";
if (ObjectUtils.isNotEmpty(currentSQLObj.getTableSchema())) { if (ObjectUtils.isNotEmpty(currentSQLObj.getTableSchema())) {
ts = currentSQLObj.getTableSchema() + ".";
if (isCross) { if (isCross) {
tablePrefix = "`"; tablePrefix = "`";
tableSuffix = "`"; tableSuffix = "`";
@ -219,6 +217,8 @@ public class DatasetSQLManage {
tablePrefix = datasourceType.getPrefix(); tablePrefix = datasourceType.getPrefix();
tableSuffix = datasourceType.getSuffix(); tableSuffix = datasourceType.getSuffix();
} }
ts = tablePrefix + currentSQLObj.getTableSchema() + tableSuffix + ".";
} }
// build join // build join
join.append(" ").append(joinType).append(" ") join.append(" ").append(joinType).append(" ")

View File

@ -44,7 +44,6 @@ public class TableUtils {
String prefix = ""; String prefix = "";
String suffix = ""; String suffix = "";
if (StringUtils.isNotEmpty(sqlObj.getTableSchema())) { if (StringUtils.isNotEmpty(sqlObj.getTableSchema())) {
schema = sqlObj.getTableSchema() + ".";
if (isCross) { if (isCross) {
prefix = "`"; prefix = "`";
suffix = "`"; suffix = "`";
@ -52,6 +51,7 @@ public class TableUtils {
prefix = datasourceType.getPrefix(); prefix = datasourceType.getPrefix();
suffix = datasourceType.getSuffix(); suffix = datasourceType.getSuffix();
} }
schema = prefix + sqlObj.getTableSchema() + suffix + ".";
} }
return schema + prefix + sqlObj.getTableName() + suffix + " " + sqlObj.getTableAlias(); return schema + prefix + sqlObj.getTableName() + suffix + " " + sqlObj.getTableAlias();
} }

View File

@ -2,7 +2,6 @@ package io.dataease.datasource.provider;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import io.dataease.dataset.utils.FieldUtils; import io.dataease.dataset.utils.FieldUtils;
import io.dataease.datasource.dto.es.EsResponse; import io.dataease.datasource.dto.es.EsResponse;
import io.dataease.datasource.dto.es.Request; import io.dataease.datasource.dto.es.Request;
@ -11,12 +10,10 @@ import io.dataease.exception.DEException;
import io.dataease.extensions.datasource.dto.*; import io.dataease.extensions.datasource.dto.*;
import io.dataease.extensions.datasource.provider.Provider; import io.dataease.extensions.datasource.provider.Provider;
import io.dataease.i18n.Translator; import io.dataease.i18n.Translator;
import io.dataease.utils.HttpClientConfig; import io.dataease.utils.HttpClientConfig;
import io.dataease.utils.HttpClientUtil; import io.dataease.utils.HttpClientUtil;
import io.dataease.utils.JsonUtil; import io.dataease.utils.JsonUtil;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders; import org.apache.http.HttpHeaders;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -98,7 +95,7 @@ public class EsProvider extends Provider {
try { try {
String sql; String sql;
if (datasourceRequest.getTable() != null) { if (datasourceRequest.getTable() != null) {
sql = "select * from " + datasourceRequest.getTable() + " limit 0"; sql = "select * from \"" + datasourceRequest.getTable() + "\" limit 0";
} else { } else {
sql = datasourceRequest.getQuery(); sql = datasourceRequest.getQuery();
} }

View File

@ -89,7 +89,7 @@ public class MysqlEngineProvider extends EngineProvider {
int size = tableField.getPrecision() * 4; int size = tableField.getPrecision() * 4;
switch (tableField.getDeExtractType()) { switch (tableField.getDeExtractType()) {
case 0: case 0:
Column_Fields.append("varchar(2048)").append(",`"); Column_Fields.append("varchar(1024)").append(",`");
break; break;
case 1: case 1:
Column_Fields.append("datetime").append(",`"); Column_Fields.append("datetime").append(",`");
@ -104,7 +104,7 @@ public class MysqlEngineProvider extends EngineProvider {
Column_Fields.append("TINYINT(length)".replace("length", String.valueOf(tableField.getPrecision()))).append(",`"); Column_Fields.append("TINYINT(length)".replace("length", String.valueOf(tableField.getPrecision()))).append(",`");
break; break;
default: default:
Column_Fields.append("varchar(2048)").append(",`"); Column_Fields.append("varchar(1024)").append(",`");
break; break;
} }
} }

View File

@ -126,7 +126,7 @@ public class DatasourceServer implements DatasourceApi {
} }
public boolean checkRepeat(@RequestBody BusiDsRequest dataSourceDTO) { public boolean checkRepeat(@RequestBody BusiDsRequest dataSourceDTO) {
if (Arrays.asList("API", "Excel", "folder").contains(dataSourceDTO.getType())) { if (Arrays.asList("API", "Excel", "folder", "es").contains(dataSourceDTO.getType())) {
return false; return false;
} }
BusiNodeRequest request = new BusiNodeRequest(); BusiNodeRequest request = new BusiNodeRequest();
@ -267,7 +267,11 @@ public class DatasourceServer implements DatasourceApi {
try { try {
datasourceSyncManage.createEngineTable(datasourceRequest.getTable(), tableFields); datasourceSyncManage.createEngineTable(datasourceRequest.getTable(), tableFields);
} catch (Exception e) { } catch (Exception e) {
DEException.throwException("Failed to create table " + datasourceRequest.getTable() + ", " + e.getMessage()); if (e.getMessage().toLowerCase().contains("Row size too large".toLowerCase())) {
DEException.throwException("文本内容超出最大支持范围: " + datasourceRequest.getTable() + ", " + e.getMessage());
} else {
DEException.throwException("Failed to create table " + datasourceRequest.getTable() + ", " + e.getMessage());
}
} }
} }
commonThreadPool.addTask(() -> { commonThreadPool.addTask(() -> {
@ -479,6 +483,23 @@ public class DatasourceServer implements DatasourceApi {
return getDatasourceDTOById(datasourceId, true); return getDatasourceDTOById(datasourceId, true);
} }
@Override
public DatasourceDTO getSimpleDs(Long datasourceId) throws DEException {
CoreDatasource datasource = datasourceMapper.selectById(datasourceId);
if (datasource == null) {
DEException.throwException("不存在的数据源!");
}
if (datasource.getType().equalsIgnoreCase("api")) {
datasource.setConfiguration("[]");
} else {
datasource.setConfiguration("");
}
datasource.setConfiguration("");
DatasourceDTO datasourceDTO = new DatasourceDTO();
BeanUtils.copyBean(datasourceDTO, datasource);
return datasourceDTO;
}
@Override @Override
public DatasourceDTO get(Long datasourceId) throws DEException { public DatasourceDTO get(Long datasourceId) throws DEException {
return getDatasourceDTOById(datasourceId, false); return getDatasourceDTOById(datasourceId, false);
@ -1128,8 +1149,12 @@ public class DatasourceServer implements DatasourceApi {
params.add(apiDefinition); params.add(apiDefinition);
} }
} }
datasourceDTO.setApiConfigurationStr(new String(Base64.getEncoder().encode(Objects.requireNonNull(JsonUtil.toJSONString(apiDefinitionListWithStatus)).toString().getBytes()))); if(CollectionUtils.isNotEmpty(params)){
datasourceDTO.setParamsStr(new String(Base64.getEncoder().encode(Objects.requireNonNull(JsonUtil.toJSONString(params)).toString().getBytes()))); datasourceDTO.setParamsStr(RsaUtils.symmetricEncrypt(JsonUtil.toJSONString(params).toString()));
}
if(CollectionUtils.isNotEmpty(apiDefinitionListWithStatus)){
datasourceDTO.setApiConfigurationStr(RsaUtils.symmetricEncrypt(JsonUtil.toJSONString(apiDefinitionListWithStatus).toString()));
}
if (success == apiDefinitionList.size()) { if (success == apiDefinitionList.size()) {
datasourceDTO.setStatus("Success"); datasourceDTO.setStatus("Success");
} else { } else {
@ -1143,7 +1168,6 @@ public class DatasourceServer implements DatasourceApi {
TaskDTO taskDTO = new TaskDTO(); TaskDTO taskDTO = new TaskDTO();
BeanUtils.copyBean(taskDTO, coreDatasourceTask); BeanUtils.copyBean(taskDTO, coreDatasourceTask);
datasourceDTO.setSyncSetting(taskDTO); datasourceDTO.setSyncSetting(taskDTO);
CoreDatasourceTask task = datasourceTaskServer.selectByDSId(datasourceDTO.getId()); CoreDatasourceTask task = datasourceTaskServer.selectByDSId(datasourceDTO.getId());
if (task != null) { if (task != null) {
datasourceDTO.setLastSyncTime(task.getStartTime()); datasourceDTO.setLastSyncTime(task.getStartTime());
@ -1153,13 +1177,12 @@ public class DatasourceServer implements DatasourceApi {
Provider provider = ProviderFactory.getProvider(datasourceDTO.getType()); Provider provider = ProviderFactory.getProvider(datasourceDTO.getType());
provider.hidePW(datasourceDTO); provider.hidePW(datasourceDTO);
} }
} }
if (datasourceDTO.getType().equalsIgnoreCase(DatasourceConfiguration.DatasourceType.Excel.toString())) { if (datasourceDTO.getType().equalsIgnoreCase(DatasourceConfiguration.DatasourceType.Excel.toString())) {
datasourceDTO.setFileName(ExcelUtils.getFileName(datasource)); datasourceDTO.setFileName(ExcelUtils.getFileName(datasource));
datasourceDTO.setSize(ExcelUtils.getSize(datasource)); datasourceDTO.setSize(ExcelUtils.getSize(datasource));
} }
datasourceDTO.setConfiguration(new String(Base64.getEncoder().encode(datasourceDTO.getConfiguration().getBytes()))); datasourceDTO.setConfiguration(RsaUtils.symmetricEncrypt(datasourceDTO.getConfiguration()));
datasourceDTO.setCreator(coreUserManage.getUserName(Long.valueOf(datasourceDTO.getCreateBy()))); datasourceDTO.setCreator(coreUserManage.getUserName(Long.valueOf(datasourceDTO.getCreateBy())));
return datasourceDTO; return datasourceDTO;
} }

View File

@ -5,9 +5,12 @@ import io.dataease.datasource.dao.auto.entity.CoreDeEngine;
import io.dataease.datasource.dao.auto.mapper.CoreDeEngineMapper; import io.dataease.datasource.dao.auto.mapper.CoreDeEngineMapper;
import io.dataease.datasource.manage.EngineManage; import io.dataease.datasource.manage.EngineManage;
import io.dataease.datasource.provider.CalciteProvider; import io.dataease.datasource.provider.CalciteProvider;
import io.dataease.exception.DEException;
import io.dataease.extensions.datasource.dto.DatasourceDTO; import io.dataease.extensions.datasource.dto.DatasourceDTO;
import io.dataease.utils.AuthUtils;
import io.dataease.utils.BeanUtils; import io.dataease.utils.BeanUtils;
import io.dataease.utils.IDUtils; import io.dataease.utils.IDUtils;
import io.dataease.utils.RsaUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -30,33 +33,44 @@ public class EngineServer implements EngineApi {
@Override @Override
public DatasourceDTO getEngine() { public DatasourceDTO getEngine() {
if (!AuthUtils.getUser().getUserId().equals(1L)) {
DEException.throwException("非管理员,无权访问!");
}
DatasourceDTO datasourceDTO = new DatasourceDTO(); DatasourceDTO datasourceDTO = new DatasourceDTO();
List<CoreDeEngine> deEngines = deEngineMapper.selectList(null); List<CoreDeEngine> deEngines = deEngineMapper.selectList(null);
if (CollectionUtils.isEmpty(deEngines)) { if (CollectionUtils.isEmpty(deEngines)) {
return datasourceDTO; return datasourceDTO;
} }
return BeanUtils.copyBean(datasourceDTO, deEngines.get(0)); BeanUtils.copyBean(datasourceDTO, deEngines.get(0));
datasourceDTO.setConfiguration(RsaUtils.symmetricEncrypt(datasourceDTO.getConfiguration()));
return datasourceDTO;
} }
@Override @Override
public void save(DatasourceDTO datasourceDTO) { public void save(DatasourceDTO datasourceDTO) {
if (!AuthUtils.getUser().getUserId().equals(1L)) {
DEException.throwException("非管理员,无权访问!");
}
if (StringUtils.isNotEmpty(datasourceDTO.getConfiguration())) { if (StringUtils.isNotEmpty(datasourceDTO.getConfiguration())) {
datasourceDTO.setConfiguration(new String(Base64.getDecoder().decode(datasourceDTO.getConfiguration()))); datasourceDTO.setConfiguration(new String(Base64.getDecoder().decode(datasourceDTO.getConfiguration())));
} }
CoreDeEngine coreDeEngine = new CoreDeEngine(); CoreDeEngine coreDeEngine = new CoreDeEngine();
BeanUtils.copyBean(coreDeEngine, datasourceDTO); BeanUtils.copyBean(coreDeEngine, datasourceDTO);
if(coreDeEngine.getId() == null){ if (coreDeEngine.getId() == null) {
coreDeEngine.setId(IDUtils.snowID()); coreDeEngine.setId(IDUtils.snowID());
datasourceDTO.setId(coreDeEngine.getId()); datasourceDTO.setId(coreDeEngine.getId());
deEngineMapper.insert(coreDeEngine); deEngineMapper.insert(coreDeEngine);
}else { } else {
deEngineMapper.updateById(coreDeEngine); deEngineMapper.updateById(coreDeEngine);
} }
calciteProvider.update(datasourceDTO); calciteProvider.update(datasourceDTO);
} }
@Override @Override
public void validate(DatasourceDTO datasourceDTO) throws Exception{ public void validate(DatasourceDTO datasourceDTO) throws Exception {
if (!AuthUtils.getUser().getUserId().equals(1L)) {
DEException.throwException("非管理员,无权访问!");
}
CoreDeEngine coreDeEngine = new CoreDeEngine(); CoreDeEngine coreDeEngine = new CoreDeEngine();
BeanUtils.copyBean(coreDeEngine, datasourceDTO); BeanUtils.copyBean(coreDeEngine, datasourceDTO);
coreDeEngine.setConfiguration(new String(Base64.getDecoder().decode(coreDeEngine.getConfiguration()))); coreDeEngine.setConfiguration(new String(Base64.getDecoder().decode(coreDeEngine.getConfiguration())));
@ -65,6 +79,9 @@ public class EngineServer implements EngineApi {
@Override @Override
public void validateById(Long id) throws Exception { public void validateById(Long id) throws Exception {
if (!AuthUtils.getUser().getUserId().equals(1L)) {
DEException.throwException("非管理员,无权访问!");
}
engineManage.validate(deEngineMapper.selectById(id)); engineManage.validate(deEngineMapper.selectById(id));
} }

View File

@ -147,19 +147,55 @@ public class ExtWhere2Str {
if (value.contains(SQLConstants.EMPTY_SIGN)) { if (value.contains(SQLConstants.EMPTY_SIGN)) {
whereValue = "('" + StringUtils.join(value, "','") + "', '')" + " or " + whereName + " is null "; whereValue = "('" + StringUtils.join(value, "','") + "', '')" + " or " + whereName + " is null ";
} else { } else {
if (StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NVARCHAR") // tree的情况需额外处理
|| StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NCHAR")) { if (request.getIsTree()) {
whereValue = "(" + value.stream().map(str -> "'" + SQLConstants.MSSQL_N_PREFIX + str + "'").collect(Collectors.joining(",")) + ")"; List<DatasetTableFieldDTO> datasetTableFieldList = request.getDatasetTableFieldList();
boolean hasN = false;
for (DatasetTableFieldDTO dto : datasetTableFieldList) {
if (StringUtils.containsIgnoreCase(dto.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(dto.getType(), "NCHAR")) {
hasN = true;
break;
}
}
if (hasN) {
whereValue = "(" + value.stream().map(str -> "'" + SQLConstants.MSSQL_N_PREFIX + str + "'").collect(Collectors.joining(",")) + ")";
} else {
whereValue = "('" + StringUtils.join(value, "','") + "')";
}
} else { } else {
whereValue = "('" + StringUtils.join(value, "','") + "')"; if (StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NCHAR")) {
whereValue = "(" + value.stream().map(str -> "'" + SQLConstants.MSSQL_N_PREFIX + str + "'").collect(Collectors.joining(",")) + ")";
} else {
whereValue = "('" + StringUtils.join(value, "','") + "')";
}
} }
} }
} else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) {
if (StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NVARCHAR") // tree的情况需额外处理
|| StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NCHAR")) { if (request.getIsTree()) {
whereValue = "'" + SQLConstants.MSSQL_N_PREFIX + "%" + value.get(0) + "%'"; List<DatasetTableFieldDTO> datasetTableFieldList = request.getDatasetTableFieldList();
boolean hasN = false;
for (DatasetTableFieldDTO dto : datasetTableFieldList) {
if (StringUtils.containsIgnoreCase(dto.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(dto.getType(), "NCHAR")) {
hasN = true;
break;
}
}
if (hasN) {
whereValue = "'" + SQLConstants.MSSQL_N_PREFIX + "%" + value.get(0) + "%'";
} else {
whereValue = "'%" + value.get(0) + "%'";
}
} else { } else {
whereValue = "'%" + value.get(0) + "%'"; if (StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NCHAR")) {
whereValue = "'" + SQLConstants.MSSQL_N_PREFIX + "%" + value.get(0) + "%'";
} else {
whereValue = "'%" + value.get(0) + "%'";
}
} }
} else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) {
if (request.getDatasetTableField().getDeType() == 1) { if (request.getDatasetTableField().getDeType() == 1) {
@ -191,11 +227,29 @@ public class ExtWhere2Str {
if (StringUtils.equals(value.get(0), SQLConstants.EMPTY_SIGN)) { if (StringUtils.equals(value.get(0), SQLConstants.EMPTY_SIGN)) {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, "") + " or " + whereName + " is null "; whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, "") + " or " + whereName + " is null ";
} else { } else {
if (StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NVARCHAR") // tree的情况需额外处理
|| StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NCHAR")) { if (request.getIsTree()) {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE_CH, value.get(0)); List<DatasetTableFieldDTO> datasetTableFieldList = request.getDatasetTableFieldList();
boolean hasN = false;
for (DatasetTableFieldDTO dto : datasetTableFieldList) {
if (StringUtils.containsIgnoreCase(dto.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(dto.getType(), "NCHAR")) {
hasN = true;
break;
}
}
if (hasN) {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE_CH, value.get(0));
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value.get(0));
}
} else { } else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value.get(0)); if (StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NCHAR")) {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE_CH, value.get(0));
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value.get(0));
}
} }
} }
} }

View File

@ -631,6 +631,7 @@ public class ExportCenterManage implements BaseExportApi {
boolean isCreated = directory.mkdir(); boolean isCreated = directory.mkdir();
TokenUserBO tokenUserBO = AuthUtils.getUser(); TokenUserBO tokenUserBO = AuthUtils.getUser();
Future future = scheduledThreadPoolExecutor.submit(() -> { Future future = scheduledThreadPoolExecutor.submit(() -> {
LicenseUtil.validate();
AuthUtils.setUser(tokenUserBO); AuthUtils.setUser(tokenUserBO);
try { try {
exportTask.setExportStatus("IN_PROGRESS"); exportTask.setExportStatus("IN_PROGRESS");
@ -654,16 +655,18 @@ public class ExportCenterManage implements BaseExportApi {
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
if (CollectionUtils.isEmpty(request.getMultiInfo())) { if (CollectionUtils.isEmpty(request.getMultiInfo())) {
List<Object[]> details = request.getDetails(); if(request.getViewInfo().getType().equalsIgnoreCase("chart-mix-dual-line")){
Integer[] excelTypes = request.getExcelTypes();
details.add(0, request.getHeader());
ViewDetailField[] detailFields = request.getDetailFields();
Object[] header = request.getHeader();
//明细sheet }else {
Sheet detailsSheet = wb.createSheet("数据"); List<Object[]> details = request.getDetails();
Integer[] excelTypes = request.getExcelTypes();
details.add(0, request.getHeader());
ViewDetailField[] detailFields = request.getDetailFields();
Object[] header = request.getHeader();
Sheet detailsSheet = wb.createSheet("数据");
ChartDataServer.setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes);
}
ChartDataServer.setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes);
} else { } else {
//多个sheet //多个sheet
for (int i = 0; i < request.getMultiInfo().size(); i++) { for (int i = 0; i < request.getMultiInfo().size(); i++) {

View File

@ -23,6 +23,13 @@ public class RestIndexController {
return RsaUtils.publicKey(); return RsaUtils.publicKey();
} }
@GetMapping("/symmetricKey")
@ResponseBody
public String symmetricKey() {
return RsaUtils.generateSymmetricKey();
}
@GetMapping("/model") @GetMapping("/model")
@ResponseBody @ResponseBody
public boolean model() { public boolean model() {

View File

@ -0,0 +1,110 @@
package io.dataease.share.interceptor;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import io.dataease.auth.DeLinkPermit;
import io.dataease.constant.AuthConstant;
import io.dataease.exception.DEException;
import io.dataease.share.manage.XpackShareManage;
import io.dataease.share.util.LinkTokenUtil;
import io.dataease.utils.LogUtil;
import io.dataease.utils.ServletUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Objects;
@Aspect
@Component
public class DeLinkAop {
private static final String PARAM_VARIABLE_PREFIX = "p";
private static final String SPRING_EL_FLAG = "#";
private final ExpressionParser parser = new SpelExpressionParser();
@Resource
private XpackShareManage xpackShareManage;
@Around(value = "@annotation(io.dataease.auth.DeLinkPermit)")
public Object logAround(ProceedingJoinPoint point) throws Throwable {
Object[] params = point.getArgs();
String linkToken = ServletUtils.getHead(AuthConstant.LINK_TOKEN_KEY);
if (StringUtils.isNotBlank(linkToken)) {
MethodSignature ms = (MethodSignature) point.getSignature();
Method method = ms.getMethod();
DeLinkPermit deLinkPermit = method.getAnnotation(DeLinkPermit.class);
String value = deLinkPermit.value();
if (StringUtils.isBlank(value)) {
value = SPRING_EL_FLAG + PARAM_VARIABLE_PREFIX + "0";
}
Long id = getExpression(params, value);
DecodedJWT jwt = JWT.decode(linkToken);
Long resourceId = jwt.getClaim("resourceId").asLong();
if (!id.equals(resourceId)) {
DEException.throwException("link token invalid");
return false;
}
Long uid = jwt.getClaim("uid").asLong();
String secret = xpackShareManage.queryPwd(resourceId, uid);
if (StringUtils.isBlank(secret)) {
secret = LinkTokenUtil.defaultPwd;
}
Algorithm algorithm = Algorithm.HMAC256(secret);
Verification verification = JWT.require(algorithm);
JWTVerifier verifier = verification.build();
DecodedJWT decode = JWT.decode(linkToken);
algorithm.verify(decode);
verifier.verify(linkToken);
}
try {
return point.proceed(params);
} catch (Exception e) {
LogUtil.error(e.getMessage());
throw e;
}
}
public Long getExpression(Object[] params, String expression) {
StandardEvaluationContext context = buildContext(params);
Object o = resolveValue(expression, context);
if (ObjectUtils.isNotEmpty(o)) return Long.parseLong(o.toString());
return null;
}
private StandardEvaluationContext buildContext(Object[] params) {
StandardEvaluationContext context = new StandardEvaluationContext();
if (params != null && params.length == 1) {
context.setRootObject(params[0]);
}
for (int i = 0; i < Objects.requireNonNull(params).length; i++) {
Object paramValue = params[i];
context.setVariable(PARAM_VARIABLE_PREFIX + i, paramValue);
}
return context;
}
private Object resolveValue(String exp, EvaluationContext context) {
if (StringUtils.contains(exp, SPRING_EL_FLAG)) {
Expression expression = parser.parseExpression(exp);
return expression.getValue(context);
}
return exp;
}
}

View File

@ -0,0 +1,54 @@
package io.dataease.share.interceptor;
import io.dataease.auth.DeLinkPermit;
import io.dataease.constant.AuthConstant;
import io.dataease.exception.DEException;
import io.dataease.utils.ServletUtils;
import io.dataease.utils.WhitelistUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Arrays;
import java.util.List;
@Component
public class LinkInterceptor implements HandlerInterceptor {
private final static String whiteListText = "/user/ipInfo, /apisix/check, /datasetData/enumValue, /datasetData/enumValueObj, /datasetData/getFieldTree, /dekey, /symmetricKey, /share/validate, /sysParameter/queryOnlineMap, /chartData/innerExportDetails";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String linkToken = ServletUtils.getHead(AuthConstant.LINK_TOKEN_KEY);
if (linkToken == null) {
return true;
}
if (handler instanceof HandlerMethod handlerMethod) {
DeLinkPermit deLinkPermit = handlerMethod.getMethodAnnotation(DeLinkPermit.class);
if (deLinkPermit == null) {
List<String> whiteList = Arrays.stream(StringUtils.split(whiteListText, ",")).map(String::trim).toList();
String requestURI = ServletUtils.request().getRequestURI();
if (StringUtils.startsWith(requestURI, WhitelistUtils.getContextPath())) {
requestURI = requestURI.replaceFirst(WhitelistUtils.getContextPath(), "");
}
if (StringUtils.startsWith(requestURI, AuthConstant.DE_API_PREFIX)) {
requestURI = requestURI.replaceFirst(AuthConstant.DE_API_PREFIX, "");
}
boolean valid = whiteList.contains(requestURI) || WhitelistUtils.match(requestURI);
if (!valid) {
DEException.throwException("分享链接Token不支持访问当前url[" + requestURI + "]");
}
return true;
}
}
return true;
}
}

View File

@ -64,6 +64,15 @@ public class XpackShareManage {
return xpackShareMapper.selectOne(queryWrapper); return xpackShareMapper.selectOne(queryWrapper);
} }
public String queryPwd(Long resourceId, Long userId) {
QueryWrapper<XpackShare> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("creator", userId);
queryWrapper.eq("resource_id", resourceId);
XpackShare xpackShare = xpackShareMapper.selectOne(queryWrapper);
if (ObjectUtils.isEmpty(xpackShare)) return null;
return xpackShare.getPwd();
}
@Transactional @Transactional
public void switcher(Long resourceId) { public void switcher(Long resourceId) {
XpackShare originData = queryByResource(resourceId); XpackShare originData = queryByResource(resourceId);
@ -199,7 +208,7 @@ public class XpackShareManage {
if (ObjectUtils.isEmpty(sharedBase) || !sharedBase.isPeRequire()) return true; if (ObjectUtils.isEmpty(sharedBase) || !sharedBase.isPeRequire()) return true;
Long exp = share.getExp(); Long exp = share.getExp();
String pwd = share.getPwd(); String pwd = share.getPwd();
return StringUtils.isNotBlank(pwd) && ObjectUtils.isNotEmpty(exp); return StringUtils.isNotBlank(pwd) && ObjectUtils.isNotEmpty(exp) && exp > 0L;
} }
public XpackShareProxyVO proxyInfo(XpackShareProxyRequest request) { public XpackShareProxyVO proxyInfo(XpackShareProxyRequest request) {

View File

@ -9,7 +9,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.Date; import java.util.Date;
public class LinkTokenUtil { public class LinkTokenUtil {
private static final String defaultPwd = "link-pwd-fit2cloud"; public static final String defaultPwd = "link-pwd-fit2cloud";
public static String generate(Long uid, Long resourceId, Long exp, String pwd, Long oid) { public static String generate(Long uid, Long resourceId, Long exp, String pwd, Long oid) {
pwd = StringUtils.isBlank(pwd) ? defaultPwd : pwd; pwd = StringUtils.isBlank(pwd) ? defaultPwd : pwd;
Algorithm algorithm = Algorithm.HMAC256(pwd); Algorithm algorithm = Algorithm.HMAC256(pwd);

View File

@ -1,6 +1,7 @@
package io.dataease.substitute.permissions.user; package io.dataease.substitute.permissions.user;
import io.dataease.api.permissions.user.vo.CurIpVO;
import io.dataease.api.permissions.user.vo.UserFormVO; import io.dataease.api.permissions.user.vo.UserFormVO;
import io.dataease.utils.IPUtils; import io.dataease.utils.IPUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -27,6 +28,7 @@ public class SubstituteUserServer {
result.put("language", "zh-CN"); result.put("language", "zh-CN");
return result; return result;
} }
@GetMapping("/personInfo") @GetMapping("/personInfo")
public UserFormVO personInfo() { public UserFormVO personInfo() {
UserFormVO userFormVO = new UserFormVO(); UserFormVO userFormVO = new UserFormVO();
@ -38,4 +40,13 @@ public class SubstituteUserServer {
userFormVO.setModel("lose"); userFormVO.setModel("lose");
return userFormVO; return userFormVO;
} }
@GetMapping("/ipInfo")
public CurIpVO ipInfo() {
CurIpVO curIpVO = new CurIpVO();
curIpVO.setAccount("admin");
curIpVO.setName("管理员");
curIpVO.setIp(IPUtils.get());
return curIpVO;
}
} }

View File

@ -12,7 +12,9 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
@RestController @RestController
@RequestMapping("/sysParameter") @RequestMapping("/sysParameter")
@ -61,6 +63,21 @@ public class SysParameterServer implements SysParameterApi {
return frontTimeOut; return frontTimeOut;
} }
@Override
public Map<String, Object> defaultSettings() {
Map<String, Object> map = new HashMap<>();
map.put(XpackSettingConstants.DEFAULT_SORT, "1");
List<SettingItemVO> settingItemVOS = queryBasicSetting();
for (int i = 0; i < settingItemVOS.size(); i++) {
SettingItemVO settingItemVO = settingItemVOS.get(i);
if (StringUtils.isNotBlank(settingItemVO.getPkey()) && settingItemVO.getPkey().equalsIgnoreCase(XpackSettingConstants.DEFAULT_SORT) && StringUtils.isNotBlank(settingItemVO.getPval())) {
map.put(XpackSettingConstants.DEFAULT_SORT, settingItemVO.getPval());
}
}
return map;
}
@Override @Override
public List<Object> ui() { public List<Object> ui() {
return sysParameterManage.getUiList(); return sysParameterManage.getUiList();

View File

@ -11,6 +11,7 @@ import io.dataease.api.template.vo.MarketLatestReleaseVO;
import io.dataease.api.template.vo.MarketMetaDataVO; import io.dataease.api.template.vo.MarketMetaDataVO;
import io.dataease.constant.CommonConstants; import io.dataease.constant.CommonConstants;
import io.dataease.exception.DEException; import io.dataease.exception.DEException;
import io.dataease.i18n.Translator;
import io.dataease.operation.manage.CoreOptRecentManage; import io.dataease.operation.manage.CoreOptRecentManage;
import io.dataease.system.manage.SysParameterManage; import io.dataease.system.manage.SysParameterManage;
import io.dataease.template.dao.auto.entity.VisualizationTemplateCategoryMap; import io.dataease.template.dao.auto.entity.VisualizationTemplateCategoryMap;
@ -166,11 +167,11 @@ public class TemplateCenterManage {
public MarketPreviewBaseResponse searchTemplatePreview() { public MarketPreviewBaseResponse searchTemplatePreview() {
try { try {
MarketBaseResponse baseContentRsp = searchTemplate(); MarketBaseResponse baseContentRsp = searchTemplate();
List<MarketMetaDataVO> categories = baseContentRsp.getCategories().stream().filter(category -> !"最近使用".equals(category.getLabel())).collect(Collectors.toList()); List<MarketMetaDataVO> categories = baseContentRsp.getCategories().stream().filter(category -> !Translator.get("i18n_template_recent").equals(category.getLabel())).toList();
List<TemplateMarketDTO> contents = baseContentRsp.getContents(); List<TemplateMarketDTO> contents = baseContentRsp.getContents();
List<TemplateMarketPreviewInfoDTO> previewContents = new ArrayList<>(); List<TemplateMarketPreviewInfoDTO> previewContents = new ArrayList<>();
categories.forEach(category -> { categories.forEach(category -> {
if ("推荐".equals(category.getLabel())) { if (Translator.get("i18n_template_recommend").equals(category.getLabel())) {
previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> "Y".equals(template.getSuggest())).collect(Collectors.toList()))); previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> "Y".equals(template.getSuggest())).collect(Collectors.toList())));
} else { } else {
previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> checkCategoryMatch(template, category.getLabel())).collect(Collectors.toList()))); previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> checkCategoryMatch(template, category.getLabel())).collect(Collectors.toList())));
@ -235,7 +236,7 @@ public class TemplateCenterManage {
List<MarketMetaDataVO> categoryVO = getCategoriesObject().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList()); List<MarketMetaDataVO> categoryVO = getCategoriesObject().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList());
Map<String, String> categoriesMap = categoryVO.stream() Map<String, String> categoriesMap = categoryVO.stream()
.collect(Collectors.toMap(MarketMetaDataVO::getValue, MarketMetaDataVO::getLabel)); .collect(Collectors.toMap(MarketMetaDataVO::getValue, MarketMetaDataVO::getLabel));
List<String> activeCategoriesName = new ArrayList<>(Arrays.asList("最近使用", "推荐")); List<String> activeCategoriesName = new ArrayList<>(Arrays.asList(Translator.get("i18n_template_recent"), Translator.get("i18n_template_recommend")));
contents.stream().forEach(templateMarketDTO -> { contents.stream().forEach(templateMarketDTO -> {
Long recentUseTime = useTime.get(templateMarketDTO.getId()); Long recentUseTime = useTime.get(templateMarketDTO.getId());
templateMarketDTO.setRecentUseTime(recentUseTime == null ? 0 : recentUseTime); templateMarketDTO.setRecentUseTime(recentUseTime == null ? 0 : recentUseTime);
@ -264,7 +265,7 @@ public class TemplateCenterManage {
public List<MarketMetaDataVO> getCategoriesObject() { public List<MarketMetaDataVO> getCategoriesObject() {
List<MarketMetaDataVO> result = getCategoriesV2(); List<MarketMetaDataVO> result = getCategoriesV2();
result.add(0, new MarketMetaDataVO("recent", "最近使用", CommonConstants.TEMPLATE_SOURCE.PUBLIC)); result.add(0, new MarketMetaDataVO("recent", Translator.get("i18n_template_recent"), CommonConstants.TEMPLATE_SOURCE.PUBLIC));
return result; return result;
} }
@ -285,7 +286,7 @@ public class TemplateCenterManage {
String resultStr = marketGet(templateParams.get("template.url") + TEMPLATE_META_DATA_URL, null); String resultStr = marketGet(templateParams.get("template.url") + TEMPLATE_META_DATA_URL, null);
MarketMetaDataBaseResponse metaData = JsonUtil.parseObject(resultStr, MarketMetaDataBaseResponse.class); MarketMetaDataBaseResponse metaData = JsonUtil.parseObject(resultStr, MarketMetaDataBaseResponse.class);
allCategories.addAll(metaData.getLabels()); allCategories.addAll(metaData.getLabels());
allCategories.add(0, new MarketMetaDataVO("suggest", "推荐", CommonConstants.TEMPLATE_SOURCE.PUBLIC)); allCategories.add(0, new MarketMetaDataVO("suggest", Translator.get("i18n_template_recommend"), CommonConstants.TEMPLATE_SOURCE.PUBLIC));
} catch (Exception e) { } catch (Exception e) {
LogUtil.error("模板市场分类获取错误", e); LogUtil.error("模板市场分类获取错误", e);
} }

View File

@ -11,6 +11,7 @@ import io.dataease.api.visualization.request.DataVisualizationBaseRequest;
import io.dataease.api.visualization.request.VisualizationAppExportRequest; import io.dataease.api.visualization.request.VisualizationAppExportRequest;
import io.dataease.api.visualization.request.VisualizationWorkbranchQueryRequest; import io.dataease.api.visualization.request.VisualizationWorkbranchQueryRequest;
import io.dataease.api.visualization.vo.*; import io.dataease.api.visualization.vo.*;
import io.dataease.auth.DeLinkPermit;
import io.dataease.chart.dao.auto.entity.CoreChartView; import io.dataease.chart.dao.auto.entity.CoreChartView;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper; import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
import io.dataease.chart.manage.ChartDataManage; import io.dataease.chart.manage.ChartDataManage;
@ -142,6 +143,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
} }
} }
@DeLinkPermit("#p0.id")
@DeLog(id = "#p0.id", ot = LogOT.READ, stExp = "#p0.busiFlag") @DeLog(id = "#p0.id", ot = LogOT.READ, stExp = "#p0.busiFlag")
@Override @Override
@XpackInteract(value = "dataVisualizationServer", original = true) @XpackInteract(value = "dataVisualizationServer", original = true)
@ -300,7 +302,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
coreDatasetTableFieldMapper.insert(dsTableFields); coreDatasetTableFieldMapper.insert(dsTableFields);
}); });
List<String> dsGroupNameSave = new ArrayList<>();
// 持久化数据集 // 持久化数据集
newDsGroupInfo.forEach(dsGroup -> { newDsGroupInfo.forEach(dsGroup -> {
dsTableIdMap.forEach((key, value) -> { dsTableIdMap.forEach((key, value) -> {
@ -325,8 +327,10 @@ public class DataVisualizationServer implements DataVisualizationApi {
} }
}); });
if(dsGroupNameSave.contains(dsGroup.getName())){
dsGroup.setName(dsGroup.getName()+"-"+UUID.randomUUID().toString());
}
dsGroupNameSave.add(dsGroup.getName());
datasetGroupManage.innerSave(dsGroup); datasetGroupManage.innerSave(dsGroup);
}); });

View File

@ -7,6 +7,7 @@ import io.dataease.api.visualization.dto.VisualizationLinkJumpInfoDTO;
import io.dataease.api.visualization.request.VisualizationLinkJumpBaseRequest; import io.dataease.api.visualization.request.VisualizationLinkJumpBaseRequest;
import io.dataease.api.visualization.response.VisualizationLinkJumpBaseResponse; import io.dataease.api.visualization.response.VisualizationLinkJumpBaseResponse;
import io.dataease.api.visualization.vo.VisualizationViewTableVO; import io.dataease.api.visualization.vo.VisualizationViewTableVO;
import io.dataease.auth.DeLinkPermit;
import io.dataease.chart.dao.auto.entity.CoreChartView; import io.dataease.chart.dao.auto.entity.CoreChartView;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper; import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO; import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
@ -67,6 +68,7 @@ public class VisualizationLinkJumpService implements VisualizationLinkJumpApi {
return extVisualizationLinkageMapper.queryTableFieldWithViewId(viewId); return extVisualizationLinkageMapper.queryTableFieldWithViewId(viewId);
} }
@DeLinkPermit
//获取仪表板的跳转信息 //获取仪表板的跳转信息
@Override @Override
public VisualizationLinkJumpBaseResponse queryVisualizationJumpInfo(Long dvId) { public VisualizationLinkJumpBaseResponse queryVisualizationJumpInfo(Long dvId) {
@ -135,6 +137,7 @@ public class VisualizationLinkJumpService implements VisualizationLinkJumpApi {
}); });
} }
@DeLinkPermit("#p0.targetDvId")
@Override @Override
public VisualizationLinkJumpBaseResponse queryTargetVisualizationJumpInfo(VisualizationLinkJumpBaseRequest request) { public VisualizationLinkJumpBaseResponse queryTargetVisualizationJumpInfo(VisualizationLinkJumpBaseRequest request) {
List<VisualizationLinkJumpDTO> result = extVisualizationLinkJumpMapper.getTargetVisualizationJumpInfo(request); List<VisualizationLinkJumpDTO> result = extVisualizationLinkJumpMapper.getTargetVisualizationJumpInfo(request);

View File

@ -6,6 +6,7 @@ import io.dataease.api.visualization.dto.LinkageInfoDTO;
import io.dataease.api.visualization.dto.VisualizationLinkageDTO; import io.dataease.api.visualization.dto.VisualizationLinkageDTO;
import io.dataease.api.visualization.request.VisualizationLinkageRequest; import io.dataease.api.visualization.request.VisualizationLinkageRequest;
import io.dataease.api.visualization.vo.VisualizationLinkageFieldVO; import io.dataease.api.visualization.vo.VisualizationLinkageFieldVO;
import io.dataease.auth.DeLinkPermit;
import io.dataease.chart.dao.auto.entity.CoreChartView; import io.dataease.chart.dao.auto.entity.CoreChartView;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper; import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
import io.dataease.utils.BeanUtils; import io.dataease.utils.BeanUtils;
@ -108,6 +109,7 @@ public class VisualizationLinkageService implements VisualizationLinkageApi {
return new BaseRspModel(); return new BaseRspModel();
} }
@DeLinkPermit
@Override @Override
public Map<String, List<String>> getVisualizationAllLinkageInfo(Long dvId) { public Map<String, List<String>> getVisualizationAllLinkageInfo(Long dvId) {
List<LinkageInfoDTO> info = extVisualizationLinkageMapper.getPanelAllLinkageInfo(dvId); List<LinkageInfoDTO> info = extVisualizationLinkageMapper.getPanelAllLinkageInfo(dvId);

View File

@ -2,13 +2,13 @@ package io.dataease.visualization.server;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.ibm.icu.impl.coll.CollationLoader;
import io.dataease.api.dataset.vo.CoreDatasetGroupVO; import io.dataease.api.dataset.vo.CoreDatasetGroupVO;
import io.dataease.api.dataset.vo.CoreDatasetTableFieldVO; import io.dataease.api.dataset.vo.CoreDatasetTableFieldVO;
import io.dataease.api.visualization.VisualizationOuterParamsApi; import io.dataease.api.visualization.VisualizationOuterParamsApi;
import io.dataease.api.visualization.dto.VisualizationOuterParamsDTO; import io.dataease.api.visualization.dto.VisualizationOuterParamsDTO;
import io.dataease.api.visualization.dto.VisualizationOuterParamsInfoDTO; import io.dataease.api.visualization.dto.VisualizationOuterParamsInfoDTO;
import io.dataease.api.visualization.response.VisualizationOuterParamsBaseResponse; import io.dataease.api.visualization.response.VisualizationOuterParamsBaseResponse;
import io.dataease.auth.DeLinkPermit;
import io.dataease.dataset.dao.auto.entity.CoreDatasetTable; import io.dataease.dataset.dao.auto.entity.CoreDatasetTable;
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableMapper; import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableMapper;
import io.dataease.engine.constant.DeTypeConstants; import io.dataease.engine.constant.DeTypeConstants;
@ -29,7 +29,10 @@ import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -98,6 +101,7 @@ public class VisualizationOuterParamsService implements VisualizationOuterParams
} }
@DeLinkPermit
@Override @Override
public VisualizationOuterParamsBaseResponse getOuterParamsInfo(String visualizationId) { public VisualizationOuterParamsBaseResponse getOuterParamsInfo(String visualizationId) {
List<VisualizationOuterParamsInfoDTO> result = extOuterParamsMapper.getVisualizationOuterParamsInfo(visualizationId); List<VisualizationOuterParamsInfoDTO> result = extOuterParamsMapper.getVisualizationOuterParamsInfo(visualizationId);

View File

@ -4,7 +4,7 @@ spring:
username: root username: root
password: 123456 password: 123456
messages: messages:
basename: i18n/lic,i18n/core,i18n/permissions,i18n/xpack basename: i18n/lic,i18n/core,i18n/permissions,i18n/xpack,i18n/sync
flyway: flyway:
enabled: true enabled: true
table: de_standalone_version table: de_standalone_version

View File

@ -0,0 +1,2 @@
INSERT INTO `core_sys_setting`(`id`, `pkey`, `pval`, `type`, `sort`)
VALUES (1048232869488627719, 'basic.defaultSort', '1', 'text', 13);

View File

@ -0,0 +1,2 @@
INSERT INTO `core_sys_setting`(`id`, `pkey`, `pval`, `type`, `sort`)
VALUES (1048232869488627719, 'basic.defaultSort', '1', 'text', 13);

View File

@ -104,3 +104,10 @@ i18n_df_multiple_value_split=use ';' to split multiple value
i18n_df_email_type=email type i18n_df_email_type=email type
i18n_df_phone_type=phone type i18n_df_phone_type=phone type
i18n_copilot_cross_ds_error=This feature is not supported for cross-source datasets.
i18n_template_recommend=Recommend
i18n_template_recent=Recently Used

View File

@ -126,3 +126,6 @@ i18n_df_phone_type=\u624B\u673A\u53F7\u683C\u5F0F
i18n_copilot_cross_ds_error=\u8DE8\u6E90\u6570\u636E\u96C6\u4E0D\u652F\u6301\u8BE5\u529F\u80FD i18n_copilot_cross_ds_error=\u8DE8\u6E90\u6570\u636E\u96C6\u4E0D\u652F\u6301\u8BE5\u529F\u80FD
i18n_template_recommend=\u63A8\u8350
i18n_template_recent=\u6700\u8FD1\u4F7F\u7528

View File

@ -124,3 +124,10 @@ i18n_df_email_type=\u90F5\u7BB1\u683C\u5F0F
i18n_df_phone_type=\u624B\u6A5F\u865F\u683C\u5F0F i18n_df_phone_type=\u624B\u6A5F\u865F\u683C\u5F0F
i18n_copilot_cross_ds_error=\u8DE8\u6E90\u6578\u64DA\u96C6\u4E0D\u652F\u6301\u8A72\u529F\u80FD
i18n_template_recommend=\u63A8\u85A6
i18n_template_recent=\u6700\u8FD1\u4F7F\u7528

View File

@ -6,3 +6,10 @@ export const getRoleRouters = async (): Promise<Array<AppCustomRouteRecordRaw>>
return res?.data return res?.data
}) })
} }
// 获取默认排序
export const getDefaultSettings = async (): Promise<IResponse> => {
return request.get({ url: '/sysParameter/defaultSettings' }).then(res => {
return res?.data
})
}

View File

@ -155,6 +155,8 @@ export const getById = (id: number) => request.get({ url: '/datasource/get/' + i
export const getHidePwById = (id: number) => request.get({ url: '/datasource/hidePw/' + id }) export const getHidePwById = (id: number) => request.get({ url: '/datasource/hidePw/' + id })
export const getSimpleDs = (id: number) => request.get({ url: '/datasource/getSimpleDs/' + id })
export const uploadFile = async (data): Promise<IResponse> => { export const uploadFile = async (data): Promise<IResponse> => {
return request return request
.post({ .post({

View File

@ -4,6 +4,8 @@ export const loginApi = data => request.post({ url: '/login/localLogin', data })
export const queryDekey = () => request.get({ url: 'dekey' }) export const queryDekey = () => request.get({ url: 'dekey' })
export const querySymmetricKey = () => request.get({ url: 'symmetricKey' })
export const modelApi = () => request.get({ url: 'model' }) export const modelApi = () => request.get({ url: 'model' })
export const platformLoginApi = origin => request.post({ url: '/login/platformLogin/' + origin }) export const platformLoginApi = origin => request.post({ url: '/login/platformLogin/' + origin })

View File

@ -32,6 +32,8 @@ export const queryFormApi = uid => request.get({ url: `/user/queryById/${uid}` }
export const personInfoApi = () => request.get({ url: `/user/personInfo` }) export const personInfoApi = () => request.get({ url: `/user/personInfo` })
export const ipInfoApi = () => request.get({ url: `/user/ipInfo` })
export const roleCreateApi = data => request.post({ url: '/role/create', data }) export const roleCreateApi = data => request.post({ url: '/role/create', data })
export const roleEditApi = data => request.post({ url: '/role/edit', data }) export const roleEditApi = data => request.post({ url: '/role/edit', data })

View 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="1731382660397" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7069" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M810.688 960H213.312A149.376 149.376 0 0 1 64 810.688V312.896a149.376 149.376 0 0 1 149.312-149.312h597.312A149.376 149.376 0 0 1 960 312.896v497.792A149.376 149.376 0 0 1 810.688 960z m99.584-647.104c0-54.976-44.608-99.52-99.584-99.52H213.312c-54.976 0-99.584 44.544-99.584 99.52v497.792c0 54.912 44.544 99.584 99.584 99.584h597.312c54.912 0 99.584-44.608 99.584-99.584V312.896z m-127.616 281.536l28.032 16.128v100.544h-149.376V462.208h149.376v116.032l-28.032 16.192zM760.896 512h-49.728v49.792h49.728V512z m0 99.584h-49.728v49.728h49.728v-49.728z m-199.104 0H462.208v99.584h-49.792v-248.96h199.104v248.896h-49.728V611.584z m0-99.584H462.208v49.792h99.584V512z m-248.896 199.104h-49.792V512h-49.792v-49.792h149.312V512h-49.728v199.104zM113.792 64h497.792v49.792H113.792V64z" p-id="7070"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1 +1,3 @@
<?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="1715769658859" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4704" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M1023.853735 948.673618v75.25325H596.248536V948.673618zM511.926868 0.073132a511.926868 511.926868 0 0 1 511.926867 511.926868h-75.253249a436.600486 436.600486 0 1 0-436.600486 436.600486h5.119269v75.253249h-5.119269a511.926868 511.926868 0 1 1 0-1023.853735z m511.926867 803.505785v75.25325H596.248536v-75.180117zM362.590487 290.116269l192.11884 110.941866 192.11884 110.941865-192.11884 110.941865-192.11884 110.941866V290.189402zM1023.853735 658.484217v75.399514H596.248536V658.630481zM437.843737 420.438223v182.831024l79.202399-45.780888 79.2024-45.707756-79.2024-45.707756z" p-id="4705"></path></svg> <svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M36.6667 5C37.5871 5 38.3333 5.83947 38.3333 6.875V33.125C38.3333 34.1605 37.5871 35 36.6667 35H3.33333C2.41286 35 1.66667 34.1605 1.66667 33.125V6.875C1.66667 5.83947 2.41286 5 3.33333 5H36.6667ZM14.3426 25.5486C14.7543 26.3719 15.7554 26.7057 16.5787 26.294L26.1853 21.4907C26.5078 21.3295 26.7693 21.0679 26.9306 20.7454C27.3423 19.9221 27.0086 18.9209 26.1853 18.5093L16.5787 13.706C16.3473 13.5903 16.0921 13.5301 15.8333 13.5301C14.9129 13.5301 14.1667 14.2763 14.1667 15.1967V24.8033C14.1667 25.062 14.2269 25.3172 14.3426 25.5486ZM10 9.16667H6.66667V14.1667H10V9.16667ZM10 17.5H6.66667V22.5H10V17.5ZM10 25.8333H6.66667V30.8333H10V25.8333ZM33.3333 9.16667H30V14.1667H33.3333V9.16667ZM30 17.5H33.3333V22.5H30V17.5ZM30 25.8333H33.3333V30.8333H30V25.8333Z" />
</svg>

Before

Width:  |  Height:  |  Size: 938 B

After

Width:  |  Height:  |  Size: 904 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 715 B

View File

@ -1,4 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M2.85738 4.85729L9.98911 11.989L2.85738 19.1207C2.66212 19.316 2.66212 19.6326 2.85738 19.8279L3.56449 20.535C3.75975 20.7302 4.07634 20.7302 4.2716 20.535L12.1104 12.6961C12.501 12.3056 12.501 11.6724 12.1104 11.2819L4.2716 3.44308C4.07634 3.24782 3.75975 3.24782 3.56449 3.44308L2.85738 4.15018C2.66212 4.34545 2.66212 4.66203 2.85738 4.85729Z" fill="#1F2329"/> <path d="M2.85738 4.85729L9.98911 11.989L2.85738 19.1207C2.66212 19.316 2.66212 19.6326 2.85738 19.8279L3.56449 20.535C3.75975 20.7302 4.07634 20.7302 4.2716 20.535L12.1104 12.6961C12.501 12.3056 12.501 11.6724 12.1104 11.2819L4.2716 3.44308C4.07634 3.24782 3.75975 3.24782 3.56449 3.44308L2.85738 4.15018C2.66212 4.34545 2.66212 4.66203 2.85738 4.85729Z" />
<path d="M11.7431 4.85729L18.8749 11.989L11.7431 19.1207C11.5479 19.316 11.5479 19.6326 11.7431 19.8279L12.4502 20.535C12.6455 20.7302 12.9621 20.7302 13.1573 20.535L20.9962 12.6961C21.3867 12.3056 21.3867 11.6724 20.9962 11.2819L13.1573 3.44308C12.9621 3.24782 12.6455 3.24782 12.4502 3.44308L11.7431 4.15018C11.5479 4.34545 11.5479 4.66203 11.7431 4.85729Z" fill="#1F2329"/> <path d="M11.7431 4.85729L18.8749 11.989L11.7431 19.1207C11.5479 19.316 11.5479 19.6326 11.7431 19.8279L12.4502 20.535C12.6455 20.7302 12.9621 20.7302 13.1573 20.535L20.9962 12.6961C21.3867 12.3056 21.3867 11.6724 20.9962 11.2819L13.1573 3.44308C12.9621 3.24782 12.6455 3.24782 12.4502 3.44308L11.7431 4.15018C11.5479 4.34545 11.5479 4.66203 11.7431 4.85729Z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 853 B

After

Width:  |  Height:  |  Size: 812 B

View File

@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M21 18.5V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V18.5C3 18.2239 3.22386 18 3.5 18H4.5C4.77614 18 5 18.2239 5 18.5V20H19V18.5C19 18.2239 19.2239 18 19.5 18H20.5C20.7761 18 21 18.2239 21 18.5ZM13 14.0357L16.0105 11.0252C16.2057 10.83 16.5223 10.83 16.7176 11.0252L17.4247 11.7324C17.6199 11.9276 17.6199 12.2442 17.4247 12.4395L12.4749 17.3892C12.3773 17.4868 12.2493 17.5357 12.1214 17.5357C11.9934 17.5357 11.8655 17.4868 11.7678 17.3892L6.81808 12.4395C6.62282 12.2442 6.62282 11.9276 6.81808 11.7324L7.52519 11.0252C7.72045 10.83 8.03703 10.83 8.2323 11.0252L11 13.793V3C11 2.72386 11.2239 2.5 11.5 2.5H12.5C12.7761 2.5 13 2.72386 13 3V14.0357Z" fill="#1F2329"/> <path d="M21 18.5V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V18.5C3 18.2239 3.22386 18 3.5 18H4.5C4.77614 18 5 18.2239 5 18.5V20H19V18.5C19 18.2239 19.2239 18 19.5 18H20.5C20.7761 18 21 18.2239 21 18.5ZM13 14.0357L16.0105 11.0252C16.2057 10.83 16.5223 10.83 16.7176 11.0252L17.4247 11.7324C17.6199 11.9276 17.6199 12.2442 17.4247 12.4395L12.4749 17.3892C12.3773 17.4868 12.2493 17.5357 12.1214 17.5357C11.9934 17.5357 11.8655 17.4868 11.7678 17.3892L6.81808 12.4395C6.62282 12.2442 6.62282 11.9276 6.81808 11.7324L7.52519 11.0252C7.72045 10.83 8.03703 10.83 8.2323 11.0252L11 13.793V3C11 2.72386 11.2239 2.5 11.5 2.5H12.5C12.7761 2.5 13 2.72386 13 3V14.0357Z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 796 B

After

Width:  |  Height:  |  Size: 769 B

View File

@ -1,3 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path d="M7.1518 11.5968C7.31452 11.4341 7.57834 11.4341 7.74106 11.5968L8.33031 12.186C8.49303 12.3487 8.49303 12.6126 8.33031 12.7753L4.99587 16.1086H7.36621C7.59633 16.1086 7.78288 16.2952 7.78288 16.5253V17.3586C7.78288 17.5887 7.59633 17.7753 7.36621 17.7753H3.05555C2.82544 17.7753 2.6171 17.682 2.4663 17.5312C2.3155 17.3804 2.22222 17.1721 2.22222 16.9419V12.6421C2.22222 12.412 2.40877 12.2255 2.63889 12.2255H3.47222C3.70234 12.2255 3.88889 12.412 3.88889 12.6421V14.8586L7.1518 11.5968ZM16.9367 2.22217C17.1668 2.22217 17.3751 2.31544 17.5259 2.46625C17.6767 2.61705 17.77 2.82538 17.77 3.0555V7.35531C17.77 7.58543 17.5835 7.77198 17.3533 7.77198H16.52C16.2899 7.77198 16.1033 7.58543 16.1033 7.35531V5.13888L12.8404 8.40068C12.6777 8.5634 12.4139 8.5634 12.2512 8.40068L11.6619 7.81142C11.4992 7.6487 11.4992 7.38489 11.6619 7.22217L14.9964 3.88883H12.626C12.3959 3.88883 12.2094 3.70229 12.2094 3.47217V2.63883C12.2094 2.40872 12.3959 2.22217 12.626 2.22217H16.9367Z" fill="#1F2329"/> <path d="M7.1518 11.5968C7.31452 11.4341 7.57834 11.4341 7.74106 11.5968L8.33031 12.186C8.49303 12.3487 8.49303 12.6126 8.33031 12.7753L4.99587 16.1086H7.36621C7.59633 16.1086 7.78288 16.2952 7.78288 16.5253V17.3586C7.78288 17.5887 7.59633 17.7753 7.36621 17.7753H3.05555C2.82544 17.7753 2.6171 17.682 2.4663 17.5312C2.3155 17.3804 2.22222 17.1721 2.22222 16.9419V12.6421C2.22222 12.412 2.40877 12.2255 2.63889 12.2255H3.47222C3.70234 12.2255 3.88889 12.412 3.88889 12.6421V14.8586L7.1518 11.5968ZM16.9367 2.22217C17.1668 2.22217 17.3751 2.31544 17.5259 2.46625C17.6767 2.61705 17.77 2.82538 17.77 3.0555V7.35531C17.77 7.58543 17.5835 7.77198 17.3533 7.77198H16.52C16.2899 7.77198 16.1033 7.58543 16.1033 7.35531V5.13888L12.8404 8.40068C12.6777 8.5634 12.4139 8.5634 12.2512 8.40068L11.6619 7.81142C11.4992 7.6487 11.4992 7.38489 11.6619 7.22217L14.9964 3.88883H12.626C12.3959 3.88883 12.2094 3.70229 12.2094 3.47217V2.63883C12.2094 2.40872 12.3959 2.22217 12.626 2.22217H16.9367Z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M9.00839 13.9974C9.28453 13.9974 9.53453 14.1093 9.71549 14.2903C9.89646 14.4712 10.0084 14.7212 10.0084 14.9974V20.1572C10.0084 20.4333 9.78453 20.6572 9.50839 20.6572H8.50839C8.23224 20.6572 8.00839 20.4333 8.00839 20.1572V17.4974L4.09289 21.4116C3.89762 21.6069 3.58104 21.6069 3.38578 21.4116L2.67867 20.7045C2.48341 20.5092 2.48341 20.1927 2.67867 19.9974L6.68001 15.9974H3.83559C3.55945 15.9974 3.33559 15.7735 3.33559 15.4974V14.4974C3.33559 14.2212 3.55945 13.9974 3.83559 13.9974H9.00839ZM19.919 2.58865C20.1142 2.39338 20.4308 2.39338 20.6261 2.58865L21.3332 3.29575C21.5284 3.49102 21.5284 3.8076 21.3332 4.00286L17.3318 8.00286H20.1763C20.4524 8.00286 20.6763 8.22672 20.6763 8.50286V9.50286C20.6763 9.779 20.4524 10.0029 20.1763 10.0029H15.0035C14.7273 10.0029 14.4773 9.89093 14.2964 9.70997C14.1154 9.529 14.0035 9.279 14.0035 9.00286V3.84309C14.0035 3.56695 14.2273 3.34309 14.5035 3.34309H15.5035C15.7796 3.34309 16.0035 3.56695 16.0035 3.84309V6.50281L19.919 2.58865Z" fill="#1F2329"/> <path d="M9.00839 13.9974C9.28453 13.9974 9.53453 14.1093 9.71549 14.2903C9.89646 14.4712 10.0084 14.7212 10.0084 14.9974V20.1572C10.0084 20.4333 9.78453 20.6572 9.50839 20.6572H8.50839C8.23224 20.6572 8.00839 20.4333 8.00839 20.1572V17.4974L4.09289 21.4116C3.89762 21.6069 3.58104 21.6069 3.38578 21.4116L2.67867 20.7045C2.48341 20.5092 2.48341 20.1927 2.67867 19.9974L6.68001 15.9974H3.83559C3.55945 15.9974 3.33559 15.7735 3.33559 15.4974V14.4974C3.33559 14.2212 3.55945 13.9974 3.83559 13.9974H9.00839ZM19.919 2.58865C20.1142 2.39338 20.4308 2.39338 20.6261 2.58865L21.3332 3.29575C21.5284 3.49102 21.5284 3.8076 21.3332 4.00286L17.3318 8.00286H20.1763C20.4524 8.00286 20.6763 8.22672 20.6763 8.50286V9.50286C20.6763 9.779 20.4524 10.0029 20.1763 10.0029H15.0035C14.7273 10.0029 14.4773 9.89093 14.2964 9.70997C14.1154 9.529 14.0035 9.279 14.0035 9.00286V3.84309C14.0035 3.56695 14.2273 3.34309 14.5035 3.34309H15.5035C15.7796 3.34309 16.0035 3.56695 16.0035 3.84309V6.50281L19.919 2.58865Z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,4 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M12.2496 19.1355L5.11783 12.0038L12.2496 4.87206C12.4448 4.6768 12.4448 4.36022 12.2496 4.16495L11.5424 3.45785C11.3472 3.26259 11.0306 3.26259 10.8353 3.45785L2.99651 11.2967C2.60598 11.6872 2.60598 12.3204 2.99651 12.7109L10.8353 20.5497C11.0306 20.745 11.3472 20.745 11.5424 20.5497L12.2496 19.8426C12.4448 19.6474 12.4448 19.3308 12.2496 19.1355Z" fill="#1F2329"/> <path d="M12.2496 19.1355L5.11783 12.0038L12.2496 4.87206C12.4448 4.6768 12.4448 4.36022 12.2496 4.16495L11.5424 3.45785C11.3472 3.26259 11.0306 3.26259 10.8353 3.45785L2.99651 11.2967C2.60598 11.6872 2.60598 12.3204 2.99651 12.7109L10.8353 20.5497C11.0306 20.745 11.3472 20.745 11.5424 20.5497L12.2496 19.8426C12.4448 19.6474 12.4448 19.3308 12.2496 19.1355Z"/>
<path d="M21.1497 19.1355L14.018 12.0038L21.1497 4.87206C21.345 4.6768 21.345 4.36022 21.1497 4.16495L20.4426 3.45785C20.2473 3.26259 19.9307 3.26259 19.7355 3.45785L11.8967 11.2967C11.5061 11.6872 11.5061 12.3204 11.8967 12.7109L19.7355 20.5497C19.9307 20.745 20.2473 20.745 20.4426 20.5497L21.1497 19.8426C21.345 19.6474 21.345 19.3308 21.1497 19.1355Z" fill="#1F2329"/> <path d="M21.1497 19.1355L14.018 12.0038L21.1497 4.87206C21.345 4.6768 21.345 4.36022 21.1497 4.16495L20.4426 3.45785C20.2473 3.26259 19.9307 3.26259 19.7355 3.45785L11.8967 11.2967C11.5061 11.6872 11.5061 12.3204 11.8967 12.7109L19.7355 20.5497C19.9307 20.745 20.2473 20.745 20.4426 20.5497L21.1497 19.8426C21.345 19.6474 21.345 19.3308 21.1497 19.1355Z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 854 B

After

Width:  |  Height:  |  Size: 813 B

View File

@ -1 +1,4 @@
<?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="1726302584557" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6066" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M0 0h938.666667v938.666667H0V0z m64 64v810.666667h810.666667v-810.666667h-810.666667z" fill="#2C82FC" p-id="6067"></path><path d="M170.666667 170.666667h853.333333v853.333333H170.666667z" fill="#2C82FC" p-id="6068"></path><path d="M967.082667 334.208v362.965333l-151.850667-162.986666s-17.962667-21.461333-32.64-21.461334a35.072 35.072 0 0 0-30.506667 17.706667c-4.053333 7.04-73.344 76.330667-207.872 207.872-6.016 4.309333-6.016 4.309333-12.586666 0L413.653333 641.706667s-16.768-14.293333-28.373333-14.293334c-5.930667 0-11.477333 1.621333-16.426667 4.224s-8.917333 6.528-10.496 8.192l-130.816 125.312V284.458667 227.541333h739.541334v106.666667z m-55.68 632.917333H227.541333v-55.68-68.650666l151.381334-144.896c5.077333-4.266667 8.362667-4.565333 13.482666-0.085334l116.224 95.061334c10.026667 7.082667 20.949333 15.786667 29.525334 15.786666 8.576 0 18.773333-2.944 29.781333-13.952l211.242667-211.242666c1.109333 0.128 2.218667 0.384 3.370666 0.384l1.066667-0.085334 183.424 196.906667v79.744h0.042667v106.666667h-55.68z" fill="#FFFFFF" p-id="6069"></path><path d="M758.698667 672.64a35.584 35.584 0 0 1 45.013333 4.437333c1.536 1.578667 4.352 4.736 4.352 4.736l15.104 15.061334a21.461333 21.461333 0 0 1 0 30.208 21.077333 21.077333 0 0 1-24.064 4.010666c-0.469333 0.256-21.162667-19.157333-21.162667-19.157333l-30.08 30.208-63.701333 63.701333c-0.512 0.554667-0.682667 1.322667-1.28 1.834667a21.418667 21.418667 0 0 1-30.165333 0 21.418667 21.418667 0 0 1 0-30.165333l0.341333-0.298667 105.642667-104.576z m84.949333 104.917333c-0.170667-0.042667-0.256-0.213333-0.469333-0.298666a21.418667 21.418667 0 0 1 0-30.165334 21.461333 21.461333 0 0 1 30.208 0l0.256 0.384 0.085333-0.128 9.728 9.770667a21.333333 21.333333 0 0 1-30.165333 30.165333l-9.642667-9.728zM426.666667 312.874667a85.333333 85.333333 0 1 1-0.042667 170.709333A85.333333 85.333333 0 0 1 426.666667 312.874667zM426.666667 426.666667a28.458667 28.458667 0 1 0-0.042667-56.96A28.458667 28.458667 0 0 0 426.666667 426.666667z" fill="#2C82FC" p-id="6070"></path></svg> <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.33251 3.33334C2.41205 3.33334 1.66585 4.07954 1.66585 5.00001V28.3333C1.66585 29.2538 2.41205 30 3.33251 30H29.9992C30.9197 30 31.6658 29.2538 31.6658 28.3333V5.00001C31.6658 4.07954 30.9197 3.33334 29.9992 3.33334H3.33251ZM28.3325 6.66654V21.6668L24.7552 18.0893C24.4297 17.764 23.902 17.764 23.5765 18.0893L18.9218 22.7442C18.5963 23.0697 18.0687 23.0697 17.7432 22.7442L10.5884 15.5893C10.263 15.264 9.73536 15.264 9.40993 15.5893L4.99918 20.0002V6.66654H28.3325ZM21.6658 9.16668C21.2057 9.16668 20.8325 9.53978 20.8325 10V12.5C20.8325 12.9602 21.2057 13.3333 21.6658 13.3333H24.1658C24.626 13.3333 24.9992 12.9602 24.9992 12.5V10C24.9992 9.53978 24.626 9.16668 24.1658 9.16668H21.6658Z" fill="#3370FF"/>
<path d="M38.3333 35C38.3333 35.4603 38.1468 35.8769 37.8452 36.1785C37.5436 36.4801 37.1269 36.6667 36.6667 36.6667H19.1667C18.7064 36.6667 18.3333 36.2936 18.3333 35.8333V34.1667C18.3333 33.7064 18.7064 33.3333 19.1667 33.3333H35V14.1667C35 13.7064 35.3731 13.3333 35.8333 13.3333H37.5C37.9602 13.3333 38.3333 13.7064 38.3333 14.1667V35Z" fill="#3370FF"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1 +1,4 @@
<?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="1726300744320" class="icon" viewBox="0 0 1448 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4293" xmlns:xlink="http://www.w3.org/1999/xlink" width="282.8125" height="200"><path d="M1081.624727 143.803796H302.916849c-49.712078 0-89.96338 40.251302-89.96338 89.96338V892.753234c0 49.712078 40.251302 89.96338 89.96338 89.963379h778.879892c49.712078 0 89.96338-40.251302 89.96338-89.963379V233.767176c-0.172014-49.712078-40.423316-89.96338-90.135394-89.96338M302.744835 203.836721h778.879892c16.513355 0 29.930455 13.417101 29.930455 29.930455V586.568117c-48.335965-39.563245-131.934823-93.059634-232.391063-93.059634-92.543591 0-183.883084 71.729884-272.126323 141.051571-67.601545 53.15236-137.611288 108.196876-186.63531 108.196875-68.805644 0-127.806484-50.572148-147.760121-69.837729V233.767176c0.172014-16.513355 13.589115-29.930455 30.10247-29.930455m778.879892 718.846968H302.744835c-16.513355 0-29.930455-13.417101-29.930456-29.930455v-142.25567c35.950949 25.458088 87.89921 52.120275 147.760121 52.120276 69.837729 0 144.491853-58.656812 223.618344-120.92592 80.33059-63.129179 163.241391-128.322526 235.143289-128.322526 128.838569 0 230.842936 113.357299 231.875021 114.561397l0.516042-0.344028V892.753234c0 16.513355-13.417101 29.930455-30.102469 29.930455m-569.366706-359.165463c66.225433 0 120.065849-53.668402 120.065849-120.065849 0-66.225433-53.668402-120.065849-120.065849-120.065849-66.225433 0-120.065849 53.668402-120.065849 120.065849 0 66.397447 53.668402 120.065849 120.065849 120.065849M512.602049 383.591466c33.026709 0 59.688896 26.662187 59.688897 59.688897 0 33.026709-26.662187 59.688896-59.688897 59.688896-33.026709 0-59.688896-26.662187-59.688896-59.688896 0-33.026709 26.662187-59.688896 59.688896-59.688897m0 0" p-id="4294"></path><path d="M1217.687888 833.236351h-96.843944v-51.08819h96.843944c24.770032 0 45.067697-20.125651 45.067697-44.895683V134.34302c0-24.770032-20.125651-44.895683-45.067697-44.895683h-844.589282c-24.770032 0-44.895683 20.125651-44.895683 44.895683v59.688897H276.942718V134.34302c0-52.980346 43.003528-95.983874 95.983874-95.983873h844.589282c52.980346 0 95.983874 43.003528 95.983874 95.983873v602.909458c0.172014 52.980346-42.831514 95.983874-95.81186 95.983873z" p-id="4295"></path></svg> <svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
<path d="M3.33251 3.33334C2.41205 3.33334 1.66585 4.07954 1.66585 5.00001V28.3333C1.66585 29.2538 2.41205 30 3.33251 30H29.9992C30.9197 30 31.6658 29.2538 31.6658 28.3333V5.00001C31.6658 4.07954 30.9197 3.33334 29.9992 3.33334H3.33251ZM28.3325 6.66654V21.6668L24.7552 18.0893C24.4297 17.764 23.902 17.764 23.5765 18.0893L18.9218 22.7442C18.5963 23.0697 18.0687 23.0697 17.7432 22.7442L10.5884 15.5893C10.263 15.264 9.73536 15.264 9.40993 15.5893L4.99918 20.0002V6.66654H28.3325ZM21.6658 9.16668C21.2057 9.16668 20.8325 9.53978 20.8325 10V12.5C20.8325 12.9602 21.2057 13.3333 21.6658 13.3333H24.1658C24.626 13.3333 24.9992 12.9602 24.9992 12.5V10C24.9992 9.53978 24.626 9.16668 24.1658 9.16668H21.6658Z" />
<path d="M38.3333 35C38.3333 35.4603 38.1468 35.8769 37.8452 36.1785C37.5436 36.4801 37.1269 36.6667 36.6667 36.6667H19.1667C18.7064 36.6667 18.3333 36.2936 18.3333 35.8333V34.1667C18.3333 33.7064 18.7064 33.3333 19.1667 33.3333H35V14.1667C35 13.7064 35.3731 13.3333 35.8333 13.3333H37.5C37.9602 13.3333 38.3333 13.7064 38.3333 14.1667V35Z" />
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1 +1,4 @@
<?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="1726302584557" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6066" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M0 0h938.666667v938.666667H0V0z m64 64v810.666667h810.666667v-810.666667h-810.666667z" fill="#2C82FC" p-id="6067"></path><path d="M170.666667 170.666667h853.333333v853.333333H170.666667z" fill="#2C82FC" p-id="6068"></path><path d="M967.082667 334.208v362.965333l-151.850667-162.986666s-17.962667-21.461333-32.64-21.461334a35.072 35.072 0 0 0-30.506667 17.706667c-4.053333 7.04-73.344 76.330667-207.872 207.872-6.016 4.309333-6.016 4.309333-12.586666 0L413.653333 641.706667s-16.768-14.293333-28.373333-14.293334c-5.930667 0-11.477333 1.621333-16.426667 4.224s-8.917333 6.528-10.496 8.192l-130.816 125.312V284.458667 227.541333h739.541334v106.666667z m-55.68 632.917333H227.541333v-55.68-68.650666l151.381334-144.896c5.077333-4.266667 8.362667-4.565333 13.482666-0.085334l116.224 95.061334c10.026667 7.082667 20.949333 15.786667 29.525334 15.786666 8.576 0 18.773333-2.944 29.781333-13.952l211.242667-211.242666c1.109333 0.128 2.218667 0.384 3.370666 0.384l1.066667-0.085334 183.424 196.906667v79.744h0.042667v106.666667h-55.68z" fill="#FFFFFF" p-id="6069"></path><path d="M758.698667 672.64a35.584 35.584 0 0 1 45.013333 4.437333c1.536 1.578667 4.352 4.736 4.352 4.736l15.104 15.061334a21.461333 21.461333 0 0 1 0 30.208 21.077333 21.077333 0 0 1-24.064 4.010666c-0.469333 0.256-21.162667-19.157333-21.162667-19.157333l-30.08 30.208-63.701333 63.701333c-0.512 0.554667-0.682667 1.322667-1.28 1.834667a21.418667 21.418667 0 0 1-30.165333 0 21.418667 21.418667 0 0 1 0-30.165333l0.341333-0.298667 105.642667-104.576z m84.949333 104.917333c-0.170667-0.042667-0.256-0.213333-0.469333-0.298666a21.418667 21.418667 0 0 1 0-30.165334 21.461333 21.461333 0 0 1 30.208 0l0.256 0.384 0.085333-0.128 9.728 9.770667a21.333333 21.333333 0 0 1-30.165333 30.165333l-9.642667-9.728zM426.666667 312.874667a85.333333 85.333333 0 1 1-0.042667 170.709333A85.333333 85.333333 0 0 1 426.666667 312.874667zM426.666667 426.666667a28.458667 28.458667 0 1 0-0.042667-56.96A28.458667 28.458667 0 0 0 426.666667 426.666667z" fill="#2C82FC" p-id="6070"></path></svg> <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.33251 3.33334C2.41205 3.33334 1.66585 4.07954 1.66585 5.00001V28.3333C1.66585 29.2538 2.41205 30 3.33251 30H29.9992C30.9197 30 31.6658 29.2538 31.6658 28.3333V5.00001C31.6658 4.07954 30.9197 3.33334 29.9992 3.33334H3.33251ZM28.3325 6.66654V21.6668L24.7552 18.0893C24.4297 17.764 23.902 17.764 23.5765 18.0893L18.9218 22.7442C18.5963 23.0697 18.0687 23.0697 17.7432 22.7442L10.5884 15.5893C10.263 15.264 9.73536 15.264 9.40993 15.5893L4.99918 20.0002V6.66654H28.3325ZM21.6658 9.16668C21.2057 9.16668 20.8325 9.53978 20.8325 10V12.5C20.8325 12.9602 21.2057 13.3333 21.6658 13.3333H24.1658C24.626 13.3333 24.9992 12.9602 24.9992 12.5V10C24.9992 9.53978 24.626 9.16668 24.1658 9.16668H21.6658Z" fill="#3370FF"/>
<path d="M38.3333 35C38.3333 35.4603 38.1468 35.8769 37.8452 36.1785C37.5436 36.4801 37.1269 36.6667 36.6667 36.6667H19.1667C18.7064 36.6667 18.3333 36.2936 18.3333 35.8333V34.1667C18.3333 33.7064 18.7064 33.3333 19.1667 33.3333H35V14.1667C35 13.7064 35.3731 13.3333 35.8333 13.3333H37.5C37.9602 13.3333 38.3333 13.7064 38.3333 14.1667V35Z" fill="#3370FF"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -2,7 +2,6 @@
import { useAttrs, computed } from 'vue' import { useAttrs, computed } from 'vue'
import icon_visible_outlined from '@/assets/svg/icon_visible_outlined.svg' import icon_visible_outlined from '@/assets/svg/icon_visible_outlined.svg'
import icon_invisible_outlined from '@/assets/svg/icon_invisible_outlined.svg' import icon_invisible_outlined from '@/assets/svg/icon_invisible_outlined.svg'
import { hIcon } from '@/components/icon-custom'
const attrs = useAttrs() const attrs = useAttrs()
const props = defineProps(['modelValue']) const props = defineProps(['modelValue'])
const emits = defineEmits(['update:modelValue']) const emits = defineEmits(['update:modelValue'])
@ -14,15 +13,12 @@ const value = computed({
emits('update:modelValue', value) emits('update:modelValue', value)
} }
}) })
const iconView = hIcon(icon_visible_outlined)
const iconHide = hIcon(icon_invisible_outlined)
</script> </script>
<template> <template>
<el-input <el-input
:icon-view-custom="iconView" :icon-view-custom="icon_visible_outlined"
:icon-hide-custom="iconHide" :icon-hide-custom="icon_invisible_outlined"
v-bind="attrs" v-bind="attrs"
v-model="value" v-model="value"
/> />

View File

@ -138,7 +138,7 @@ const previewOuter = () => {
return return
} }
canvasSave(() => { canvasSave(() => {
const url = '#/preview?dvId=' + dvInfo.value.id const url = '#/preview?ignoreParams=true&dvId=' + dvInfo.value.id
const newWindow = window.open(url, '_blank') const newWindow = window.open(url, '_blank')
initOpenHandler(newWindow) initOpenHandler(newWindow)
}) })

View File

@ -20,7 +20,7 @@
<el-checkbox <el-checkbox
size="small" size="small"
:effect="themes" :effect="themes"
v-model="colorForm.basicStyle.gradient" v-model="colorForm['basicStyle']['gradient']"
@change="changeColorCase('gradient')" @change="changeColorCase('gradient')"
> >
{{ $t('chart.gradient') }}{{ $t('chart.color') }} {{ $t('chart.gradient') }}{{ $t('chart.color') }}
@ -36,7 +36,7 @@
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes"> <el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider <el-slider
:effect="themes" :effect="themes"
v-model="colorForm.basicStyle.alpha" v-model="colorForm['basicStyle']['alpha']"
@change="changeColorCase('alpha')" @change="changeColorCase('alpha')"
/> />
</el-form-item> </el-form-item>
@ -50,7 +50,7 @@
<el-input <el-input
type="number" type="number"
:effect="themes" :effect="themes"
v-model="colorForm.basicStyle.alpha" v-model="colorForm['basicStyle']['alpha']"
:min="0" :min="0"
:max="100" :max="100"
class="alpha-input-number" class="alpha-input-number"
@ -78,7 +78,7 @@
<el-form-item :label="t('chart.table_header_bg')" class="form-item"> <el-form-item :label="t('chart.table_header_bg')" class="form-item">
<el-color-picker <el-color-picker
:trigger-width="colorPickerWidth" :trigger-width="colorPickerWidth"
v-model="colorForm.tableHeader.tableHeaderBgColor" v-model="colorForm['tableHeader']['tableHeaderBgColor']"
size="small" size="small"
:predefine="predefineColors" :predefine="predefineColors"
is-custom is-custom
@ -91,7 +91,7 @@
<el-form-item :label="t('chart.table_item_bg')" class="form-item"> <el-form-item :label="t('chart.table_item_bg')" class="form-item">
<el-color-picker <el-color-picker
:trigger-width="colorPickerWidth" :trigger-width="colorPickerWidth"
v-model="colorForm.tableCell.tableItemBgColor" v-model="colorForm['tableCell']['tableItemBgColor']"
size="small" size="small"
:predefine="predefineColors" :predefine="predefineColors"
:effect="themes" :effect="themes"
@ -106,7 +106,7 @@
<el-form-item :label="t('chart.table_header_font_color')" class="form-item"> <el-form-item :label="t('chart.table_header_font_color')" class="form-item">
<el-color-picker <el-color-picker
:trigger-width="colorPickerWidth" :trigger-width="colorPickerWidth"
v-model="colorForm.tableHeader.tableHeaderFontColor" v-model="colorForm['tableHeader']['tableHeaderFontColor']"
:effect="themes" :effect="themes"
size="small" size="small"
:predefine="predefineColors" :predefine="predefineColors"
@ -119,7 +119,7 @@
<el-form-item :label="t('chart.table_item_font_color')" class="form-item"> <el-form-item :label="t('chart.table_item_font_color')" class="form-item">
<el-color-picker <el-color-picker
:trigger-width="colorPickerWidth" :trigger-width="colorPickerWidth"
v-model="colorForm.tableCell.tableFontColor" v-model="colorForm['tableCell']['tableFontColor']"
size="small" size="small"
:predefine="predefineColors" :predefine="predefineColors"
:effect="themes" :effect="themes"
@ -134,7 +134,7 @@
<el-form-item :label="t('chart.table_border_color')" class="form-item"> <el-form-item :label="t('chart.table_border_color')" class="form-item">
<el-color-picker <el-color-picker
:trigger-width="colorPickerWidth" :trigger-width="colorPickerWidth"
v-model="colorForm.basicStyle.tableBorderColor" v-model="colorForm.basicStyle['tableBorderColor']"
size="small" size="small"
:predefine="predefineColors" :predefine="predefineColors"
:effect="themes" :effect="themes"
@ -147,7 +147,7 @@
<el-form-item :label="t('chart.table_scroll_bar_color')" class="form-item"> <el-form-item :label="t('chart.table_scroll_bar_color')" class="form-item">
<el-color-picker <el-color-picker
:trigger-width="colorPickerWidth" :trigger-width="colorPickerWidth"
v-model="colorForm.basicStyle.tableScrollBarColor" v-model="colorForm.basicStyle['tableScrollBarColor']"
size="small" size="small"
:predefine="predefineColors" :predefine="predefineColors"
color-format="rgb" color-format="rgb"

View File

@ -180,6 +180,26 @@
:disabled="canvasStyleData.dashboard.resultMode === 'all'" :disabled="canvasStyleData.dashboard.resultMode === 'all'"
/> />
</el-form-item> </el-form-item>
<el-form-item style="margin-top: 16px; margin-bottom: 8px" :class="'form-item-' + themes">
<el-checkbox
:effect="themes"
size="small"
v-model="canvasStyleData.suspensionButtonAvailable"
@change="themeChange"
>
<span class="data-area-label">
<span style="margin-right: 4px"> 显示放大导出等悬浮按钮 </span>
<el-tooltip class="item" :effect="toolTip" placement="bottom">
<template #content>
<div>预览时启用</div>
</template>
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
<Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon>
</el-icon>
</el-tooltip>
</span>
</el-checkbox>
</el-form-item>
</el-form> </el-form>
</template> </template>

View File

@ -349,7 +349,7 @@ const coordinates = ref([]) //坐标点集合
let lastTask = undefined let lastTask = undefined
let isOverlay = false // let isOverlay = false //
let moveTime = 200 // let moveTime = 100 //
const itemMaxY = ref(0) const itemMaxY = ref(0)
let itemMaxX = 0 let itemMaxX = 0
@ -874,6 +874,11 @@ function removeItemById(componentId) {
removeItem(index) removeItem(index)
} }
}) })
if (!isMainCanvas(canvasId.value)) {
nextTick(() => {
canvasInit()
})
}
} }
} }
@ -1514,6 +1519,7 @@ defineExpose({
:style="editStyle" :style="editStyle"
@contextmenu="handleContextMenu" @contextmenu="handleContextMenu"
> >
<slot name="canvasDragTips" />
<drag-info v-if="dragInfoShow"></drag-info> <drag-info v-if="dragInfoShow"></drag-info>
<canvas-opt-bar <canvas-opt-bar
v-if="dvInfo.type === 'dataV'" v-if="dvInfo.type === 'dataV'"

View File

@ -37,8 +37,14 @@ const popComponentDataLength = computed(
) )
const lock = () => { const lock = () => {
if (curComponent.value && !isGroupArea.value) {
lockStore.lock()
} else if (areaData.value.components.length) {
areaData.value.components.forEach(component => {
lockStore.lock(component)
})
}
snapshotStore.recordSnapshotCache() snapshotStore.recordSnapshotCache()
lockStore.lock()
menuOpt('lock') menuOpt('lock')
} }
@ -75,14 +81,26 @@ const copy = () => {
} }
const hide = () => { const hide = () => {
if (curComponent.value && !isGroupArea.value) {
layerStore.hideComponentWithComponent()
} else if (areaData.value.components.length) {
areaData.value.components.forEach(component => {
layerStore.hideComponentWithComponent(component.id)
})
}
snapshotStore.recordSnapshotCache() snapshotStore.recordSnapshotCache()
layerStore.hideComponent()
menuOpt('hide') menuOpt('hide')
} }
const show = () => { const show = () => {
if (curComponent.value && !isGroupArea.value) {
layerStore.showComponent()
} else if (areaData.value.components.length) {
areaData.value.components.forEach(component => {
layerStore.showComponent(component.id)
})
}
snapshotStore.recordSnapshotCache() snapshotStore.recordSnapshotCache()
layerStore.showComponent()
menuOpt('show') menuOpt('show')
} }
const categoryChange = type => { const categoryChange = type => {

View File

@ -19,8 +19,9 @@ import { useEmitt } from '@/hooks/web/useEmitt'
import DatasetParamsComponent from '@/components/visualization/DatasetParamsComponent.vue' import DatasetParamsComponent from '@/components/visualization/DatasetParamsComponent.vue'
import DeFullscreen from '@/components/visualization/common/DeFullscreen.vue' import DeFullscreen from '@/components/visualization/common/DeFullscreen.vue'
import EmptyBackground from '../../empty-background/src/EmptyBackground.vue' import EmptyBackground from '../../empty-background/src/EmptyBackground.vue'
import LinkOptBar from '@/components/data-visualization/canvas/LinkOptBar.vue'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { pcMatrixCount, curComponent, mobileInPc, canvasState } = storeToRefs(dvMainStore) const { pcMatrixCount, curComponent, mobileInPc, canvasState, inMobile } = storeToRefs(dvMainStore)
const openHandler = ref(null) const openHandler = ref(null)
const customDatasetParamsRef = ref(null) const customDatasetParamsRef = ref(null)
const emits = defineEmits(['onResetLayout']) const emits = defineEmits(['onResetLayout'])
@ -77,6 +78,11 @@ const props = defineProps({
isSelector: { isSelector: {
type: Boolean, type: Boolean,
default: false default: false
},
//
showPopBar: {
type: Boolean,
default: false
} }
}) })
@ -90,7 +96,8 @@ const {
previewActive, previewActive,
downloadStatus, downloadStatus,
outerScale, outerScale,
outerSearchCount outerSearchCount,
showPopBar
} = toRefs(props) } = toRefs(props)
const domId = 'preview-' + canvasId.value const domId = 'preview-' + canvasId.value
const scaleWidthPoint = ref(100) const scaleWidthPoint = ref(100)
@ -234,7 +241,8 @@ const resetLayout = () => {
baseComponentData.value, baseComponentData.value,
canvasStyleData.value, canvasStyleData.value,
scaleMin.value || outerScale.value * 100, scaleMin.value || outerScale.value * 100,
scaleMinHeight || outerScale.value * 100 scaleMinHeight || outerScale.value * 100,
outerScale.value * 100
) )
scaleMin.value = isMainCanvas(canvasId.value) ? scaleMin.value : outerScale.value * 100 scaleMin.value = isMainCanvas(canvasId.value) ? scaleMin.value : outerScale.value * 100
} }
@ -393,6 +401,19 @@ const datasetParamsInit = item => {
const dataVPreview = computed( const dataVPreview = computed(
() => dvInfo.value.type === 'dataV' && canvasId.value === 'canvas-main' () => dvInfo.value.type === 'dataV' && canvasId.value === 'canvas-main'
) )
const linkOptBarShow = computed(() => {
return Boolean(
canvasStyleData.value.suspensionButtonAvailable &&
!inMobile.value &&
!mobileInPc.value &&
showPopBar.value
)
})
const downloadAsPDF = () => {
// test
}
defineExpose({ defineExpose({
restore restore
}) })
@ -455,6 +476,13 @@ defineExpose({
<de-fullscreen ref="fullScreeRef"></de-fullscreen> <de-fullscreen ref="fullScreeRef"></de-fullscreen>
<dataset-params-component ref="customDatasetParamsRef"></dataset-params-component> <dataset-params-component ref="customDatasetParamsRef"></dataset-params-component>
<XpackComponent ref="openHandler" jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI=" /> <XpackComponent ref="openHandler" jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI=" />
<link-opt-bar
v-if="linkOptBarShow"
ref="link-opt-bar"
:terminal="'pc'"
:canvas-style-data="canvasStyleData"
@link-export-pdf="downloadAsPDF"
/>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -0,0 +1,242 @@
<template>
<div
id="fullscreenElement"
ref="widget-div"
class="link-bar-main bar-light"
:class="[{ ['link-bar-main-active']: state.barActive }, functionClass]"
:style="{
'--fullWidth': state.fullWidth + 'px',
'--fullContent': 28 - state.fullWidth + 'px',
'--firstHoveMove': 32 - state.fullWidth + 'px'
}"
>
<div class="bar-first">
<el-tooltip :content="state.barActive ? '收起' : '展开'">
<el-icon style="width: 16px; height: 16px" @click="firstBarClick">
<Icon name="icon_down_right_outlined" v-if="state.barActive">
<icon_down_right_outlined />
</Icon>
<Icon name="icon_up_left_outlined" v-else>
<icon_up_left_outlined />
</Icon>
</el-icon>
</el-tooltip>
</div>
<div class="bar-content">
<div class="bar-diver" />
<div v-show="fromLink" class="link-icon-active">
<el-tooltip content="返回上一级">
<el-icon style="width: 16px; height: 16px" @click="back2Last">
<Icon name="icon_left_outlined">
<icon_left_outlined class="svg-icon" />
</Icon>
</el-icon>
</el-tooltip>
</div>
<div class="link-icon-active">
<el-tooltip content="导出PDF">
<el-icon style="width: 16px; height: 16px" @click="exportPDF">
<Icon name="icon_download_outlined">
<icon_download_outlined class="svg-icon" />
</Icon>
</el-icon>
</el-tooltip>
</div>
<div id="fullscreenElement" class="link-icon-active" style="padding-right: 4px">
<el-tooltip :content="fullscreenFlag ? '退出全屏' : '全屏'">
<el-icon style="width: 16px; height: 16px" @click="toggleFullscreen">
<Icon name="icon_minify_outlined" v-if="fullscreenFlag">
<icon_minify_outlined class="svg-icon" />
</Icon>
<Icon name="icon_magnify_outlined" v-else>
<icon_magnify_outlined class="svg-icon" />
</Icon>
</el-icon>
</el-tooltip>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, reactive, toRefs } from 'vue'
import router from '@/router'
import { ElIcon } from 'element-plus-secondary'
import Icon from '../../icon-custom/src/Icon.vue'
import icon_down_right_outlined from '@/assets/svg/icon_down-right_outlined.svg'
import icon_up_left_outlined from '@/assets/svg/icon_up-left_outlined.svg'
import icon_left_outlined from '@/assets/svg/icon_left_outlined.svg'
import icon_download_outlined from '@/assets/svg/icon_download_outlined.svg'
import icon_minify_outlined from '@/assets/svg/icon_minify_outlined.svg'
import icon_magnify_outlined from '@/assets/svg/icon_magnify_outlined.svg'
import { useEmitt } from '@/hooks/web/useEmitt'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
const dvMainStore = dvMainStoreWithOut()
const props = defineProps({
canvasStyleData: {
type: Object,
required: true
}
})
const { canvasStyleData } = toRefs(props)
const { fullscreenFlag } = storeToRefs(dvMainStore)
const state = reactive({
fullscreenElement: null,
barActive: false,
fullWidth: router.currentRoute.value.query?.fromLink === 'true' ? 126 : 94
})
const functionClass = computed(() => {
let result = 'link-bar-main-light'
if (canvasStyleData.value?.dashboard?.themeColor === 'dark') {
result = 'link-bar-main-dark'
}
return result
})
const fromLink = computed(() => {
return router.currentRoute.value.query?.fromLink === 'true'
})
const firstBarClick = () => {
state.barActive = !state.barActive
}
const toggleFullscreen = () => {
if (!document.fullscreenElement) {
//
useEmitt().emitter.emit('canvasFullscreen')
} else {
// 退
document.exitFullscreen().catch(error => {
console.error('Exit fullscreen failed:', error)
})
}
}
const back2Last = () => {
const parentUrl = localStorage.getItem('beforeJumpUrl')
localStorage.removeItem('beforeJumpUrl')
window.location.href = parentUrl
window.location.reload()
}
const exportPDF = () => {
useEmitt().emitter.emit('canvasDownload')
}
</script>
<style lang="less" scoped>
.link-bar-main {
position: fixed;
display: flex;
z-index: 10;
height: 30px;
width: var(--fullWidth);
bottom: 24px;
right: var(--fullContent);
border-top-left-radius: 50%;
border-bottom-left-radius: 50%;
&:hover {
right: var(--firstHoveMove);
}
transition: 0.2s; /* 添加过渡动画 */
}
.link-bar-main-light {
color: rgba(31, 35, 41, 1);
.bar-first {
border-left: 1px solid rgba(222, 224, 227, 1);
border-top: 1px solid rgba(222, 224, 227, 1);
border-bottom: 1px solid rgba(222, 224, 227, 1);
background-color: rgba(255, 255, 255, 1);
}
.bar-content {
border-top: 1px solid rgba(222, 224, 227, 1);
border-bottom: 1px solid rgba(222, 224, 227, 1);
background-color: rgba(255, 255, 255, 1);
.bar-diver {
background: rgba(187, 191, 196, 1);
}
}
}
.link-bar-main-dark {
color: rgba(255, 255, 255, 1);
.bar-first {
border-left: 1px solid rgba(67, 67, 67, 1);
border-top: 1px solid rgba(67, 67, 67, 1);
border-bottom: 1px solid rgba(67, 67, 67, 1);
background-color: rgba(26, 26, 26, 1);
}
.bar-content {
border-top: 1px solid rgba(67, 67, 67, 1);
border-bottom: 1px solid rgba(67, 67, 67, 1);
background-color: rgba(26, 26, 26, 1);
.bar-diver {
background: rgba(95, 95, 95, 1);
}
}
}
.link-bar-main-active {
right: 0px !important;
transition: 0.2s; /* 添加过渡动画 */
}
.bar-first {
width: 36px;
border-top-left-radius: 50%;
border-bottom-left-radius: 50%;
padding: 4px 0 4px 8px;
cursor: pointer;
&:hover {
background: rgba(31, 35, 41, 0.1);
}
}
.bar-diver {
width: 1px;
height: 18px;
}
.bar-content {
display: flex;
align-items: center;
padding-right: 4px;
}
.link-icon-active {
width: 24px;
height: 24px;
cursor: pointer;
transition: 0.1s;
border-radius: 3px;
padding-top: 2px;
padding-left: 2px;
padding-right: 2px;
margin-left: 4px;
text-align: center;
&:active {
color: #000;
border-color: #3a8ee6;
background-color: red;
outline: 0;
}
&:hover {
background-color: rgba(31, 35, 41, 0.1);
color: #3a8ee6;
}
}
</style>

View File

@ -9,7 +9,21 @@
element-loading-background="rgba(255, 255, 255, 1)" element-loading-background="rgba(255, 255, 255, 1)"
@dblclick="handleDbClick" @dblclick="handleDbClick"
> >
<div v-if="showCheck" class="del-from-mobile" @click="delFromMobile"> <div
title="同步PC设计"
v-if="showCheck && ['VQuery'].includes(element.component)"
class="refresh-from-pc"
@click="updateFromMobile($event, 'syncPcDesign')"
>
<el-icon>
<Icon name="icon_replace_outlined"><replaceOutlined class="svg-icon" /></Icon>
</el-icon>
</div>
<div
v-if="showCheck"
class="del-from-mobile"
@click="updateFromMobile($event, 'delFromMobile')"
>
<el-icon> <el-icon>
<Icon name="mobile-checkbox"><mobileCheckbox class="svg-icon" /></Icon> <Icon name="mobile-checkbox"><mobileCheckbox class="svg-icon" /></Icon>
</el-icon> </el-icon>
@ -98,6 +112,7 @@
<script setup lang="ts"> <script setup lang="ts">
import mobileCheckbox from '@/assets/svg/mobile-checkbox.svg' import mobileCheckbox from '@/assets/svg/mobile-checkbox.svg'
import replaceOutlined from '@/assets/svg/icon_replace_outlined.svg'
import dvLock from '@/assets/svg/dv-lock.svg' import dvLock from '@/assets/svg/dv-lock.svg'
import eventBus from '@/utils/eventBus' import eventBus from '@/utils/eventBus'
import calculateComponentPositionAndSize, { import calculateComponentPositionAndSize, {
@ -141,7 +156,8 @@ const {
tabCollisionActiveId, tabCollisionActiveId,
tabMoveInActiveId, tabMoveInActiveId,
tabMoveOutComponentId, tabMoveOutComponentId,
mobileInPc mobileInPc,
mainScrollTop
} = storeToRefs(dvMainStore) } = storeToRefs(dvMainStore)
const { editorMap, areaData, isCtrlOrCmdDown } = storeToRefs(composeStore) const { editorMap, areaData, isCtrlOrCmdDown } = storeToRefs(composeStore)
const emit = defineEmits([ const emit = defineEmits([
@ -282,9 +298,13 @@ const showCheck = computed(() => {
return mobileInPc.value && element.value.canvasId === 'canvas-main' return mobileInPc.value && element.value.canvasId === 'canvas-main'
}) })
const delFromMobile = () => { const updateFromMobile = (e, type) => {
if (type === 'syncPcDesign') {
e.preventDefault()
e.stopPropagation()
}
useEmitt().emitter.emit('onMobileStatusChange', { useEmitt().emitter.emit('onMobileStatusChange', {
type: 'delFromMobile', type: type,
value: element.value.id value: element.value.id
}) })
} }
@ -539,7 +559,7 @@ const handleMouseDownOnShape = e => {
mouseY: mouseY:
!isDashboard() && outerTabDom !isDashboard() && outerTabDom
? outerTabDom.offsetTop + curDom.offsetTop + offsetY + 100 ? outerTabDom.offsetTop + curDom.offsetTop + offsetY + 100
: curY, : curY + mainScrollTop.value,
width: componentWidth, width: componentWidth,
height: componentHeight height: componentHeight
}) })
@ -865,9 +885,7 @@ const componentBackgroundStyle = computed(() => {
innerPadding, innerPadding,
borderRadius borderRadius
} = element.value.commonBackground } = element.value.commonBackground
const innerPaddingTarget = ['Group', 'DeTabs'].includes(element.value.component) const innerPaddingTarget = ['Group'].includes(element.value.component) ? 0 : innerPadding
? 0
: innerPadding
const style = { const style = {
padding: innerPaddingTarget * scale.value + 'px', padding: innerPaddingTarget * scale.value + 'px',
borderRadius: borderRadius + 'px' borderRadius: borderRadius + 'px'
@ -1080,6 +1098,15 @@ onMounted(() => {
<style lang="less" scoped> <style lang="less" scoped>
.shape { .shape {
position: absolute; position: absolute;
.refresh-from-pc {
position: absolute;
right: 38px;
top: 12px;
z-index: 2;
font-size: 16px;
cursor: pointer;
color: var(--ed-color-primary);
}
.del-from-mobile { .del-from-mobile {
position: absolute; position: absolute;
right: 12px; right: 12px;

View File

@ -21,6 +21,27 @@
</div> </div>
</el-checkbox> </el-checkbox>
</el-form-item> </el-form-item>
<el-form-item class="form-item no-margin-bottom" :class="'form-item-' + themes">
<el-checkbox
size="small"
:effect="themes"
v-model="canvasStyleData.suspensionButtonAvailable"
@change="onPopButtonChange"
>
<div style="display: flex; line-height: 14px">
<span style="margin-right: 4px">显示放大导出等悬浮按钮</span>
<el-tooltip class="item" :effect="themes" placement="bottom">
<template #content>
<div>预览时启用</div>
</template>
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
<Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon>
</el-icon>
</el-tooltip>
</div>
</el-checkbox>
</el-form-item>
</el-form> </el-form>
</div> </div>
</template> </template>

View File

@ -47,7 +47,8 @@ const dialogInfo = {
} }
const dialogInit = initInfo => { const dialogInit = initInfo => {
const canvasTypeName = initInfo.canvasType === 'dataV' ? '数据大屏' : '仪表板' const canvasTypeName =
initInfo.canvasType === 'dataV' ? t('work_branch.big_data_screen') : t('work_branch.dashboard')
dialogInfo.resourceId = initInfo.resourceId dialogInfo.resourceId = initInfo.resourceId
dialogInfo.title = '存在未保存的' + canvasTypeName dialogInfo.title = '存在未保存的' + canvasTypeName
dialogInfo.tips = canvasTypeName + '存在未保存的修改,立即恢复?' dialogInfo.tips = canvasTypeName + '存在未保存的修改,立即恢复?'

View File

@ -465,7 +465,9 @@ const { t } = useI18n()
const dialogShow = ref(false) const dialogShow = ref(false)
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const resourceType = computed(() => (dvInfo.value.type === 'dashboard' ? '仪表板' : '数据大屏')) const resourceType = computed(() =>
dvInfo.value.type === 'dashboard' ? t('work_branch.dashboard') : t('work_branch.big_data_screen')
)
const state = reactive({ const state = reactive({
loading: false, loading: false,

View File

@ -205,7 +205,7 @@
<div class="select-filed"> <div class="select-filed">
<el-select <el-select
v-model="itemLinkage.targetField" v-model="itemLinkage.targetField"
:placeholder="'请选择'" :placeholder="t('common.selectText')"
style="width: 100%" style="width: 100%"
> >
<el-option <el-option

View File

@ -166,7 +166,7 @@
filterable filterable
clearable clearable
style="width: 100%" style="width: 100%"
placeholder="请选择" :placeholder="t('common.selectText')"
> >
<template #header> <template #header>
<el-tabs <el-tabs

View File

@ -183,7 +183,8 @@ const DETAIL_CHART_ATTR: DeepPartial<ChartObj> = {
tableCell: { tableCell: {
tableItemBgColor: '#FFFFFF', tableItemBgColor: '#FFFFFF',
tableFontColor: '#7C7E81', tableFontColor: '#7C7E81',
enableTableCrossBG: false enableTableCrossBG: false,
mergeCells: false
}, },
tooltip: { tooltip: {
show: false show: false

View File

@ -16,13 +16,17 @@
import dvDragTips from '@/assets/svg/dv-drag-tips.svg' import dvDragTips from '@/assets/svg/dv-drag-tips.svg'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { dvInfo, mobileInPc } = storeToRefs(dvMainStore) const { dvInfo, mobileInPc } = storeToRefs(dvMainStore)
const tips = const tips =
'从顶部工具栏中选择组件,添加到这里创建' + '从顶部工具栏中选择组件,添加到这里创建' +
(dvInfo.value.type === 'dashboard' ? '仪表板' : '数据大屏') (dvInfo.value.type === 'dashboard'
? t('work_branch.dashboard')
: t('work_branch.big_data_screen'))
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -68,6 +68,7 @@
<div class="indented-item"> <div class="indented-item">
<el-form-item class="form-item" :class="'form-item-' + themes"> <el-form-item class="form-item" :class="'form-item-' + themes">
<el-color-picker <el-color-picker
v-if="state.commonBackground.backgroundColor"
v-model="state.commonBackground.backgroundColor" v-model="state.commonBackground.backgroundColor"
:effect="themes" :effect="themes"
:disabled="!state.commonBackground.backgroundColorSelect" :disabled="!state.commonBackground.backgroundColorSelect"
@ -324,7 +325,6 @@ const upload = file => {
} }
const onBackgroundChange = () => { const onBackgroundChange = () => {
snapshotStore.recordSnapshotCacheToMobile('commonBackground')
emits('onBackgroundChange', state.commonBackground) emits('onBackgroundChange', state.commonBackground)
} }

View File

@ -2,7 +2,7 @@
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { ref } from 'vue' import { ref } from 'vue'
import { personInfoApi } from '@/api/user' import { ipInfoApi } from '@/api/user'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { dvInfo } = storeToRefs(dvMainStore) const { dvInfo } = storeToRefs(dvMainStore)
@ -163,7 +163,7 @@ export function activeWatermarkCheckUser(domId, canvasId, scale = 1) {
scale scale
) )
} else { } else {
personInfoApi().then(res => { ipInfoApi().then(res => {
userInfo.value = res.data userInfo.value = res.data
if (userInfo.value && userInfo.value.model !== 'lose') { if (userInfo.value && userInfo.value.model !== 'lose') {
activeWatermark( activeWatermark(

View File

@ -53,6 +53,7 @@ const dashboardActive = computed(() => {
const onBackgroundChange = val => { const onBackgroundChange = val => {
element.value.commonBackground = val element.value.commonBackground = val
snapshotStore.recordSnapshotCacheToMobile('commonBackground')
emits('onAttrChange', { custom: 'commonBackground' }) emits('onAttrChange', { custom: 'commonBackground' })
} }

View File

@ -290,6 +290,7 @@ import dvStyleHeadFontActiveColor from '@/assets/svg/dv-style-headFontActiveColo
import dvStyleHeadFontColor from '@/assets/svg/dv-style-headFontColor.svg' import dvStyleHeadFontColor from '@/assets/svg/dv-style-headFontColor.svg'
import dvStyleScrollSpeed from '@/assets/svg/dv-style-scroll-speed.svg' import dvStyleScrollSpeed from '@/assets/svg/dv-style-scroll-speed.svg'
import dvStyleOpacity from '@/assets/svg/dv-style-opacity.svg' import dvStyleOpacity from '@/assets/svg/dv-style-opacity.svg'
import dvStyleTabHead from '@/assets/svg/dv-style-tab-head.svg'
import dvStyleFontSize from '@/assets/svg/dv-style-fontSize.svg' import dvStyleFontSize from '@/assets/svg/dv-style-fontSize.svg'
import dvStyleLetterSpacing from '@/assets/svg/dv-style-letterSpacing.svg' import dvStyleLetterSpacing from '@/assets/svg/dv-style-letterSpacing.svg'
import dvStyleActiveFont from '@/assets/svg/dv-style-activeFont.svg' import dvStyleActiveFont from '@/assets/svg/dv-style-activeFont.svg'
@ -371,6 +372,11 @@ const opacitySizeList = [
{ name: '1', value: 1 } { name: '1', value: 1 }
] ]
const titleHideList = [
{ name: '隐藏', value: true },
{ name: '显示', value: false }
]
const styleForm = computed<any>(() => element.value.style) const styleForm = computed<any>(() => element.value.style)
const state = reactive({ const state = reactive({
fontSize: [], fontSize: [],
@ -466,6 +472,13 @@ const styleOptionKeyArray = [
customOption: opacitySizeList, customOption: opacitySizeList,
width: '90px', width: '90px',
icon: dvStyleOpacity icon: dvStyleOpacity
},
{
value: 'titleHide',
label: '标题样式',
customOption: titleHideList,
width: '90px',
icon: dvStyleTabHead
} }
] ]

View File

@ -2,7 +2,12 @@
<div <div
v-if="state.tabShow" v-if="state.tabShow"
style="width: 100%; height: 100%" style="width: 100%; height: 100%"
:class="[headClass, `ed-tabs-${curThemes}`]" :class="[
headClass,
`ed-tabs-${curThemes}`,
{ 'title-hidde-tab': hideTitle },
{ 'title-show-tab': !hideTitle }
]"
class="custom-tabs-head" class="custom-tabs-head"
ref="tabComponentRef" ref="tabComponentRef"
> >
@ -14,8 +19,9 @@
:active-color="activeColor" :active-color="activeColor"
:border-color="noBorderColor" :border-color="noBorderColor"
:border-active-color="borderActiveColor" :border-active-color="borderActiveColor"
:hide-title="hideTitle"
> >
<template :key="tabItem.name" v-for="(tabItem, index) in element.propValue"> <template :key="tabItem.name" v-for="tabItem in element.propValue">
<el-tab-pane <el-tab-pane
class="el-tab-pane-custom" class="el-tab-pane-custom"
:lazy="isEditMode" :lazy="isEditMode"
@ -54,32 +60,39 @@
</el-dropdown> </el-dropdown>
</div> </div>
</template> </template>
<de-canvas
v-if="isEdit && !mobileInPc"
:ref="'tabCanvas_' + index"
:component-data="tabItem.componentData"
:canvas-style-data="canvasStyleData"
:canvas-view-info="canvasViewInfo"
:canvas-id="element.id + '--' + tabItem.name"
:class="moveActive ? 'canvas-move-in' : ''"
:canvas-active="editableTabsValue === tabItem.name"
></de-canvas>
<de-preview
v-else
:ref="'dashboardPreview'"
:dv-info="dvInfo"
:cur-gap="curPreviewGap"
:component-data="tabItem.componentData"
:canvas-style-data="{}"
:canvas-view-info="canvasViewInfo"
:canvas-id="element.id + '--' + tabItem.name"
:preview-active="editableTabsValue === tabItem.name"
:show-position="showPosition"
:outer-scale="scale"
:outer-search-count="searchCount"
></de-preview>
</el-tab-pane> </el-tab-pane>
</template> </template>
<div
style="position: absolute; width: 100%; height: 100%"
:key="tabItem.name + '-content'"
v-for="(tabItem, index) in element.propValue"
:class="{ 'switch-hidden': editableTabsValue !== tabItem.name }"
>
<de-canvas
v-if="isEdit && !mobileInPc"
:ref="'tabCanvas_' + index"
:component-data="tabItem.componentData"
:canvas-style-data="canvasStyleData"
:canvas-view-info="canvasViewInfo"
:canvas-id="element.id + '--' + tabItem.name"
:class="moveActive ? 'canvas-move-in' : ''"
:canvas-active="editableTabsValue === tabItem.name"
></de-canvas>
<de-preview
v-else
:ref="'dashboardPreview'"
:dv-info="dvInfo"
:cur-gap="curPreviewGap"
:component-data="tabItem.componentData"
:canvas-style-data="{}"
:canvas-view-info="canvasViewInfo"
:canvas-id="element.id + '--' + tabItem.name"
:preview-active="editableTabsValue === tabItem.name"
:show-position="showPosition"
:outer-scale="scale"
:outer-search-count="searchCount"
></de-preview>
</div>
</de-custom-tab> </de-custom-tab>
<el-dialog <el-dialog
title="编辑标题" title="编辑标题"
@ -111,6 +124,7 @@ import {
getCurrentInstance, getCurrentInstance,
nextTick, nextTick,
onBeforeMount, onBeforeMount,
onBeforeUnmount,
onMounted, onMounted,
reactive, reactive,
ref, ref,
@ -128,12 +142,13 @@ import DePreview from '@/components/data-visualization/canvas/DePreview.vue'
import { useEmitt } from '@/hooks/web/useEmitt' import { useEmitt } from '@/hooks/web/useEmitt'
import { getPanelAllLinkageInfo } from '@/api/visualization/linkage' import { getPanelAllLinkageInfo } from '@/api/visualization/linkage'
import { dataVTabComponentAdd, groupSizeStyleAdaptor } from '@/utils/style' import { dataVTabComponentAdd, groupSizeStyleAdaptor } from '@/utils/style'
import { copyStoreWithOut, deepCopyTabItemHelper } from '@/store/modules/data-visualization/copy' import { deepCopyTabItemHelper } from '@/store/modules/data-visualization/copy'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut()
const { tabMoveInActiveId, bashMatrixInfo, editMode, mobileInPc } = storeToRefs(dvMainStore) const { tabMoveInActiveId, bashMatrixInfo, editMode, mobileInPc } = storeToRefs(dvMainStore)
const tabComponentRef = ref(null) const tabComponentRef = ref(null)
let carouselTimer = null let carouselTimer = null
const copyStore = copyStoreWithOut()
const props = defineProps({ const props = defineProps({
canvasStyleData: { canvasStyleData: {
@ -202,6 +217,19 @@ const editableTabsValue = ref(null)
const noBorderColor = ref('none') const noBorderColor = ref('none')
let currentInstance let currentInstance
const hideTitle = computed(() => {
if (
element.value &&
element.value.style &&
element.value.style.titleHide &&
typeof element.value.style.titleHide === 'boolean'
) {
return element.value.style.titleHide
} else {
return false
}
})
const isEditMode = computed(() => editMode.value === 'edit' && isEdit.value && !mobileInPc.value) const isEditMode = computed(() => editMode.value === 'edit' && isEdit.value && !mobileInPc.value)
const curThemes = isDashboard() ? 'light' : 'dark' const curThemes = isDashboard() ? 'light' : 'dark'
const calcTabLength = () => { const calcTabLength = () => {
@ -233,6 +261,7 @@ const curPreviewGap = computed(() =>
function sureCurTitle() { function sureCurTitle() {
state.curItem.title = state.textarea state.curItem.title = state.textarea
state.dialogVisible = false state.dialogVisible = false
snapshotStore.recordSnapshotCache()
} }
function addTab() { function addTab() {
@ -245,6 +274,7 @@ function addTab() {
} }
element.value.propValue.push(newTab) element.value.propValue.push(newTab)
editableTabsValue.value = newTab.name editableTabsValue.value = newTab.name
snapshotStore.recordSnapshotCache()
} }
function deleteCur(param) { function deleteCur(param) {
@ -286,9 +316,11 @@ function handleCommand(command) {
break break
case 'deleteCur': case 'deleteCur':
deleteCur(command.param) deleteCur(command.param)
snapshotStore.recordSnapshotCache()
break break
case 'copyCur': case 'copyCur':
copyCur(command.param) copyCur(command.param)
snapshotStore.recordSnapshotCache()
break break
} }
} }
@ -322,8 +354,9 @@ const componentMoveIn = component => {
component.style.left = 0 component.style.left = 0
component.style.top = 0 component.style.top = 0
tabItem.componentData.push(component) tabItem.componentData.push(component)
refInstance.addItemBox(component) //
nextTick(() => { nextTick(() => {
refInstance.addItemBox(component) // refInstance.canvasInitImmediately()
}) })
} }
} else { } else {
@ -496,20 +529,26 @@ onMounted(() => {
editableTabsValue.value = element.value.propValue[0].name editableTabsValue.value = element.value.propValue[0].name
} }
calcTabLength() calcTabLength()
eventBus.on('onTabMoveIn-' + element.value.id, componentMoveIn) if (['canvas', 'canvasDataV', 'edit'].includes(showPosition.value) && !mobileInPc.value) {
eventBus.on('onTabMoveOut-' + element.value.id, componentMoveOut) eventBus.on('onTabMoveIn-' + element.value.id, componentMoveIn)
eventBus.on('onTabSortChange-' + element.value.id, reShow) eventBus.on('onTabMoveOut-' + element.value.id, componentMoveOut)
eventBus.on('onTabSortChange-' + element.value.id, reShow)
}
currentInstance = getCurrentInstance() currentInstance = getCurrentInstance()
initCarousel() initCarousel()
nextTick(() => { nextTick(() => {
groupSizeStyleAdaptor(element.value) groupSizeStyleAdaptor(element.value)
}) })
}) })
onBeforeUnmount(() => {
if (['canvas', 'canvasDataV', 'edit'].includes(showPosition.value) && !mobileInPc.value) {
eventBus.off('onTabMoveIn-' + element.value.id, componentMoveIn)
eventBus.off('onTabMoveOut-' + element.value.id, componentMoveOut)
eventBus.off('onTabSortChange-' + element.value.id, reShow)
}
})
onBeforeMount(() => { onBeforeMount(() => {
eventBus.off('onTabMoveIn-' + element.value.id, componentMoveIn)
eventBus.off('onTabMoveOut-' + element.value.id, componentMoveOut)
eventBus.off('onTabSortChange-' + element.value.id, reShow)
if (carouselTimer) { if (carouselTimer) {
clearInterval(carouselTimer) clearInterval(carouselTimer)
carouselTimer = null carouselTimer = null
@ -517,9 +556,18 @@ onBeforeMount(() => {
}) })
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
:deep(.ed-tabs__content) { .title-hidde-tab {
height: calc(100% - 46px) !important; :deep(.ed-tabs__content) {
height: 100% !important;
}
} }
.title-show-tab {
:deep(.ed-tabs__content) {
height: calc(100% - 46px) !important;
}
}
.ed-tabs-dark { .ed-tabs-dark {
:deep(.ed-tabs__new-tab) { :deep(.ed-tabs__new-tab) {
margin-right: 25px; margin-right: 25px;
@ -537,7 +585,6 @@ onBeforeMount(() => {
} }
.el-tab-pane-custom { .el-tab-pane-custom {
width: 100%; width: 100%;
height: 100%;
} }
.canvas-move-in { .canvas-move-in {
border: 2px dotted transparent; border: 2px dotted transparent;
@ -558,4 +605,9 @@ onBeforeMount(() => {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.switch-hidden {
opacity: 0;
z-index: -1;
}
</style> </style>

View File

@ -7,6 +7,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
const props = defineProps({ const props = defineProps({
hideTitle: Boolean,
/* 颜色可以单词如red也可以是颜色值 */ /* 颜色可以单词如red也可以是颜色值 */
// //
fontColor: String, fontColor: String,
@ -37,7 +38,8 @@ const tabClassName = computed(() =>
props.fontColor && 'fontColor', props.fontColor && 'fontColor',
props.activeColor && 'activeColor', props.activeColor && 'activeColor',
noBorder.value ? 'noBorder' : props.borderColor && 'borderColor', noBorder.value ? 'noBorder' : props.borderColor && 'borderColor',
props.borderActiveColor && 'borderActiveColor' props.borderActiveColor && 'borderActiveColor',
props.hideTitle && 'no-header'
] ]
) )
@ -47,6 +49,11 @@ const noBorder = computed(() => props.borderColor === 'none')
<style lang="less"> <style lang="less">
.de-tabs { .de-tabs {
height: 100%; height: 100%;
&.no-header {
.ed-tabs__header {
display: none;
}
}
&.ed-tabs--card { &.ed-tabs--card {
> .ed-tabs__header { > .ed-tabs__header {
height: auto !important; height: auto !important;

View File

@ -67,7 +67,7 @@ import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const errMsg = ref('') const errMsg = ref('')
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { canvasViewInfo } = storeToRefs(dvMainStore) const { canvasViewInfo, mobileInPc } = storeToRefs(dvMainStore)
const isError = ref(false) const isError = ref(false)
const appearanceStore = useAppearanceStoreWithOut() const appearanceStore = useAppearanceStoreWithOut()
@ -459,7 +459,8 @@ const computedCanEdit = computed<boolean>(() => {
editStatus.value && editStatus.value &&
canEdit.value === false && canEdit.value === false &&
!isError.value && !isError.value &&
!disabled.value !disabled.value &&
!mobileInPc.value
) )
}) })

View File

@ -11,7 +11,7 @@ const { curComponent } = storeToRefs(dvMainStore)
<div class="attr-list"> <div class="attr-list">
<CommonAttr :element="curComponent"></CommonAttr> <CommonAttr :element="curComponent"></CommonAttr>
<div class="content"> <div class="content">
<span>内容</span> <span>{{ $t('visualization.content') }}</span>
<el-input v-model="curComponent['propValue']" type="textarea" :rows="3" /> <el-input v-model="curComponent['propValue']" type="textarea" :rows="3" />
</div> </div>
</div> </div>

View File

@ -2,6 +2,7 @@
import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg' import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg'
import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.svg' import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.svg'
import eventBus from '@/utils/eventBus' import eventBus from '@/utils/eventBus'
import { isMobile } from '@/utils/utils'
import { ElMessage } from 'element-plus-secondary' import { ElMessage } from 'element-plus-secondary'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import QueryConditionConfiguration from './QueryConditionConfiguration.vue' import QueryConditionConfiguration from './QueryConditionConfiguration.vue'
@ -256,6 +257,7 @@ const releaseSelect = id => {
const queryDataForId = id => { const queryDataForId = id => {
let requiredName = '' let requiredName = ''
let numName = ''
const emitterList = (element.value.propValue || []) const emitterList = (element.value.propValue || [])
.filter(ele => ele.id === id) .filter(ele => ele.id === id)
.reduce((pre, next) => { .reduce((pre, next) => {
@ -288,6 +290,22 @@ const queryDataForId = id => {
requiredName = next.name requiredName = next.name
} }
} }
if (next.displayType === '22') {
if (
!isNaN(next.numValueEnd) &&
!isNaN(next.numValueStart) &&
next.numValueEnd < next.numValueStart
) {
numName = next.name
}
if (
[next.numValueEnd, next.numValueStart].filter(itx => ![null, undefined, ''].includes(itx))
.length === 1
) {
requiredName = next.name
}
}
const keyList = Object.entries(next.checkedFieldsMap) const keyList = Object.entries(next.checkedFieldsMap)
.filter(ele => next.checkedFields.includes(ele[0])) .filter(ele => next.checkedFields.includes(ele[0]))
.filter(ele => !!ele[1]) .filter(ele => !!ele[1])
@ -296,7 +314,11 @@ const queryDataForId = id => {
return pre return pre
}, []) }, [])
if (!!requiredName) { if (!!requiredName) {
ElMessage.error(`${requiredName}】查询条件是必填项,请设置选项值后,再进行查询!`) ElMessage.error(`${requiredName}${t('v_query.before_querying')}`)
return
}
if (!!numName) {
ElMessage.error(`${numName}${t('v_query.the_minimum_value')}`)
return return
} }
if (!emitterList.length) return if (!emitterList.length) return
@ -339,6 +361,7 @@ onBeforeUnmount(() => {
}) })
const updateQueryCriteria = () => { const updateQueryCriteria = () => {
if (dvMainStore.mobileInPc && !isMobile()) return
Array.isArray(element.value.propValue) && Array.isArray(element.value.propValue) &&
element.value.propValue.forEach(ele => { element.value.propValue.forEach(ele => {
if (ele.auto) { if (ele.auto) {
@ -380,6 +403,10 @@ onMounted(() => {
emitter.on(`editQueryCriteria${element.value.id}`, editQueryCriteria) emitter.on(`editQueryCriteria${element.value.id}`, editQueryCriteria)
emitter.on(`updateQueryCriteria${element.value.id}`, updateQueryCriteria) emitter.on(`updateQueryCriteria${element.value.id}`, updateQueryCriteria)
updateQueryCriteria() updateQueryCriteria()
if (dvMainStore.mobileInPc && !isMobile()) {
queryData()
}
}) })
const dragover = () => { const dragover = () => {
@ -488,6 +515,9 @@ const clearData = () => {
}) })
}) })
;(list.value || []).reduce((pre, next) => { ;(list.value || []).reduce((pre, next) => {
if (!next.visible) {
return pre
}
next.selectValue = next.multiple || +next.displayType === 7 ? [] : undefined next.selectValue = next.multiple || +next.displayType === 7 ? [] : undefined
if (next.optionValueSource === 1 && next.defaultMapValue?.length) { if (next.optionValueSource === 1 && next.defaultMapValue?.length) {
next.mapValue = next.multiple ? [] : undefined next.mapValue = next.multiple ? [] : undefined
@ -534,6 +564,7 @@ const boxWidth = computed(() => {
const queryData = () => { const queryData = () => {
let requiredName = '' let requiredName = ''
let numName = ''
const emitterList = (element.value.propValue || []).reduce((pre, next) => { const emitterList = (element.value.propValue || []).reduce((pre, next) => {
if (next.required) { if (next.required) {
if (!next.defaultValueCheck) { if (!next.defaultValueCheck) {
@ -564,6 +595,22 @@ const queryData = () => {
requiredName = next.name requiredName = next.name
} }
} }
if (next.displayType === '22') {
if (
!isNaN(next.numValueEnd) &&
!isNaN(next.numValueStart) &&
next.numValueEnd < next.numValueStart
) {
numName = next.name
}
if (
[next.numValueEnd, next.numValueStart].filter(itx => ![null, undefined, ''].includes(itx))
.length === 1
) {
requiredName = next.name
}
}
const keyList = Object.entries(next.checkedFieldsMap) const keyList = Object.entries(next.checkedFieldsMap)
.filter(ele => next.checkedFields.includes(ele[0])) .filter(ele => next.checkedFields.includes(ele[0]))
.filter(ele => !!ele[1]) .filter(ele => !!ele[1])
@ -572,11 +619,18 @@ const queryData = () => {
return pre return pre
}, []) }, [])
if (!!requiredName) { if (!!requiredName) {
ElMessage.error(`${requiredName}】查询条件是必填项,请设置选项值后,再进行查询!`) ElMessage.error(`${requiredName}${t('v_query.before_querying')}`)
return
}
if (!!numName) {
ElMessage.error(`${numName}${t('v_query.the_minimum_value')}`)
return return
} }
if (!emitterList.length) return if (!emitterList.length) return
dvMainStore.setFirstLoadMap([...new Set([...emitterList, ...firstLoadMap.value])]) if (!(dvMainStore.mobileInPc && !isMobile())) {
dvMainStore.setFirstLoadMap([...new Set([...emitterList, ...firstLoadMap.value])])
}
emitterList.forEach(ele => { emitterList.forEach(ele => {
emitter.emit(`query-data-${ele}`) emitter.emit(`query-data-${ele}`)
}) })
@ -640,13 +694,13 @@ const autoStyle = computed(() => {
> >
<div v-if="!listVisible.length" class="no-list-label flex-align-center"> <div v-if="!listVisible.length" class="no-list-label flex-align-center">
<div class="container flex-align-center"> <div class="container flex-align-center">
将右侧的字段拖拽到这里 点击 {{ t('v_query.here_or_click') }}
<el-button <el-button
:disabled="showPosition === 'preview' || mobileInPc" :disabled="showPosition === 'preview' || mobileInPc"
@click="addCriteriaConfigOut" @click="addCriteriaConfigOut"
text text
> >
添加查询条件 {{ t('v_query.add_query_condition') }}
</el-button> </el-button>
</div> </div>
</div> </div>
@ -677,12 +731,16 @@ const autoStyle = computed(() => {
class="label-wrapper-tooltip" class="label-wrapper-tooltip"
v-if="showPosition !== 'preview' && !dvMainStore.mobileInPc" v-if="showPosition !== 'preview' && !dvMainStore.mobileInPc"
> >
<el-tooltip effect="dark" content="设置过滤条件" placement="top"> <el-tooltip
effect="dark"
:content="t('v_query.set_filter_condition')"
placement="top"
>
<el-icon @click="editeQueryConfig(ele.id)"> <el-icon @click="editeQueryConfig(ele.id)">
<Icon name="icon_edit_outlined"><icon_edit_outlined class="svg-icon" /></Icon> <Icon name="icon_edit_outlined"><icon_edit_outlined class="svg-icon" /></Icon>
</el-icon> </el-icon>
</el-tooltip> </el-tooltip>
<el-tooltip effect="dark" content="删除条件" placement="top"> <el-tooltip effect="dark" :content="t('v_query.delete_condition')" placement="top">
<el-icon style="margin-left: 8px" @click="delQueryConfig(index)"> <el-icon style="margin-left: 8px" @click="delQueryConfig(index)">
<Icon name="icon_delete-trash_outlined" <Icon name="icon_delete-trash_outlined"
><icon_deleteTrash_outlined class="svg-icon" ><icon_deleteTrash_outlined class="svg-icon"
@ -865,6 +923,7 @@ const autoStyle = computed(() => {
height: 16px; height: 16px;
line-height: 16px; line-height: 16px;
color: #575757; color: #575757;
white-space: nowrap;
} }
} }

View File

@ -69,15 +69,15 @@ const relativeToCurrentTypeList = computed(() => {
} }
return [ return [
{ {
label: '年', label: t('dynamic_time.year'),
value: 'year' value: 'year'
}, },
{ {
label: '月', label: t('dynamic_time.month'),
value: 'month' value: 'month'
}, },
{ {
label: '日', label: t('dynamic_time.date'),
value: 'date' value: 'date'
} }
].slice(0, index) ].slice(0, index)
@ -90,11 +90,11 @@ const relativeToCurrentList = computed(() => {
case 'year': case 'year':
list = [ list = [
{ {
label: '今年', label: t('dynamic_year.current'),
value: 'thisYear' value: 'thisYear'
}, },
{ {
label: '去年', label: t('dynamic_year.last'),
value: 'lastYear' value: 'lastYear'
} }
] ]
@ -102,11 +102,11 @@ const relativeToCurrentList = computed(() => {
case 'month': case 'month':
list = [ list = [
{ {
label: '本月', label: t('cron.this_month'),
value: 'thisMonth' value: 'thisMonth'
}, },
{ {
label: '上月', label: t('dynamic_month.last'),
value: 'lastMonth' value: 'lastMonth'
} }
] ]
@ -114,19 +114,19 @@ const relativeToCurrentList = computed(() => {
case 'date': case 'date':
list = [ list = [
{ {
label: '今天', label: t('dynamic_time.today'),
value: 'today' value: 'today'
}, },
{ {
label: '昨天', label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{ {
label: '月初', label: t('dynamic_time.firstOfMonth'),
value: 'monthBeginning' value: 'monthBeginning'
}, },
{ {
label: '年初', label: t('dynamic_time.firstOfYear'),
value: 'yearBeginning' value: 'yearBeginning'
} }
] ]
@ -134,19 +134,19 @@ const relativeToCurrentList = computed(() => {
case 'datetime': case 'datetime':
list = [ list = [
{ {
label: '今天', label: t('dynamic_time.today'),
value: 'today' value: 'today'
}, },
{ {
label: '昨天', label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{ {
label: '月初', label: t('dynamic_time.firstOfMonth'),
value: 'monthBeginning' value: 'monthBeginning'
}, },
{ {
label: '年初', label: t('dynamic_time.firstOfYear'),
value: 'yearBeginning' value: 'yearBeginning'
} }
] ]
@ -159,7 +159,7 @@ const relativeToCurrentList = computed(() => {
return [ return [
...list, ...list,
{ {
label: '自定义', label: t('dynamic_time.custom'),
value: 'custom' value: 'custom'
} }
] ]
@ -172,11 +172,11 @@ const relativeToCurrentListRange = computed(() => {
case 'yearrange': case 'yearrange':
list = [ list = [
{ {
label: '今年', label: t('dynamic_year.current'),
value: 'thisYear' value: 'thisYear'
}, },
{ {
label: '去年', label: t('dynamic_year.last'),
value: 'lastYear' value: 'lastYear'
} }
] ]
@ -184,23 +184,23 @@ const relativeToCurrentListRange = computed(() => {
case 'monthrange': case 'monthrange':
list = [ list = [
{ {
label: '本月', label: t('cron.this_month'),
value: 'thisMonth' value: 'thisMonth'
}, },
{ {
label: '上月', label: t('dynamic_month.dynamic_month'),
value: 'lastMonth' value: 'lastMonth'
}, },
{ {
label: '最近 3 个 月', label: t('v_query.last_3_months'),
value: 'LastThreeMonths' value: 'LastThreeMonths'
}, },
{ {
label: '最近 6 个 月', label: t('v_query.last_6_months'),
value: 'LastSixMonths' value: 'LastSixMonths'
}, },
{ {
label: '最近 12 个 月', label: t('v_query.last_12_months'),
value: 'LastTwelveMonths' value: 'LastTwelveMonths'
} }
] ]
@ -209,23 +209,23 @@ const relativeToCurrentListRange = computed(() => {
case 'datetimerange': case 'datetimerange':
list = [ list = [
{ {
label: '今天', label: t('dynamic_time.today'),
value: 'today' value: 'today'
}, },
{ {
label: '昨天', label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{ {
label: '最近 3 天', label: t('v_query.last_3_days'),
value: 'LastThreeDays' value: 'LastThreeDays'
}, },
{ {
label: '月初至今', label: t('v_query.month_to_date'),
value: 'monthBeginning' value: 'monthBeginning'
}, },
{ {
label: '年初至今', label: t('v_query.year_to_date'),
value: 'yearBeginning' value: 'yearBeginning'
} }
] ]
@ -238,7 +238,7 @@ const relativeToCurrentListRange = computed(() => {
return [ return [
...list, ...list,
{ {
label: '自定义', label: t('dynamic_time.custom'),
value: 'custom' value: 'custom'
} }
] ]
@ -246,11 +246,11 @@ const relativeToCurrentListRange = computed(() => {
const aroundList = [ const aroundList = [
{ {
label: '前', label: t('dynamic_time.before'),
value: 'f' value: 'f'
}, },
{ {
label: '后', label: t('dynamic_time.after'),
value: 'b' value: 'b'
} }
] ]
@ -262,11 +262,11 @@ const dynamicTime = computed(() => {
const operators = [ const operators = [
{ {
label: '精确匹配', label: t('v_query.exact_match'),
value: 'eq' value: 'eq'
}, },
{ {
label: '模糊匹配', label: t('v_query.fuzzy_match'),
value: 'like' value: 'like'
} }
] ]
@ -320,18 +320,11 @@ defineExpose({
mult, mult,
single single
}) })
const handleInputStart = value => {
curComponent.value.defaultNumValueStart = value.replace(/[^\d.]/g, '')
}
const handleInputEnd = value => {
curComponent.value.defaultNumValueEnd = value.replace(/[^\d.]/g, '')
}
</script> </script>
<template> <template>
<div class="list-item top-item" v-if="curComponent.displayType === '8'" @click.stop> <div class="list-item top-item" v-if="curComponent.displayType === '8'" @click.stop>
<div class="label">设置默认值</div> <div class="label">{{ t('dynamic_time.set_default') }}</div>
<div class="value" :class="curComponent.hideConditionSwitching && 'hide-condition_switching'"> <div class="value" :class="curComponent.hideConditionSwitching && 'hide-condition_switching'">
<div class="condition-type"> <div class="condition-type">
<el-select <el-select
@ -352,7 +345,9 @@ const handleInputEnd = value => {
<div class="bottom-line"></div> <div class="bottom-line"></div>
</div> </div>
<div class="condition-type" v-if="[1, 2].includes(curComponent.conditionType)"> <div class="condition-type" v-if="[1, 2].includes(curComponent.conditionType)">
<sapn class="condition-type-tip">{{ curComponent.conditionType === 1 ? '与' : '或' }}</sapn> <sapn class="condition-type-tip">{{
curComponent.conditionType === 1 ? t('chart.and') : t('chart.or')
}}</sapn>
<el-select <el-select
v-if="!curComponent.hideConditionSwitching" v-if="!curComponent.hideConditionSwitching"
class="condition-value-select" class="condition-value-select"
@ -374,19 +369,22 @@ const handleInputEnd = value => {
</div> </div>
<div class="list-item top-item" v-if="curComponent.displayType === '22'" @click.stop> <div class="list-item top-item" v-if="curComponent.displayType === '22'" @click.stop>
<div class="label"> <div class="label">
<el-checkbox v-model="curComponent.defaultValueCheck" label="设置默认值" /> <el-checkbox
v-model="curComponent.defaultValueCheck"
:label="t('dynamic_time.set_default')"
/>
</div> </div>
<div class="setting-content" style="display: flex; align-items: center"> <div class="setting-content" style="display: flex; align-items: center">
<el-input-number <el-input-number
:disabled="!curComponent.defaultValueCheck" :disabled="!curComponent.defaultValueCheck"
placeholder="请输入最小值" :placeholder="t('system.the_minimum_value')"
style="width: 192.5px" style="width: 192.5px"
controls-position="right" controls-position="right"
v-model="curComponent.defaultNumValueStart" v-model="curComponent.defaultNumValueStart"
/> />
<div class="num-value_line"></div> <div class="num-value_line"></div>
<el-input-number <el-input-number
placeholder="请输入最大值" :placeholder="t('system.the_maximum_value')"
style="width: 192.5px" style="width: 192.5px"
controls-position="right" controls-position="right"
:disabled="!curComponent.defaultValueCheck" :disabled="!curComponent.defaultValueCheck"
@ -398,7 +396,7 @@ const handleInputEnd = value => {
v-if="!['1', '7', '8', '22'].includes(curComponent.displayType) && showFlag" v-if="!['1', '7', '8', '22'].includes(curComponent.displayType) && showFlag"
class="list-item" class="list-item"
> >
<div class="label">选项类型</div> <div class="label">{{ t('v_query.option_type') }}</div>
<div class="value"> <div class="value">
<el-radio-group <el-radio-group
class="larger-radio" class="larger-radio"
@ -412,7 +410,7 @@ const handleInputEnd = value => {
</div> </div>
<div v-if="curComponent.displayType === '7' && showFlag" class="list-item"> <div v-if="curComponent.displayType === '7' && showFlag" class="list-item">
<div class="label"> <div class="label">
<el-checkbox v-model="curComponent.setTimeRange" label="设置时间筛选范围" /> <el-checkbox v-model="curComponent.setTimeRange" :label="t('v_query.time_filter_range')" />
</div> </div>
<div class="setting-content"> <div class="setting-content">
<el-popover <el-popover
@ -433,7 +431,7 @@ const handleInputEnd = value => {
<template #icon> <template #icon>
<Icon name="icon_admin_outlined"><icon_admin_outlined class="svg-icon" /></Icon> <Icon name="icon_admin_outlined"><icon_admin_outlined class="svg-icon" /></Icon>
</template> </template>
设置 {{ t('dynamic_time.set') }}
</el-button> </el-button>
</template> </template>
<RangeFilterTime <RangeFilterTime
@ -446,7 +444,7 @@ const handleInputEnd = value => {
curComponent.timeRange.intervalType !== 'none' || curComponent.timeRange.dynamicWindow curComponent.timeRange.intervalType !== 'none' || curComponent.timeRange.dynamicWindow
" "
class="config-flag range-filter-time-flag" class="config-flag range-filter-time-flag"
>已配置</span >{{ t('v_query.configured') }}</span
> >
</div> </div>
</div> </div>
@ -457,21 +455,24 @@ const handleInputEnd = value => {
<div class="label"> <div class="label">
<el-tooltip <el-tooltip
effect="dark" effect="dark"
content="绑定参数后,不支持传空数据" :content="t('v_query.is_not_supported')"
:disabled="!curComponent.parametersCheck" :disabled="!curComponent.parametersCheck"
placement="top" placement="top"
> >
<el-checkbox <el-checkbox
:disabled="curComponent.parametersCheck" :disabled="curComponent.parametersCheck"
v-model="curComponent.showEmpty" v-model="curComponent.showEmpty"
label="选项值包含空数据" :label="t('v_query.contains_empty_data')"
/> />
</el-tooltip> </el-tooltip>
</div> </div>
</div> </div>
<div v-if="!['8', '22'].includes(curComponent.displayType)" class="list-item"> <div v-if="!['8', '22'].includes(curComponent.displayType)" class="list-item">
<div class="label"> <div class="label">
<el-checkbox v-model="curComponent.defaultValueCheck" label="设置默认值" /> <el-checkbox
v-model="curComponent.defaultValueCheck"
:label="t('dynamic_time.set_default')"
/>
</div> </div>
<div <div
class="setting-content" class="setting-content"
@ -479,13 +480,13 @@ const handleInputEnd = value => {
> >
<div class="setting"> <div class="setting">
<el-radio-group @change="handleTimeTypeChange" v-model="curComponent.timeType"> <el-radio-group @change="handleTimeTypeChange" v-model="curComponent.timeType">
<el-radio label="fixed">固定时间</el-radio> <el-radio label="fixed">{{ t('dynamic_time.fix') }}</el-radio>
<el-radio label="dynamic">动态时间</el-radio> <el-radio label="dynamic">{{ t('dynamic_time.dynamic') }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<template v-if="dynamicTime && curComponent.displayType === '1'"> <template v-if="dynamicTime && curComponent.displayType === '1'">
<div class="setting"> <div class="setting">
<div class="setting-label">相对当前</div> <div class="setting-label">{{ t('dynamic_time.relative') }}</div>
<div class="setting-value select"> <div class="setting-value select">
<el-select @focus="handleDialogClick" v-model="curComponent.relativeToCurrent"> <el-select @focus="handleDialogClick" v-model="curComponent.relativeToCurrent">
<el-option <el-option
@ -533,7 +534,7 @@ const handleInputEnd = value => {
</template> </template>
<template v-else-if="dynamicTime && curComponent.displayType === '7'"> <template v-else-if="dynamicTime && curComponent.displayType === '7'">
<div class="setting"> <div class="setting">
<div class="setting-label">相对当前</div> <div class="setting-label">{{ t('dynamic_time.relative') }}</div>
<div class="setting-value select"> <div class="setting-value select">
<el-select @focus="handleDialogClick" v-model="curComponent.relativeToCurrentRange"> <el-select @focus="handleDialogClick" v-model="curComponent.relativeToCurrentRange">
<el-option <el-option
@ -554,7 +555,7 @@ const handleInputEnd = value => {
) && 'is-year-month-range' ) && 'is-year-month-range'
" "
> >
<div class="setting-label">开始时间</div> <div class="setting-label">{{ t('datasource.start_time') }}</div>
<div class="setting-input with-date range"> <div class="setting-input with-date range">
<el-input-number <el-input-number
step-strictly step-strictly
@ -590,7 +591,7 @@ const handleInputEnd = value => {
) && 'is-year-month-range' ) && 'is-year-month-range'
" "
> >
<div class="setting-label">结束时间</div> <div class="setting-label">{{ t('datasource.end_time') }}</div>
<div class="setting-input with-date range"> <div class="setting-input with-date range">
<el-input-number <el-input-number
v-model="curComponent.timeNumRange" v-model="curComponent.timeNumRange"
@ -620,7 +621,7 @@ const handleInputEnd = value => {
</template> </template>
</div> </div>
<div v-if="curComponent.defaultValueCheck" class="parameters" :class="dynamicTime && 'setting'"> <div v-if="curComponent.defaultValueCheck" class="parameters" :class="dynamicTime && 'setting'">
<div class="setting-label" v-if="dynamicTime">预览</div> <div class="setting-label" v-if="dynamicTime">{{ t('template_manage.preview') }}</div>
<div :class="dynamicTime ? 'setting-value' : 'w100'"> <div :class="dynamicTime ? 'setting-value' : 'w100'">
<component :config="curComponent" isConfig ref="inputCom" :is="filterTypeCom"></component> <component :config="curComponent" isConfig ref="inputCom" :is="filterTypeCom"></component>
</div> </div>

View File

@ -2,6 +2,7 @@
import { toRefs, onBeforeMount, type PropType, type Ref, inject, computed, nextTick } from 'vue' import { toRefs, onBeforeMount, type PropType, type Ref, inject, computed, nextTick } from 'vue'
interface SelectConfig { interface SelectConfig {
id: string id: string
defaultValueCheck: boolean
defaultNumValueEnd: number defaultNumValueEnd: number
numValueEnd: number numValueEnd: number
numValueStart: number numValueStart: number
@ -11,7 +12,7 @@ interface SelectConfig {
const placeholder: Ref = inject('placeholder') const placeholder: Ref = inject('placeholder')
const placeholderText = computed(() => { const placeholderText = computed(() => {
if (placeholder.value.placeholderShow) { if (placeholder?.value?.placeholderShow) {
return props.config.placeholder return props.config.placeholder
} }
return ' ' return ' '
@ -26,7 +27,8 @@ const props = defineProps({
defaultNumValueEnd: '', defaultNumValueEnd: '',
defaultNumValueStart: '', defaultNumValueStart: '',
numValueEnd: '', numValueEnd: '',
numValueStart: '' numValueStart: '',
defaultValueCheck: false
} }
} }
}, },
@ -38,6 +40,11 @@ const props = defineProps({
const { config } = toRefs(props) const { config } = toRefs(props)
const setParams = () => { const setParams = () => {
if (!config.value.defaultValueCheck) {
config.value.numValueEnd = undefined
config.value.numValueStart = undefined
return
}
const { defaultNumValueEnd, defaultNumValueStart } = config.value const { defaultNumValueEnd, defaultNumValueStart } = config.value
config.value.numValueEnd = defaultNumValueEnd config.value.numValueEnd = defaultNumValueEnd
config.value.numValueStart = defaultNumValueStart config.value.numValueStart = defaultNumValueStart

View File

@ -36,7 +36,7 @@ const cancelClick = () => {
const confirmClick = () => { const confirmClick = () => {
const { isError, arr } = setCascadeArrBack() const { isError, arr } = setCascadeArrBack()
if (isError) { if (isError) {
ElMessage.error('查询条件或字段不能为空!') ElMessage.error(t('v_query.cannot_be_empty'))
return return
} }
emits('saveCascade', arr) emits('saveCascade', arr)
@ -141,7 +141,7 @@ const addCascadeItem = item => {
item.push({ item.push({
datasetId: '', datasetId: '',
fieldId: '', fieldId: '',
placeholder: item.length ? '' : '第一级无需配置被级联字段', placeholder: item.length ? '' : t('v_query.the_first_level'),
id: guid() id: guid()
}) })
} }
@ -158,7 +158,7 @@ const setPlaceholder = () => {
item.datasetId && item.datasetId &&
item.datasetId.split('--')[0] === ele[idx - 1].datasetId.split('--')[0] item.datasetId.split('--')[0] === ele[idx - 1].datasetId.split('--')[0]
) { ) {
item.placeholder = '与上一级使用同一个数据集,无需配置被级联字段' item.placeholder = t('v_query.configure_cascaded_fields')
item.fieldId = '' item.fieldId = ''
} }
}) })
@ -168,7 +168,7 @@ const setPlaceholder = () => {
const deleteCascade = (idx, item) => { const deleteCascade = (idx, item) => {
item.splice(idx, 1) item.splice(idx, 1)
item[0].fieldId = '' item[0].fieldId = ''
item[0].placeholder = '第一级无需配置被级联字段' item[0].placeholder = t('v_query.the_first_level')
setPlaceholder() setPlaceholder()
} }
@ -182,7 +182,14 @@ const addCascadeBlock = () => {
cascadeList.value.push(arr) cascadeList.value.push(arr)
} }
const indexCascade = ' 一二三四五' const indexCascade = [
' ',
t('report.week_mon'),
t('report.week_tue'),
t('report.week_wed'),
t('report.week_thu'),
t('report.week_fri')
]
defineExpose({ defineExpose({
init init
@ -201,21 +208,22 @@ defineExpose({
> >
<template #title> <template #title>
<div class="title"> <div class="title">
查询条件级联配置<span class="tip">(仅上级能级联下级,不可反向级联)</span> {{ t('v_query.condition_cascade_configuration')
}}<span class="tip">{{ t('v_query.not_reverse_cascade') }}</span>
</div> </div>
</template> </template>
<div class="content"> <div class="content">
<el-icon style="font-size: 16px"> <el-icon style="font-size: 16px">
<Icon name="icon_info_colorful"><icon_info_colorful class="svg-icon" /></Icon> <Icon name="icon_info_colorful"><icon_info_colorful class="svg-icon" /></Icon>
</el-icon> </el-icon>
基于当前查询组件的查询条件如果需要进行级联配置需要满足以下条件<br /> {{ t('v_query.must_be_met') }}<br />
1. 展示类型文本下拉组件和数字下拉组件2. 选项值来源选择数据集<br /> {{ t('v_query.select_data_set') }}<br />
</div> </div>
<el-button text @click="addCascadeBlock"> <el-button text @click="addCascadeBlock">
<template #icon> <template #icon>
<Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon> <Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon>
</template> </template>
添加级联配置 {{ t('v_query.add_cascade_configuration') }}
</el-button> </el-button>
<div class="cascade-content" v-for="(item, index) in cascadeList" :key="index"> <div class="cascade-content" v-for="(item, index) in cascadeList" :key="index">
<div style="display: flex; align-items: center; justify-content: space-between"> <div style="display: flex; align-items: center; justify-content: space-between">
@ -223,7 +231,7 @@ defineExpose({
<template #icon> <template #icon>
<Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon> <Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon>
</template> </template>
添加级联条件 {{ t('v_query.add_cascade_condition') }}
</el-button> </el-button>
<el-button @click="deleteCascadeBlock(index)" class="cascade-delete-block" text> <el-button @click="deleteCascadeBlock(index)" class="cascade-delete-block" text>
<template #icon> <template #icon>
@ -234,13 +242,13 @@ defineExpose({
</el-button> </el-button>
</div> </div>
<div class="cascade-item"> <div class="cascade-item">
<div class="label">查询条件层级</div> <div class="label">{{ t('v_query.query_condition_level') }}</div>
<div class="item-name">请选择查询条件</div> <div class="item-name">{{ t('v_query.select_query_condition') }}</div>
<div class="cascade-icon"></div> <div class="cascade-icon"></div>
<div class="item-field">请选择被级联字段</div> <div class="item-field">{{ t('v_query.select_cascaded_field') }}</div>
</div> </div>
<div class="cascade-item" v-for="(ele, idx) in item" :key="ele.id"> <div class="cascade-item" v-for="(ele, idx) in item" :key="ele.id">
<div class="label">{{ indexCascade[idx + 1] }}</div> <div class="label">{{ t('v_query.level_1', { msg: indexCascade[idx + 1] }) }}</div>
<div class="item-name"> <div class="item-name">
<el-select <el-select
@visible-change="val => visibleChange(val, index, idx)" @visible-change="val => visibleChange(val, index, idx)"

View File

@ -307,11 +307,11 @@ const showDatasetError = computed(() => {
}) })
const typeList = [ const typeList = [
{ {
label: '重命名', label: t('data_fill.rename'),
command: 'rename' command: 'rename'
}, },
{ {
label: '删除', label: t('data_fill.delete'),
command: 'del' command: 'del'
} }
] ]
@ -684,13 +684,13 @@ const setParameters = field => {
Object.values(field?.fields || {}) Object.values(field?.fields || {})
.flat() .flat()
.filter(ele => fieldArr.includes(ele.id) && !!ele.variableName) .filter(ele => fieldArr.includes(ele.id) && !!ele.variableName)
.concat(curComponent.value.parameters.filter(ele => fieldArr.includes(ele.id)))
) )
nextTick(() => { nextTick(() => {
if (isTimeParameter.value) { if (isTimeParameter.value) {
const timeParameter = curComponent.value.parameters.find(ele => ele.deType === 1)
curComponent.value.timeGranularity = curComponent.value.timeGranularity =
typeTimeMap[ typeTimeMap[timeParameter.type[1] || timeParameter.type[0]]
curComponent.value.parameters[0].type[1] || curComponent.value.parameters[0].type[0]
]
curComponent.value.displayType = '1' curComponent.value.displayType = '1'
} }
@ -831,19 +831,19 @@ const notTimeRangeType = computed(() => {
const timeList = [ const timeList = [
{ {
label: '年', label: t('dynamic_time.year'),
value: 'year' value: 'year'
}, },
{ {
label: '年月', label: t('chart.y_M'),
value: 'month' value: 'month'
}, },
{ {
label: '年月日', label: t('chart.y_M_d'),
value: 'date' value: 'date'
}, },
{ {
label: '年月日时分秒', label: t('chart.y_M_d_H_m_s'),
value: 'datetime' value: 'datetime'
} }
] ]
@ -924,17 +924,14 @@ const confirmIdChange = () => {
const handleDatasetChange = () => { const handleDatasetChange = () => {
if (!!newDatasetId && !!oldDatasetId) { if (!!newDatasetId && !!oldDatasetId) {
curComponent.value.dataset.id = oldDatasetId curComponent.value.dataset.id = oldDatasetId
ElMessageBox.confirm( ElMessageBox.confirm(t('v_query.to_modify_it'), {
'数据集的修改,会导致级联配置失效,因此对应的级联关系将被清除,确定修改吗?', confirmButtonType: 'primary',
{ type: 'warning',
confirmButtonType: 'primary', confirmButtonText: t('commons.confirm'),
type: 'warning', cancelButtonText: t('commons.cancel'),
confirmButtonText: '确定', autofocus: false,
cancelButtonText: '取消', showClose: false
autofocus: false, }).then(() => {
showClose: false
}
).then(() => {
confirmIdChange() confirmIdChange()
}) })
return return
@ -1115,7 +1112,14 @@ const clearCascadeArrDataset = id => {
cascadeArr = cascadeArr.filter(ele => !!ele.length) cascadeArr = cascadeArr.filter(ele => !!ele.length)
} }
const indexCascade = ' 一二三四五' const indexCascade = [
' ',
t('report.week_mon'),
t('report.week_tue'),
t('report.week_wed'),
t('report.week_thu'),
t('report.week_fri')
]
const validateConditionType = ({ const validateConditionType = ({
defaultConditionValueF, defaultConditionValueF,
@ -1146,11 +1150,31 @@ const validate = () => {
return conditions.value.some(ele => { return conditions.value.some(ele => {
if (ele.auto) return false if (ele.auto) return false
if (!ele.checkedFields?.length || ele.checkedFields.some(itx => !ele.checkedFieldsMap[itx])) { if (!ele.checkedFields?.length || ele.checkedFields.some(itx => !ele.checkedFieldsMap[itx])) {
ElMessage.error('请先勾选需要联动的图表及字段') ElMessage.error(t('v_query.be_linked_first'))
return true return true
} }
if (ele.displayType === '22' && ele.defaultValueCheck) {
ele.numValueEnd = ele.defaultNumValueEnd
ele.numValueStart = ele.defaultNumValueStart
if (
(ele.defaultNumValueEnd !== 0 && !ele.defaultNumValueEnd) ||
(ele.defaultNumValueStart !== 0 && !ele.defaultNumValueStart)
) {
ElMessage.error(t('v_query.cannot_be_empty_de'))
return true
}
if (
!isNaN(ele.defaultNumValueEnd) &&
!isNaN(ele.defaultNumValueStart) &&
ele.defaultNumValueEnd < ele.defaultNumValueStart
) {
ElMessage.error(t('v_query.the_minimum_value'))
return true
}
}
let displayTypeField = null let displayTypeField = null
let errorTips = '所选字段类型不一致,无法进行查询配置' let errorTips = t('v_query.cannot_be_performed')
let hasParameterTimeArrType = 0 let hasParameterTimeArrType = 0
let hasParameterNumArrType = 0 let hasParameterNumArrType = 0
if ( if (
@ -1180,7 +1204,7 @@ const validate = () => {
} }
if (ele.checkedFieldsMapArrNum?.[id]?.length === 1 && ele.displayType === '22') { if (ele.checkedFieldsMapArrNum?.[id]?.length === 1 && ele.displayType === '22') {
errorTips = '数值参数配置必须配置最大值和最小值' errorTips = t('v_query.numerical_parameter_configuration')
return true return true
} }
@ -1209,7 +1233,7 @@ const validate = () => {
} }
if (ele.checkedFieldsMapArr?.[id]?.length === 1 && ele.displayType === '7') { if (ele.checkedFieldsMapArr?.[id]?.length === 1 && ele.displayType === '7') {
errorTips = '时间参数配置必须配置开始时间和结束时间' errorTips = t('v_query.and_end_time')
return true return true
} }
@ -1228,12 +1252,12 @@ const validate = () => {
return false return false
} }
if (displayTypeField.type?.length !== field.type?.length) { if (displayTypeField.type?.length !== field.type?.length) {
errorTips = '时间格式不一致' errorTips = t('v_query.format_is_inconsistent')
return true return true
} }
for (let index = 0; index < displayTypeField.type.length; index++) { for (let index = 0; index < displayTypeField.type.length; index++) {
if (displayTypeField.type[index] !== field.type[index]) { if (displayTypeField.type[index] !== field.type[index]) {
errorTips = '时间格式不一致' errorTips = t('v_query.format_is_inconsistent')
return true return true
} }
} }
@ -1250,13 +1274,13 @@ const validate = () => {
setParams(ele) setParams(ele)
const result = validateConditionType(ele) const result = validateConditionType(ele)
if (result) { if (result) {
ElMessage.error('查询条件为必填项,默认值不能为空') ElMessage.error(t('v_query.cannot_be_empty_de'))
} }
return result return result
} }
if (!ele.defaultValueCheck) { if (!ele.defaultValueCheck) {
ElMessage.error('查询条件为必填项,默认值不能为空') ElMessage.error(t('v_query.cannot_be_empty_de'))
return true return true
} }
@ -1265,7 +1289,7 @@ const validate = () => {
(ele.defaultNumValueEnd !== 0 && !ele.defaultNumValueEnd) || (ele.defaultNumValueEnd !== 0 && !ele.defaultNumValueEnd) ||
(ele.defaultNumValueStart !== 0 && !ele.defaultNumValueStart) (ele.defaultNumValueStart !== 0 && !ele.defaultNumValueStart)
) { ) {
ElMessage.error('查询条件为必填项,默认值不能为空') ElMessage.error(t('v_query.cannot_be_empty_de'))
return true return true
} }
return false return false
@ -1275,7 +1299,7 @@ const validate = () => {
(Array.isArray(ele.defaultValue) && !ele.defaultValue.length) || (Array.isArray(ele.defaultValue) && !ele.defaultValue.length) ||
(ele.defaultValue !== 0 && !ele.defaultValue) (ele.defaultValue !== 0 && !ele.defaultValue)
) { ) {
ElMessage.error('查询条件为必填项,默认值不能为空') ElMessage.error(t('v_query.cannot_be_empty_de'))
return true return true
} }
} }
@ -1295,7 +1319,7 @@ const validate = () => {
if (!ele.defaultValueCheck) return false if (!ele.defaultValueCheck) return false
if (ele.timeType === 'fixed') { if (ele.timeType === 'fixed') {
if (!ele.defaultValue) { if (!ele.defaultValue) {
ElMessage.error('默认时间不能为空!') ElMessage.error(t('v_query.cannot_be_empty_time'))
return true return true
} }
} }
@ -1306,7 +1330,7 @@ const validate = () => {
if (ele.timeType === 'fixed') { if (ele.timeType === 'fixed') {
const [s, e] = ele.defaultValue || [] const [s, e] = ele.defaultValue || []
if (!s || !e) { if (!s || !e) {
ElMessage.error('默认时间不能为空!') ElMessage.error(t('v_query.cannot_be_empty_time'))
return true return true
} }
} }
@ -1353,7 +1377,7 @@ const validate = () => {
;[startTime, endTime] = getCustomRange(relativeToCurrentRange) ;[startTime, endTime] = getCustomRange(relativeToCurrentRange)
} }
if (+startTime > +endTime) { if (+startTime > +endTime) {
ElMessage.error('结束时间必须大于开始时间!') ElMessage.error(t('v_query.the_start_time'))
return true return true
} }
if (!ele.setTimeRange) return false if (!ele.setTimeRange) return false
@ -1368,7 +1392,7 @@ const validate = () => {
: +endTime : +endTime
) )
) { ) {
ElMessage.error('默认值超出日期筛选范围内,请重新设置!') ElMessage.error(t('v_query.range_please_reset'))
return true return true
} }
return false return false
@ -1383,12 +1407,14 @@ const validate = () => {
ele.optionValueSource === 2 && ele.optionValueSource === 2 &&
!ele.valueSource?.filter(ele => !!ele).length !ele.valueSource?.filter(ele => !!ele).length
) { ) {
ElMessage.error('手工输入-选项值不能为空') ElMessage.error(t('v_query.cannot_be_empty_input'))
return true return true
} }
if (!['9', '22'].includes(ele.displayType) && ele.optionValueSource === 1 && !ele.field.id) { if (!['9', '22'].includes(ele.displayType) && ele.optionValueSource === 1 && !ele.field.id) {
ElMessage.error(!ele.dataset?.id ? '请选择数据集及选项值字段' : '请选择数据集的选项值字段') ElMessage.error(
!ele.dataset?.id ? t('v_query.option_value_field') : t('v_query.the_data_set')
)
return true return true
} }
}) })
@ -1455,7 +1481,7 @@ const confirmValueSource = () => {
return false return false
}) })
) { ) {
ElMessage.error('手工输入-选项值不能为空') ElMessage.error(t('v_query.cannot_be_empty_input'))
return return
} }
@ -1728,10 +1754,9 @@ const startTreeDesign = () => {
const [comId] = curComponent.value.checkedFields const [comId] = curComponent.value.checkedFields
const componentObj = fields.value.find(ele => ele.componentId === comId) const componentObj = fields.value.find(ele => ele.componentId === comId)
treeDialog.value.init( treeDialog.value.init(
(curComponent.value.optionValueSource === 0 componentObj?.fields?.dimensionList.filter(
? componentObj?.fields?.dimensionList ele => ele.deType === +curComponent.value.field.deType
: curComponent.value.dataset?.fields ),
).filter(ele => ele.deType === +curComponent.value.field.deType),
curComponent.value.treeFieldList curComponent.value.treeFieldList
) )
} }
@ -1776,11 +1801,11 @@ const relativeToCurrentList = computed(() => {
case 'year': case 'year':
list = [ list = [
{ {
label: '今年', label: t('dynamic_year.current'),
value: 'thisYear' value: 'thisYear'
}, },
{ {
label: '去年', label: t('dynamic_year.last'),
value: 'lastYear' value: 'lastYear'
} }
] ]
@ -1788,11 +1813,11 @@ const relativeToCurrentList = computed(() => {
case 'month': case 'month':
list = [ list = [
{ {
label: '本月', label: t('cron.this_month'),
value: 'thisMonth' value: 'thisMonth'
}, },
{ {
label: '上月', label: t('dynamic_month.last'),
value: 'lastMonth' value: 'lastMonth'
} }
] ]
@ -1800,19 +1825,19 @@ const relativeToCurrentList = computed(() => {
case 'date': case 'date':
list = [ list = [
{ {
label: '今天', label: t('dynamic_time.today'),
value: 'today' value: 'today'
}, },
{ {
label: '昨天', label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{ {
label: '月初', label: t('dynamic_time.firstOfMonth'),
value: 'monthBeginning' value: 'monthBeginning'
}, },
{ {
label: '年初', label: t('dynamic_time.firstOfYear'),
value: 'yearBeginning' value: 'yearBeginning'
} }
] ]
@ -1820,19 +1845,19 @@ const relativeToCurrentList = computed(() => {
case 'datetime': case 'datetime':
list = [ list = [
{ {
label: '今天', label: t('dynamic_time.today'),
value: 'today' value: 'today'
}, },
{ {
label: '昨天', label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{ {
label: '月初', label: t('dynamic_time.firstOfMonth'),
value: 'monthBeginning' value: 'monthBeginning'
}, },
{ {
label: '年初', label: t('dynamic_time.firstOfYear'),
value: 'yearBeginning' value: 'yearBeginning'
} }
] ]
@ -1845,7 +1870,7 @@ const relativeToCurrentList = computed(() => {
return [ return [
...list, ...list,
{ {
label: '自定义', label: t('dynamic_time.custom'),
value: 'custom' value: 'custom'
} }
] ]
@ -1858,11 +1883,11 @@ const relativeToCurrentListRange = computed(() => {
case 'yearrange': case 'yearrange':
list = [ list = [
{ {
label: '今年', label: t('dynamic_year.current'),
value: 'thisYear' value: 'thisYear'
}, },
{ {
label: '去年', label: t('dynamic_year.last'),
value: 'lastYear' value: 'lastYear'
} }
] ]
@ -1870,23 +1895,23 @@ const relativeToCurrentListRange = computed(() => {
case 'monthrange': case 'monthrange':
list = [ list = [
{ {
label: '本月', label: t('cron.this_month'),
value: 'thisMonth' value: 'thisMonth'
}, },
{ {
label: '上月', label: t('dynamic_month.dynamic_month'),
value: 'lastMonth' value: 'lastMonth'
}, },
{ {
label: '最近 3 个 月', label: t('v_query.last_3_months'),
value: 'LastThreeMonths' value: 'LastThreeMonths'
}, },
{ {
label: '最近 6 个 月', label: t('v_query.last_6_months'),
value: 'LastSixMonths' value: 'LastSixMonths'
}, },
{ {
label: '最近 12 个 月', label: t('v_query.last_12_months'),
value: 'LastTwelveMonths' value: 'LastTwelveMonths'
} }
] ]
@ -1895,23 +1920,23 @@ const relativeToCurrentListRange = computed(() => {
case 'datetimerange': case 'datetimerange':
list = [ list = [
{ {
label: '今天', label: t('dynamic_time.today'),
value: 'today' value: 'today'
}, },
{ {
label: '昨天', label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{ {
label: '最近 3 天', label: t('v_query.last_3_days'),
value: 'LastThreeDays' value: 'LastThreeDays'
}, },
{ {
label: '月初至今', label: t('v_query.month_to_date'),
value: 'monthBeginning' value: 'monthBeginning'
}, },
{ {
label: '年初至今', label: t('v_query.year_to_date'),
value: 'yearBeginning' value: 'yearBeginning'
} }
] ]
@ -1924,7 +1949,7 @@ const relativeToCurrentListRange = computed(() => {
return [ return [
...list, ...list,
{ {
label: '自定义', label: t('dynamic_time.custom'),
value: 'custom' value: 'custom'
} }
] ]
@ -2018,7 +2043,7 @@ const dfs = arr => {
const renameInputBlur = () => { const renameInputBlur = () => {
if (activeConditionForRename.name.trim() === '') { if (activeConditionForRename.name.trim() === '') {
ElMessage.error('字段名称不能为空') ElMessage.error(t('v_query.cannot_be_empty_name'))
renameInput.value[0]?.focus() renameInput.value[0]?.focus()
return return
} }
@ -2058,7 +2083,7 @@ defineExpose({
class="query-condition-configuration" class="query-condition-configuration"
v-model="dialogVisible" v-model="dialogVisible"
width="1200px" width="1200px"
title="查询条件设置" :title="t('v_query.query_condition_setting')"
@click.stop @click.stop
:before-close="handleBeforeClose" :before-close="handleBeforeClose"
@mousedown.stop @mousedown.stop
@ -2067,7 +2092,7 @@ defineExpose({
<div class="container" @click="handleDialogClick"> <div class="container" @click="handleDialogClick">
<div class="query-condition-list"> <div class="query-condition-list">
<div class="title"> <div class="title">
查询条件 {{ t('v_query.query_condition') }}
<el-icon @click="addQueryCriteriaAndSelect"> <el-icon @click="addQueryCriteriaAndSelect">
<Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon> <Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon>
</el-icon> </el-icon>
@ -2127,17 +2152,17 @@ defineExpose({
<div v-if="!!curComponent" class="chart-field" :class="curComponent.auto && 'hidden'"> <div v-if="!!curComponent" class="chart-field" :class="curComponent.auto && 'hidden'">
<div class="mask" v-if="curComponent.auto"></div> <div class="mask" v-if="curComponent.auto"></div>
<div class="title flex-align-center"> <div class="title flex-align-center">
选择关联图表及字段 {{ t('v_query.chart_and_field') }}
<el-radio-group class="ml-4 larger-radio" v-model="curComponent.auto"> <el-radio-group class="ml-4 larger-radio" v-model="curComponent.auto">
<el-radio :disabled="!curComponent.auto" :label="true"> <el-radio :disabled="!curComponent.auto" :label="true">
<div class="flex-align-center"> <div class="flex-align-center">
自动 {{ t('chart.margin_model_auto') }}
<el-tooltip effect="dark" placement="top"> <el-tooltip effect="dark" placement="top">
<template #content> <template #content>
<div> <div>
注意:自动模式支持同数据集自动关联字段可切换到 {{ t('v_query.be_switched_to') }}
<br /> <br />
自定义模式切换到自定义模式后无法再切换为自动 {{ t('v_query.to_automatic_again') }}
</div> </div>
</template> </template>
<el-icon style="margin-left: 4px; color: #646a73"> <el-icon style="margin-left: 4px; color: #646a73">
@ -2225,9 +2250,13 @@ defineExpose({
</template> </template>
<template #header> <template #header>
<el-tabs stretch class="params-select--header" v-model="field.activelist"> <el-tabs stretch class="params-select--header" v-model="field.activelist">
<el-tab-pane disabled label="维度" name="dimensionList"></el-tab-pane> <el-tab-pane
<el-tab-pane disabled label="指标" name="quotaList"></el-tab-pane> disabled
<el-tab-pane label="参数" name="parameterList"></el-tab-pane> :label="t('chart.dimension')"
name="dimensionList"
></el-tab-pane>
<el-tab-pane disabled :label="t('chart.quota')" name="quotaList"></el-tab-pane>
<el-tab-pane :label="t('dataset.param')" name="parameterList"></el-tab-pane>
</el-tabs> </el-tabs>
</template> </template>
<el-option <el-option
@ -2260,9 +2289,9 @@ defineExpose({
> >
{{ {{
curComponent.checkedFieldsMapStart[field.componentId] === ele.id curComponent.checkedFieldsMapStart[field.componentId] === ele.id
? '开始时间' ? t('dataset.start_time')
: curComponent.checkedFieldsMapEnd[field.componentId] === ele.id : curComponent.checkedFieldsMapEnd[field.componentId] === ele.id
? '结束时间' ? t('dataset.end_time')
: '' : ''
}} }}
<el-icon> <el-icon>
@ -2322,9 +2351,13 @@ defineExpose({
</template> </template>
<template #header> <template #header>
<el-tabs stretch class="params-select--header" v-model="field.activelist"> <el-tabs stretch class="params-select--header" v-model="field.activelist">
<el-tab-pane disabled label="维度" name="dimensionList"></el-tab-pane> <el-tab-pane
<el-tab-pane disabled label="指标" name="quotaList"></el-tab-pane> disabled
<el-tab-pane label="参数" name="parameterList"></el-tab-pane> :label="t('chart.dimension')"
name="dimensionList"
></el-tab-pane>
<el-tab-pane disabled :label="t('chart.quota')" name="quotaList"></el-tab-pane>
<el-tab-pane :label="t('dataset.param')" name="parameterList"></el-tab-pane>
</el-tabs> </el-tabs>
</template> </template>
<el-option <el-option
@ -2357,9 +2390,9 @@ defineExpose({
> >
{{ {{
curComponent.checkedFieldsMapStartNum[field.componentId] === ele.id curComponent.checkedFieldsMapStartNum[field.componentId] === ele.id
? '最小值' ? t('chart.min')
: curComponent.checkedFieldsMapEndNum[field.componentId] === ele.id : curComponent.checkedFieldsMapEndNum[field.componentId] === ele.id
? '最大值' ? t('chart.max')
: '' : ''
}} }}
<el-icon> <el-icon>
@ -2408,15 +2441,15 @@ defineExpose({
</template> </template>
<template #header> <template #header>
<el-tabs stretch class="params-select--header" v-model="field.activelist"> <el-tabs stretch class="params-select--header" v-model="field.activelist">
<el-tab-pane label="维度" name="dimensionList"></el-tab-pane> <el-tab-pane :label="t('chart.dimension')" name="dimensionList"></el-tab-pane>
<el-tab-pane <el-tab-pane
:disabled="curComponent.displayType === '9'" :disabled="curComponent.displayType === '9'"
label="指标" :label="t('chart.quota')"
name="quotaList" name="quotaList"
></el-tab-pane> ></el-tab-pane>
<el-tab-pane <el-tab-pane
v-if="field.hasParameter" v-if="field.hasParameter"
label="参数" :label="t('dataset.param')"
:disabled="curComponent.displayType === '9'" :disabled="curComponent.displayType === '9'"
name="parameterList" name="parameterList"
></el-tab-pane> ></el-tab-pane>
@ -2435,7 +2468,7 @@ defineExpose({
> >
<div <div
class="flex-align-center icon" class="flex-align-center icon"
:title="ele.desensitized ? '脱敏字段,不能被设置为查询条件' : ''" :title="ele.desensitized ? t('v_query.as_query_conditions') : ''"
> >
<el-icon> <el-icon>
<Icon :className="`field-icon-${fieldType[ele.deType]}`" <Icon :className="`field-icon-${fieldType[ele.deType]}`"
@ -2463,7 +2496,7 @@ defineExpose({
" "
class="range-time_setting" class="range-time_setting"
> >
{{ isNumParameter ? '数值' : '时间' }} {{ isNumParameter ? t('chart.value_formatter_value') : t('dataset.time') }}
<el-icon> <el-icon>
<Icon> <Icon>
<icon_edit_outlined class="svg-icon"></icon_edit_outlined> <icon_edit_outlined class="svg-icon"></icon_edit_outlined>
@ -2478,14 +2511,18 @@ defineExpose({
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div> </div>
<div v-if="!!curComponent" class="condition-configuration"> <div
v-if="!!curComponent"
class="condition-configuration"
:class="curComponent.auto && 'condition-configuration_hide'"
>
<div class="mask condition" v-if="curComponent.auto"></div> <div class="mask condition" v-if="curComponent.auto"></div>
<div class="title flex-align-center"> <div class="title flex-align-center">
查询条件配置 {{ t('v_query.query_condition_configuration') }}
<el-checkbox <el-checkbox
:disabled="curComponent.auto" :disabled="curComponent.auto"
v-model="curComponent.required" v-model="curComponent.required"
label="必填项" :label="t('v_query.required_items')"
/> />
</div> </div>
<div <div
@ -2493,7 +2530,7 @@ defineExpose({
class="configuration-list" class="configuration-list"
> >
<div class="list-item"> <div class="list-item">
<div class="label">展示类型</div> <div class="label">{{ t('v_query.display_type') }}</div>
<div class="value"> <div class="value">
<el-select <el-select
@focus="handleDialogClick" @focus="handleDialogClick"
@ -2502,12 +2539,12 @@ defineExpose({
> >
<el-option <el-option
:disabled="!['0', '8', '9'].includes(curComponent.displayType)" :disabled="!['0', '8', '9'].includes(curComponent.displayType)"
label="文本下拉" :label="t('v_query.text_drop_down')"
value="0" value="0"
/> />
<el-option <el-option
:disabled="!['0', '8', '9'].includes(curComponent.displayType)" :disabled="!['0', '8', '9'].includes(curComponent.displayType)"
label="文本搜索" :label="t('v_query.text_search')"
value="8" value="8"
/> />
<el-option <el-option
@ -2515,26 +2552,26 @@ defineExpose({
!['0', '8', '9'].includes(curComponent.displayType) || !['0', '8', '9'].includes(curComponent.displayType) ||
!!curComponent.parameters.length !!curComponent.parameters.length
" "
label="下拉树" :label="t('v_query.drop_down_tree')"
value="9" value="9"
/> />
<template v-if="['2', '22'].includes(curComponent.displayType)"> <template v-if="['2', '22'].includes(curComponent.displayType)">
<el-option <el-option
:disabled="!['2', '22'].includes(curComponent.displayType) || notNumRange" :disabled="!['2', '22'].includes(curComponent.displayType) || notNumRange"
label="数字下拉" :label="t('v_query.number_drop_down')"
value="2" value="2"
/> />
<el-option <el-option
:disabled="!['2', '22'].includes(curComponent.displayType) || canNotNumRange" :disabled="!['2', '22'].includes(curComponent.displayType) || canNotNumRange"
label="数值区间" :label="t('v_query.number_range')"
value="22" value="22"
/> />
</template> </template>
<el-option <el-option
v-else v-else
:disabled="curComponent.displayType !== '5'" :disabled="curComponent.displayType !== '5'"
label="数字下拉" :label="t('v_query.number_drop_down')"
value="5" value="5"
/> />
<el-option <el-option
@ -2542,7 +2579,7 @@ defineExpose({
!['1', '7'].includes(curComponent.displayType) || !['1', '7'].includes(curComponent.displayType) ||
(isTimeParameter && notTimeRange) (isTimeParameter && notTimeRange)
" "
label="时间" :label="t('dataset.time')"
value="1" value="1"
/> />
<el-option <el-option
@ -2550,24 +2587,24 @@ defineExpose({
!['1', '7'].includes(curComponent.displayType) || !['1', '7'].includes(curComponent.displayType) ||
(isTimeParameter && !notTimeRange) (isTimeParameter && !notTimeRange)
" "
label="时间范围" :label="t('common.component.dateRange')"
value="7" value="7"
/> />
</el-select> </el-select>
</div> </div>
</div> </div>
<div class="list-item" v-if="curComponent.displayType === '9'"> <div class="list-item" v-if="curComponent.displayType === '9'">
<div class="label">选项值数量</div> <div class="label">{{ t('v_query.of_option_values') }}</div>
<div class="value"> <div class="value">
<el-radio-group class="larger-radio" v-model="curComponent.resultMode"> <el-radio-group class="larger-radio" v-model="curComponent.resultMode">
<el-radio :label="0">默认</el-radio> <el-radio :label="0">{{ t('login.default_login') }}</el-radio>
<el-radio :label="1">全部</el-radio> <el-radio :label="1">{{ t('chart.result_mode_all') }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
</div> </div>
<div class="list-item" v-if="curComponent.displayType === '9'"> <div class="list-item" v-if="curComponent.displayType === '9'">
<div class="label" style="width: 135px; height: 26px; line-height: 26px"> <div class="label" style="width: 135px; height: 26px; line-height: 26px">
下拉树结构设计 {{ t('v_query.tree_structure_design') }}
<el-button <el-button
v-if="curComponent.treeFieldList && !!curComponent.treeFieldList.length" v-if="curComponent.treeFieldList && !!curComponent.treeFieldList.length"
text text
@ -2585,7 +2622,9 @@ defineExpose({
:key="ele.id" :key="ele.id"
class="tree-field" class="tree-field"
> >
<span class="level-index">层级{{ indexCascade[index + 1] }}</span> <span class="level-index"
>{{ t('visualization.level') }}{{ indexCascade[index + 1] }}</span
>
<span class="field-type" <span class="field-type"
><el-icon> ><el-icon>
<Icon :className="`field-icon-${fieldType[ele.deType]}`" <Icon :className="`field-icon-${fieldType[ele.deType]}`"
@ -2603,31 +2642,31 @@ defineExpose({
<template #icon> <template #icon>
<Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon> <Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon>
</template> </template>
点击进行树结构设计 {{ t('v_query.the_tree_structure') }}
</el-button> </el-button>
</div> </div>
<TreeFieldDialog ref="treeDialog" @save-tree="saveTree"></TreeFieldDialog> <TreeFieldDialog ref="treeDialog" @save-tree="saveTree"></TreeFieldDialog>
</div> </div>
<div class="list-item" v-if="['1', '7'].includes(curComponent.displayType)"> <div class="list-item" v-if="['1', '7'].includes(curComponent.displayType)">
<div class="label">时间粒度</div> <div class="label">{{ t('v_query.time_granularity') }}</div>
<div class="value"> <div class="value">
<template v-if="curComponent.displayType === '7' && !isTimeParameter"> <template v-if="curComponent.displayType === '7' && !isTimeParameter">
<el-select <el-select
@change="timeGranularityMultipleChange" @change="timeGranularityMultipleChange"
placeholder="请选择时间粒度" :placeholder="t('v_query.the_time_granularity')"
@focus="handleDialogClick" @focus="handleDialogClick"
v-model="curComponent.timeGranularityMultiple" v-model="curComponent.timeGranularityMultiple"
> >
<el-option label="年" value="yearrange" /> <el-option :label="t('chart.y')" value="yearrange" />
<el-option label="年月" value="monthrange" /> <el-option :label="t('chart.y_M')" value="monthrange" />
<el-option label="年月日" value="daterange" /> <el-option :label="t('chart.y_M_d')" value="daterange" />
<el-option label="年月日时分秒" value="datetimerange" /> <el-option :label="t('chart.y_M_d_H_m_s')" value="datetimerange" />
</el-select> </el-select>
</template> </template>
<template v-else> <template v-else>
<el-select <el-select
@change="timeGranularityChange" @change="timeGranularityChange"
placeholder="请选择时间粒度" :placeholder="t('v_query.the_time_granularity')"
v-model="curComponent.timeGranularity" v-model="curComponent.timeGranularity"
> >
<el-option <el-option
@ -2644,7 +2683,7 @@ defineExpose({
class="list-item top-item" class="list-item top-item"
v-if="!['1', '7', '8', '9', '22'].includes(curComponent.displayType)" v-if="!['1', '7', '8', '9', '22'].includes(curComponent.displayType)"
> >
<div class="label">选项值来源</div> <div class="label">{{ t('v_query.option_value_source') }}</div>
<div class="value"> <div class="value">
<div class="value"> <div class="value">
<el-radio-group <el-radio-group
@ -2656,7 +2695,7 @@ defineExpose({
t('chart.margin_model_auto') t('chart.margin_model_auto')
}}</el-radio> }}</el-radio>
<el-radio :label="1">{{ t('chart.select_dataset') }}</el-radio> <el-radio :label="1">{{ t('chart.select_dataset') }}</el-radio>
<el-radio :label="2">手动输入</el-radio> <el-radio :label="2">{{ t('v_query.manual_input') }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<template v-if="curComponent.optionValueSource === 1"> <template v-if="curComponent.optionValueSource === 1">
@ -2665,7 +2704,7 @@ defineExpose({
:teleported="false" :teleported="false"
v-model="curComponent.dataset.id" v-model="curComponent.dataset.id"
:data="datasetTree" :data="datasetTree"
placeholder="请选择数据集" :placeholder="t('copilot.pls_choose_dataset')"
@change="handleDatasetChange" @change="handleDatasetChange"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
:props="dsSelectProps" :props="dsSelectProps"
@ -2693,10 +2732,10 @@ defineExpose({
</el-tree-select> </el-tree-select>
</div> </div>
<div class="value"> <div class="value">
<span class="label">查询字段</span> <span class="label">{{ t('v_query.query_field') }}</span>
<el-select <el-select
@change="handleFieldChange" @change="handleFieldChange"
placeholder="查询字段" :placeholder="t('v_query.query_field')"
class="search-field" class="search-field"
v-model="curComponent.field.id" v-model="curComponent.field.id"
> >
@ -2735,7 +2774,7 @@ defineExpose({
> >
<div <div
class="flex-align-center icon" class="flex-align-center icon"
:title="ele.desensitized ? '脱敏字段,不能被设置为查询条件' : ''" :title="ele.desensitized ? t('v_query.as_query_conditions') : ''"
> >
<el-icon> <el-icon>
<Icon :className="`field-icon-${fieldType[ele.deType]}`" <Icon :className="`field-icon-${fieldType[ele.deType]}`"
@ -2754,9 +2793,9 @@ defineExpose({
</el-select> </el-select>
</div> </div>
<div class="value"> <div class="value">
<span class="label">显示字段</span> <span class="label">{{ t('v_query.display_field') }}</span>
<el-select <el-select
placeholder="显示字段" :placeholder="t('v_query.display_field')"
class="search-field" class="search-field"
v-model="curComponent.displayId" v-model="curComponent.displayId"
> >
@ -2795,7 +2834,7 @@ defineExpose({
> >
<div <div
class="flex-align-center icon" class="flex-align-center icon"
:title="ele.desensitized ? '脱敏字段,不能被设置为查询条件' : ''" :title="ele.desensitized ? t('v_query.as_query_conditions') : ''"
> >
<el-icon> <el-icon>
<Icon :className="`field-icon-${fieldType[ele.deType]}`" <Icon :className="`field-icon-${fieldType[ele.deType]}`"
@ -2814,10 +2853,10 @@ defineExpose({
</el-select> </el-select>
</div> </div>
<div class="value"> <div class="value">
<span class="label">排序字段</span> <span class="label">{{ t('chart.total_sort_field') }}</span>
<el-select <el-select
clearable clearable
placeholder="请选择排序字段" :placeholder="t('v_query.the_sorting_field')"
v-model="curComponent.sortId" v-model="curComponent.sortId"
class="sort-field" class="sort-field"
@change="handleFieldChange" @change="handleFieldChange"
@ -2850,7 +2889,7 @@ defineExpose({
> >
<div <div
class="flex-align-center icon" class="flex-align-center icon"
:title="ele.desensitized ? '脱敏字段,不能被设置为查询条件' : ''" :title="ele.desensitized ? t('v_query.as_query_conditions') : ''"
> >
<el-icon> <el-icon>
<Icon <Icon
@ -2872,8 +2911,8 @@ defineExpose({
v-model="curComponent.sort" v-model="curComponent.sort"
@change="handleFieldChange" @change="handleFieldChange"
> >
<el-option label="升序" value="asc" /> <el-option :label="t('chart.asc')" value="asc" />
<el-option label="降序" value="desc" /> <el-option :label="t('chart.desc')" value="desc" />
</el-select> </el-select>
</div> </div>
</template> </template>
@ -2898,7 +2937,7 @@ defineExpose({
<div class="manual-input-container"> <div class="manual-input-container">
<div class="title">{{ t('auth.manual_input') }}</div> <div class="title">{{ t('auth.manual_input') }}</div>
<div class="select-value"> <div class="select-value">
<span> 选项值 </span> <span> {{ t('data_fill.form.option_value') }} </span>
<div :key="index" v-for="(_, index) in valueSource" class="select-item"> <div :key="index" v-for="(_, index) in valueSource" class="select-item">
<el-input <el-input
maxlength="20" maxlength="20"
@ -2933,7 +2972,7 @@ defineExpose({
><icon_add_outlined class="svg-icon" ><icon_add_outlined class="svg-icon"
/></Icon> /></Icon>
</template> </template>
添加选项值 {{ t('data_fill.form.add_option') }}
</el-button> </el-button>
</div> </div>
<div class="manual-footer flex-align-center"> <div class="manual-footer flex-align-center">
@ -2945,36 +2984,39 @@ defineExpose({
</div> </div>
</el-popover> </el-popover>
<div v-if="!!curComponent.valueSource.length" class="config-flag flex-align-center"> <div v-if="!!curComponent.valueSource.length" class="config-flag flex-align-center">
已配置 {{ t('v_query.configured') }}
</div> </div>
</div> </div>
</div> </div>
<div class="label" style="margin-top: 10.5px">选项值数量</div> <div class="label" style="margin-top: 10.5px">{{ t('v_query.of_option_values') }}</div>
<div class="value" style="margin-top: 10.5px"> <div class="value" style="margin-top: 10.5px">
<el-radio-group class="larger-radio" v-model="curComponent.resultMode"> <el-radio-group class="larger-radio" v-model="curComponent.resultMode">
<el-radio :label="0">默认</el-radio> <el-radio :label="0">{{ t('chart.default') }}</el-radio>
<el-radio :label="1">全部</el-radio> <el-radio :label="1">{{ t('data_set.all') }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
</div> </div>
<div class="list-item top-item" v-if="curComponent.displayType === '8'"> <div class="list-item top-item" v-if="curComponent.displayType === '8'">
<div class="label">条件类型</div> <div class="label">{{ t('v_query.condition_type') }}</div>
<div class="value"> <div class="value">
<div class="value"> <div class="value">
<el-radio-group class="larger-radio" v-model="curComponent.conditionType"> <el-radio-group class="larger-radio" v-model="curComponent.conditionType">
<el-radio :label="0">单条件</el-radio> <el-radio :label="0">{{ t('v_query.single_condition') }}</el-radio>
<el-radio :label="1" :disabled="!!curComponent.parameters.length" <el-radio :label="1" :disabled="!!curComponent.parameters.length">{{
>与条件</el-radio t('v_query.with_condition')
> }}</el-radio>
<el-radio :label="2" :disabled="!!curComponent.parameters.length" <el-radio :label="2" :disabled="!!curComponent.parameters.length">{{
>或条件</el-radio t('v_query.or_condition')
> }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
</div> </div>
</div> </div>
<div style="margin-bottom: 10.5px" v-if="curComponent.displayType === '8'"> <div style="margin-bottom: 10.5px" v-if="curComponent.displayType === '8'">
<el-checkbox v-model="curComponent.hideConditionSwitching" label="隐藏条件切换" /> <el-checkbox
v-model="curComponent.hideConditionSwitching"
:label="t('v_query.hide_condition_switch')"
/>
</div> </div>
<condition-default-configuration <condition-default-configuration
ref="defaultConfigurationRef" ref="defaultConfigurationRef"
@ -2983,19 +3025,21 @@ defineExpose({
></condition-default-configuration> ></condition-default-configuration>
</div> </div>
<div v-if="showTypeError && showConfiguration" class="empty"> <div v-if="showTypeError && showConfiguration" class="empty">
<empty-background description="所选字段类型不一致,无法进行查询配置" img-type="error" /> <empty-background :description="t('v_query.cannot_be_performed')" img-type="error" />
</div> </div>
<div v-else-if="showDatasetError && showConfiguration" class="empty"> <div v-else-if="showDatasetError && showConfiguration" class="empty">
<empty-background description="图表所使用的数据集不同, 无法展示配置项" img-type="error" /> <empty-background :description="t('v_query.cannot_be_displayed')" img-type="error" />
</div> </div>
<div v-else-if="!showConfiguration" class="empty"> <div v-else-if="!showConfiguration" class="empty">
<empty-background description="请先勾选需要联动的图表及字段" img-type="noneWhite" /> <empty-background :description="t('v_query.be_linked_first')" img-type="noneWhite" />
</div> </div>
</div> </div>
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button class="query-cascade" @click="openCascadeDialog">查询组件级联配置</el-button> <el-button class="query-cascade" @click="openCascadeDialog">{{
t('v_query.component_cascade_configuration')
}}</el-button>
<el-button @click="cancelClick">{{ t('chart.cancel') }} </el-button> <el-button @click="cancelClick">{{ t('chart.cancel') }} </el-button>
<el-button @click="confirmClick" type="primary">{{ t('chart.confirm') }} </el-button> <el-button @click="confirmClick" type="primary">{{ t('chart.confirm') }} </el-button>
</div> </div>
@ -3003,32 +3047,32 @@ defineExpose({
</el-dialog> </el-dialog>
<el-dialog :title="timeName" v-model="timeDialogShow" width="420px"> <el-dialog :title="timeName" v-model="timeDialogShow" width="420px">
<el-form label-position="top"> <el-form label-position="top">
<el-form-item label="时间类型" class="form-item" prop="name"> <el-form-item :label="t('v_query.time_type')" class="form-item" prop="name">
<el-radio-group v-model="timeParameterType"> <el-radio-group v-model="timeParameterType">
<el-radio :label="0">时间</el-radio> <el-radio :label="0">{{ t('data_set.time') }}</el-radio>
<el-radio :label="1">开始时间</el-radio> <el-radio :label="1">{{ t('datasource.start_time') }}</el-radio>
<el-radio :label="2">结束时间</el-radio> <el-radio :label="2">{{ t('datasource.end_time') }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button secondary @click="timeDialogShow = false">取消</el-button> <el-button secondary @click="timeDialogShow = false">{{ t('chart.cancel') }}</el-button>
<el-button type="primary" @click="timeTypeChange">确认</el-button> <el-button type="primary" @click="timeTypeChange">{{ t('chart.confirm') }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog :title="numName" v-model="numDialogShow" width="420px"> <el-dialog :title="numName" v-model="numDialogShow" width="420px">
<el-form label-position="top"> <el-form label-position="top">
<el-form-item label="类型" class="form-item" prop="name"> <el-form-item :label="t('chart.map_line_type')" class="form-item" prop="name">
<el-radio-group v-model="numParameterType"> <el-radio-group v-model="numParameterType">
<el-radio :label="0">数值</el-radio> <el-radio :label="0">{{ t('chart.value_formatter_value') }}</el-radio>
<el-radio :label="1">最小值</el-radio> <el-radio :label="1">{{ t('chart.min') }}</el-radio>
<el-radio :label="2">最大值</el-radio> <el-radio :label="2">{{ t('chart.max') }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button secondary @click="numDialogShow = false">取消</el-button> <el-button secondary @click="numDialogShow = false">{{ t('dataset.cancel') }}</el-button>
<el-button type="primary" @click="numTypeChange">确认</el-button> <el-button type="primary" @click="numTypeChange">{{ t('dataset.confirm') }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
<CascadeDialog @saveCascade="saveCascade" ref="cascadeDialog"></CascadeDialog> <CascadeDialog @saveCascade="saveCascade" ref="cascadeDialog"></CascadeDialog>
@ -3274,6 +3318,10 @@ defineExpose({
width: 467px; width: 467px;
position: relative; position: relative;
overflow-y: auto; overflow-y: auto;
&.condition-configuration_hide {
overflow: hidden;
}
.mask { .mask {
left: -1px; left: -1px;
width: calc(100% + 2px); width: calc(100% + 2px);

View File

@ -1,6 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { toRefs, computed, PropType } from 'vue' import { toRefs, computed, PropType } from 'vue'
import { type TimeRange } from './time-format' import { type TimeRange } from './time-format'
import { useI18n } from '@/hooks/web/useI18n'
import DynamicTime from './DynamicTimeFiltering.vue' import DynamicTime from './DynamicTimeFiltering.vue'
import DynamicTimeRange from './DynamicTimeRangeFiltering.vue' import DynamicTimeRange from './DynamicTimeRangeFiltering.vue'
const props = defineProps({ const props = defineProps({
@ -27,21 +28,23 @@ const props = defineProps({
default: 'yearrange' default: 'yearrange'
} }
}) })
const { t } = useI18n()
const intervalTypeList = [ const intervalTypeList = [
{ {
label: '无', label: t('chart.line_symbol_none'),
value: 'none' value: 'none'
}, },
{ {
label: '开始于', label: t('v_query.start_at'),
value: 'start' value: 'start'
}, },
{ {
label: '结束于', label: t('v_query.end_at'),
value: 'end' value: 'end'
}, },
{ {
label: '时间区间', label: t('v_query.time_interval'),
value: 'timeInterval' value: 'timeInterval'
} }
] ]
@ -60,11 +63,11 @@ const filterTypeCom = computed(() => {
const aroundList = [ const aroundList = [
{ {
label: '前', label: t('dynamic_time.before'),
value: 'f' value: 'f'
}, },
{ {
label: '后', label: t('dynamic_time.after'),
value: 'b' value: 'b'
} }
] ]
@ -76,15 +79,15 @@ const relativeToCurrentTypeList = computed(() => {
) + 1 ) + 1
return [ return [
{ {
label: '年', label: t('dynamic_time.year'),
value: 'year' value: 'year'
}, },
{ {
label: '月', label: t('dynamic_time.month'),
value: 'month' value: 'month'
}, },
{ {
label: '日', label: t('dynamic_time.date'),
value: 'day' value: 'day'
} }
].slice(0, index) ].slice(0, index)
@ -100,11 +103,11 @@ const relativeToCurrentList = computed(() => {
case 'yearrange': case 'yearrange':
list = [ list = [
{ {
label: '今年', label: t('dynamic_year.current'),
value: 'thisYear' value: 'thisYear'
}, },
{ {
label: '去年', label: t('dynamic_year.last'),
value: 'lastYear' value: 'lastYear'
} }
] ]
@ -112,11 +115,11 @@ const relativeToCurrentList = computed(() => {
case 'monthrange': case 'monthrange':
list = [ list = [
{ {
label: '本月', label: t('cron.this_month'),
value: 'thisMonth' value: 'thisMonth'
}, },
{ {
label: '上月', label: t('dynamic_month.last'),
value: 'lastMonth' value: 'lastMonth'
} }
] ]
@ -124,19 +127,19 @@ const relativeToCurrentList = computed(() => {
case 'daterange': case 'daterange':
list = [ list = [
{ {
label: '今天', label: t('dynamic_time.today'),
value: 'today' value: 'today'
}, },
{ {
label: '昨天', label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{ {
label: '月初', label: t('dynamic_time.firstOfMonth'),
value: 'monthBeginning' value: 'monthBeginning'
}, },
{ {
label: '年初', label: t('dynamic_time.firstOfYear'),
value: 'yearBeginning' value: 'yearBeginning'
} }
] ]
@ -144,19 +147,19 @@ const relativeToCurrentList = computed(() => {
case 'datetimerange': case 'datetimerange':
list = [ list = [
{ {
label: '今天', label: t('dynamic_time.today'),
value: 'today' value: 'today'
}, },
{ {
label: '昨天', label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{ {
label: '月初', label: t('dynamic_time.firstOfMonth'),
value: 'monthBeginning' value: 'monthBeginning'
}, },
{ {
label: '年初', label: t('dynamic_time.firstOfYear'),
value: 'yearBeginning' value: 'yearBeginning'
} }
] ]
@ -169,7 +172,7 @@ const relativeToCurrentList = computed(() => {
return [ return [
...list, ...list,
{ {
label: '自定义', label: t('dynamic_time.custom'),
value: 'custom' value: 'custom'
} }
] ]
@ -182,11 +185,11 @@ const relativeToCurrentListRange = computed(() => {
case 'yearrange': case 'yearrange':
list = [ list = [
{ {
label: '今年', label: t('dynamic_year.current'),
value: 'thisYear' value: 'thisYear'
}, },
{ {
label: '去年', label: t('dynamic_year.last'),
value: 'lastYear' value: 'lastYear'
} }
] ]
@ -194,23 +197,23 @@ const relativeToCurrentListRange = computed(() => {
case 'monthrange': case 'monthrange':
list = [ list = [
{ {
label: '本月', label: t('cron.this_month'),
value: 'thisMonth' value: 'thisMonth'
}, },
{ {
label: '上月', label: t('dynamic_month.dynamic_month'),
value: 'lastMonth' value: 'lastMonth'
}, },
{ {
label: '最近 3 个 月', label: t('v_query.last_3_months'),
value: 'LastThreeMonths' value: 'LastThreeMonths'
}, },
{ {
label: '最近 6 个 月', label: t('v_query.last_6_months'),
value: 'LastSixMonths' value: 'LastSixMonths'
}, },
{ {
label: '最近 12 个 月', label: t('v_query.last_12_months'),
value: 'LastTwelveMonths' value: 'LastTwelveMonths'
} }
] ]
@ -219,23 +222,23 @@ const relativeToCurrentListRange = computed(() => {
case 'datetimerange': case 'datetimerange':
list = [ list = [
{ {
label: '今天', label: t('dynamic_time.today'),
value: 'today' value: 'today'
}, },
{ {
label: '昨天', label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{ {
label: '最近 3 天', label: t('v_query.last_3_days'),
value: 'LastThreeDays' value: 'LastThreeDays'
}, },
{ {
label: '月初至今', label: t('v_query.month_to_date'),
value: 'monthBeginning' value: 'monthBeginning'
}, },
{ {
label: '年初至今', label: t('v_query.year_to_date'),
value: 'yearBeginning' value: 'yearBeginning'
} }
] ]
@ -248,7 +251,7 @@ const relativeToCurrentListRange = computed(() => {
return [ return [
...list, ...list,
{ {
label: '自定义', label: t('dynamic_time.custom'),
value: 'custom' value: 'custom'
} }
] ]
@ -257,9 +260,9 @@ const relativeToCurrentListRange = computed(() => {
<template> <template>
<div class="set-time-filtering-range"> <div class="set-time-filtering-range">
<div class="title">设置时间筛选范围</div> <div class="title">{{ t('v_query.time_filter_range') }}</div>
<div class="list-item"> <div class="list-item">
<div class="label">区间类型</div> <div class="label">{{ t('v_query.interval_type') }}</div>
<div class="setting-content"> <div class="setting-content">
<div class="setting"> <div class="setting">
<el-radio-group v-model="timeRange.intervalType"> <el-radio-group v-model="timeRange.intervalType">
@ -275,13 +278,13 @@ const relativeToCurrentListRange = computed(() => {
<div class="setting-content"> <div class="setting-content">
<div class="setting"> <div class="setting">
<el-radio-group v-model="timeRange.regularOrTrends"> <el-radio-group v-model="timeRange.regularOrTrends">
<el-radio label="fixed">固定时间</el-radio> <el-radio label="fixed">{{ t('dynamic_time.fix') }}</el-radio>
<el-radio label="dynamic">动态时间</el-radio> <el-radio label="dynamic">{{ t('dynamic_time.dynamic') }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<template v-if="dynamicTime && timeRange.intervalType !== 'timeInterval'"> <template v-if="dynamicTime && timeRange.intervalType !== 'timeInterval'">
<div class="setting" v-if="timeRange.intervalType !== 'timeInterval'"> <div class="setting" v-if="timeRange.intervalType !== 'timeInterval'">
<div class="setting-label">相对当前</div> <div class="setting-label">{{ t('dynamic_time.relative') }}</div>
<div class="setting-value select"> <div class="setting-value select">
<el-select v-model="timeRange.relativeToCurrent"> <el-select v-model="timeRange.relativeToCurrent">
<el-option <el-option
@ -317,7 +320,7 @@ const relativeToCurrentListRange = computed(() => {
</template> </template>
<template v-else-if="dynamicTime && timeRange.intervalType === 'timeInterval'"> <template v-else-if="dynamicTime && timeRange.intervalType === 'timeInterval'">
<div class="setting"> <div class="setting">
<div class="setting-label">相对当前</div> <div class="setting-label">{{ t('dynamic_time.relative') }}</div>
<div class="setting-value select"> <div class="setting-value select">
<el-select v-model="timeRange.relativeToCurrentRange"> <el-select v-model="timeRange.relativeToCurrentRange">
<el-option <el-option
@ -337,7 +340,7 @@ const relativeToCurrentListRange = computed(() => {
'is-year-month-range' 'is-year-month-range'
" "
> >
<div class="setting-label">开始时间</div> <div class="setting-label">{{ t('datasource.start_time') }}</div>
<div class="setting-input range"> <div class="setting-input range">
<el-input-number <el-input-number
step-strictly step-strictly
@ -370,7 +373,7 @@ const relativeToCurrentListRange = computed(() => {
'is-year-month-range' 'is-year-month-range'
" "
> >
<div class="setting-label">结束时间</div> <div class="setting-label">{{ t('datasource.end_time') }}</div>
<div class="setting-input range"> <div class="setting-input range">
<el-input-number <el-input-number
v-model="timeRange.timeNumRange" v-model="timeRange.timeNumRange"
@ -400,7 +403,7 @@ const relativeToCurrentListRange = computed(() => {
</template> </template>
</div> </div>
<div class="parameters" :class="dynamicTime && 'setting'"> <div class="parameters" :class="dynamicTime && 'setting'">
<div class="setting-label" v-if="dynamicTime">预览</div> <div class="setting-label" v-if="dynamicTime">{{ t('template_manage.preview') }}</div>
<div :class="dynamicTime ? 'setting-value' : 'w100'"> <div :class="dynamicTime ? 'setting-value' : 'w100'">
<component <component
:config="timeRange" :config="timeRange"
@ -413,10 +416,10 @@ const relativeToCurrentListRange = computed(() => {
</div> </div>
<div class="list-item"> <div class="list-item">
<div class="label"> <div class="label">
<el-checkbox v-model="timeRange.dynamicWindow" label="动态查询时间窗口" /> <el-checkbox v-model="timeRange.dynamicWindow" :label="t('v_query.query_time_window')" />
</div> </div>
<div v-if="timeRange.dynamicWindow" class="setting-content maximum-single-query"> <div v-if="timeRange.dynamicWindow" class="setting-content maximum-single-query">
单次查询最多 {{ t('v_query.maximum_single_query') }}
<el-input-number <el-input-number
v-model="timeRange.maximumSingleQuery" v-model="timeRange.maximumSingleQuery"
:min="1" :min="1"

View File

@ -15,6 +15,7 @@ import {
import { enumValueObj, type EnumValue, getEnumValue } from '@/api/dataset' import { enumValueObj, type EnumValue, getEnumValue } from '@/api/dataset'
import { cloneDeep, debounce } from 'lodash-es' import { cloneDeep, debounce } from 'lodash-es'
import { useEmitt } from '@/hooks/web/useEmitt' import { useEmitt } from '@/hooks/web/useEmitt'
import { useI18n } from '@/hooks/web/useI18n'
interface SelectConfig { interface SelectConfig {
selectValue: any selectValue: any
@ -46,6 +47,8 @@ interface SelectConfig {
}[] }[]
} }
const { t } = useI18n()
const props = defineProps({ const props = defineProps({
config: { config: {
type: Object as PropType<SelectConfig>, type: Object as PropType<SelectConfig>,
@ -83,7 +86,7 @@ const cascadeList = inject('cascade-list', Function, true)
const setCascadeDefault = inject('set-cascade-default', Function, true) const setCascadeDefault = inject('set-cascade-default', Function, true)
const placeholderText = computed(() => { const placeholderText = computed(() => {
if (placeholder.value.placeholderShow) { if (placeholder?.value?.placeholderShow) {
return ['', undefined].includes(props.config.placeholder) ? ' ' : props.config.placeholder return ['', undefined].includes(props.config.placeholder) ? ' ' : props.config.placeholder
} }
return ' ' return ' '
@ -367,7 +370,7 @@ const setEmptyData = () => {
const [s] = options.value const [s] = options.value
if (showEmpty) { if (showEmpty) {
if (s?.value !== '_empty_$') { if (s?.value !== '_empty_$') {
options.value = [{ label: '空数据', value: '_empty_$' }, ...options.value] options.value = [{ label: t('v_query.empty_data'), value: '_empty_$' }, ...options.value]
} }
} else { } else {
if (s?.value === '_empty_$') { if (s?.value === '_empty_$') {

View File

@ -2,6 +2,7 @@
import { toRefs, onBeforeMount, type PropType, type Ref, inject, computed, nextTick } from 'vue' import { toRefs, onBeforeMount, type PropType, type Ref, inject, computed, nextTick } from 'vue'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useI18n } from '@/hooks/web/useI18n'
interface SelectConfig { interface SelectConfig {
id: string id: string
conditionValueOperatorF: string conditionValueOperatorF: string
@ -17,9 +18,10 @@ interface SelectConfig {
conditionType: number conditionType: number
} }
const placeholder: Ref = inject('placeholder') const placeholder: Ref = inject('placeholder')
const { t } = useI18n()
const placeholderText = computed(() => { const placeholderText = computed(() => {
if (placeholder.value.placeholderShow) { if (placeholder?.value?.placeholderShow) {
return props.config.placeholder return props.config.placeholder
} }
return ' ' return ' '
@ -27,11 +29,11 @@ const placeholderText = computed(() => {
const operators = [ const operators = [
{ {
label: '精确匹配', label: t('v_query.exact_match'),
value: 'eq' value: 'eq'
}, },
{ {
label: '模糊匹配', label: t('v_query.fuzzy_match'),
value: 'like' value: 'like'
} }
] ]
@ -120,7 +122,9 @@ const lineWidth = computed(() => {
<div :style="lineWidth" class="bottom-line"></div> <div :style="lineWidth" class="bottom-line"></div>
</div> </div>
<div class="condition-type" v-if="[1, 2].includes(config.conditionType)"> <div class="condition-type" v-if="[1, 2].includes(config.conditionType)">
<sapn class="condition-type-tip">{{ config.conditionType === 1 ? '与' : '或' }}</sapn> <sapn class="condition-type-tip">{{
config.conditionType === 1 ? t('chart.and') : t('chart.or')
}}</sapn>
<el-select <el-select
v-if="!config.hideConditionSwitching" v-if="!config.hideConditionSwitching"
class="condition-value-select" class="condition-value-select"

View File

@ -5,6 +5,7 @@ import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import type { ManipulateType } from 'dayjs' import type { ManipulateType } from 'dayjs'
import { type TimeRange } from './time-format' import { type TimeRange } from './time-format'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useI18n } from '@/hooks/web/useI18n'
import { useShortcuts } from './shortcuts' import { useShortcuts } from './shortcuts'
import { getThisStart, getLastStart, getAround } from './time-format-dayjs' import { getThisStart, getLastStart, getAround } from './time-format-dayjs'
import VanPopup from 'vant/es/popup' import VanPopup from 'vant/es/popup'
@ -28,6 +29,7 @@ interface SelectConfig {
placeholder: string placeholder: string
setTimeRange: boolean setTimeRange: boolean
} }
const { t } = useI18n()
const props = defineProps({ const props = defineProps({
config: { config: {
@ -65,7 +67,7 @@ const props = defineProps({
}) })
const placeholder: Ref = inject('placeholder') const placeholder: Ref = inject('placeholder')
const placeholderText = computed(() => { const placeholderText = computed(() => {
if (placeholder.value.placeholderShow) { if (placeholder?.value?.placeholderShow) {
return props.config.placeholder return props.config.placeholder
} }
return ' ' return ' '
@ -453,9 +455,9 @@ const formatDate = computed(() => {
@confirm="onConfirm" @confirm="onConfirm"
@cancel="onCancel" @cancel="onCancel"
v-if="showTimePick" v-if="showTimePick"
title="时间选择" :title="t('v_query.time_selection')"
:tabs="['选择日期', '选择时间']" :tabs="[t('dataset.select_date'), t('dataset.select_time')]"
next-step-text="下一步" :next-step-text="t('sync_datasource.next')"
> >
<van-date-picker <van-date-picker
:min-date="minDate" :min-date="minDate"
@ -466,7 +468,7 @@ const formatDate = computed(() => {
<van-time-picker :columns-type="['hour', 'minute', 'second']" v-model="currentTime" /> <van-time-picker :columns-type="['hour', 'minute', 'second']" v-model="currentTime" />
</van-picker-group> </van-picker-group>
<van-date-picker <van-date-picker
title="选择日期" :title="t('dataset.select_date')"
:columns-type="columnsType" :columns-type="columnsType"
@confirm="onConfirm" @confirm="onConfirm"
@cancel="onCancel" @cancel="onCancel"

View File

@ -58,7 +58,7 @@ const props = defineProps({
const placeholder: Ref = inject('placeholder') const placeholder: Ref = inject('placeholder')
const placeholderText = computed(() => { const placeholderText = computed(() => {
if (placeholder.value.placeholderShow) { if (placeholder?.value?.placeholderShow) {
return ['', undefined].includes(props.config.placeholder) ? ' ' : props.config.placeholder return ['', undefined].includes(props.config.placeholder) ? ' ' : props.config.placeholder
} }
return ' ' return ' '

View File

@ -2,6 +2,7 @@
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg' import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.svg' import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.svg'
import { guid } from '@/views/visualized/data/dataset/form/util.js' import { guid } from '@/views/visualized/data/dataset/form/util.js'
import { useI18n } from '@/hooks/web/useI18n'
import { ElMessage } from 'element-plus-secondary' import { ElMessage } from 'element-plus-secondary'
import { ref, shallowRef, computed } from 'vue' import { ref, shallowRef, computed } from 'vue'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
@ -10,10 +11,12 @@ const dialogVisible = ref(false)
const treeList = ref([]) const treeList = ref([])
const datasetMap = shallowRef([]) const datasetMap = shallowRef([])
const emits = defineEmits(['saveTree']) const emits = defineEmits(['saveTree'])
const { t } = useI18n()
const addCascadeItem = () => { const addCascadeItem = () => {
treeList.value.push({ treeList.value.push({
field: null, field: {
id: ''
},
id: guid() id: guid()
}) })
} }
@ -50,13 +53,20 @@ const setCascadeArrBack = () => {
const confirmClick = () => { const confirmClick = () => {
const { isError, arr } = setCascadeArrBack() const { isError, arr } = setCascadeArrBack()
if (isError) { if (isError) {
ElMessage.error('层级字段不能为空,请选择字段!') ElMessage.error(t('v_query.select_a_field'))
return return
} }
emits('saveTree', arr) emits('saveTree', arr)
handleBeforeClose() handleBeforeClose()
} }
const indexCascade = ' 一二三四五' const indexCascade = [
' ',
t('report.week_mon'),
t('report.week_tue'),
t('report.week_wed'),
t('report.week_thu'),
t('report.week_fri')
]
const deleteCascade = idx => { const deleteCascade = idx => {
treeList.value.splice(idx, 1) treeList.value.splice(idx, 1)
@ -75,7 +85,7 @@ defineExpose({
:before-close="handleBeforeClose" :before-close="handleBeforeClose"
@mousedown.stop @mousedown.stop
@mousedup.stop @mousedup.stop
title="下拉树结构设计" :title="t('v_query.tree_structure_design')"
> >
<div class="cascade-content"> <div class="cascade-content">
<div style="display: flex; align-items: center; justify-content: space-between"> <div style="display: flex; align-items: center; justify-content: space-between">
@ -83,15 +93,15 @@ defineExpose({
<template #icon> <template #icon>
<Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon> <Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon>
</template> </template>
添加层级 {{ t('v_query.add_level') }}
</el-button> </el-button>
</div> </div>
<div class="cascade-item"> <div class="cascade-item">
<div class="label">层级</div> <div class="label">{{ t('visualization.level') }}</div>
<div class="item-name">下拉树查询字段</div> <div class="item-name">{{ t('v_query.tree_query_field') }}</div>
</div> </div>
<div class="cascade-item" v-for="(ele, idx) in treeList" :key="ele.id"> <div class="cascade-item" v-for="(ele, idx) in treeList" :key="ele.id">
<div class="label">层级{{ indexCascade[idx + 1] }}</div> <div class="label">{{ t('visualization.level') }}{{ indexCascade[idx + 1] }}</div>
<div class="item-name"> <div class="item-name">
<el-select <el-select
:disabled="idx === 0 && ele.field" :disabled="idx === 0 && ele.field"
@ -119,8 +129,8 @@ defineExpose({
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button secondary @click="cancelClick">取消</el-button> <el-button secondary @click="cancelClick">{{ t('common.cancel') }}</el-button>
<el-button type="primary" @click="confirmClick"> 确定 </el-button> <el-button type="primary" @click="confirmClick"> {{ t('pblink.sure_bt') }} </el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>

View File

@ -1,5 +1,7 @@
import type { ComponentInfo } from '@/api/chart' import type { ComponentInfo } from '@/api/chart'
import { guid } from '@/views/visualized/data/dataset/form/util.js' import { guid } from '@/views/visualized/data/dataset/form/util.js'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
const infoFormat = (obj: ComponentInfo) => { const infoFormat = (obj: ComponentInfo) => {
const { id, name, deType, type, datasetId } = obj const { id, name, deType, type, datasetId } = obj
@ -67,7 +69,7 @@ const infoFormat = (obj: ComponentInfo) => {
const addQueryCriteriaConfig = () => { const addQueryCriteriaConfig = () => {
const componentInfo: ComponentInfo = { const componentInfo: ComponentInfo = {
id: '', id: '',
name: '未命名', name: t('v_query.unnamed'),
deType: 0, deType: 0,
type: 'VARCHAR', type: 'VARCHAR',
datasetId: '' datasetId: ''

View File

@ -181,8 +181,12 @@ const getResultNum = (
numValueEnd, numValueEnd,
numValueStart, numValueStart,
defaultNumValueStart, defaultNumValueStart,
defaultValueCheck,
firstLoad firstLoad
) => { ) => {
if (firstLoad && !defaultValueCheck) {
return []
}
const valueS = firstLoad ? defaultNumValueStart : numValueStart const valueS = firstLoad ? defaultNumValueStart : numValueStart
const valueE = firstLoad ? defaultNumValueEnd : numValueEnd const valueE = firstLoad ? defaultNumValueEnd : numValueEnd
return [valueS ?? '', valueE ?? ''].filter(ele => ele !== '') return [valueS ?? '', valueE ?? ''].filter(ele => ele !== '')
@ -246,242 +250,238 @@ const duplicateRemoval = arr => {
export const searchQuery = (queryComponentList, filter, curComponentId, firstLoad) => { export const searchQuery = (queryComponentList, filter, curComponentId, firstLoad) => {
queryComponentList.forEach(ele => { queryComponentList.forEach(ele => {
if (!!ele.propValue?.length) { if (!!ele.propValue?.length) {
ele.propValue ele.propValue.forEach(item => {
.filter(itx => itx.visible) if (item.checkedFields.includes(curComponentId) && item.checkedFieldsMap[curComponentId]) {
.forEach(item => { let selectValue
const {
selectValue: value,
timeGranularityMultiple,
defaultNumValueEnd,
numValueEnd,
numValueStart,
defaultNumValueStart,
conditionType = 0,
treeFieldList = [],
defaultConditionValueOperatorF = 'eq',
defaultConditionValueF = '',
defaultConditionValueOperatorS = 'like',
defaultConditionValueS = '',
conditionValueOperatorF = 'eq',
conditionValueF = '',
conditionValueOperatorS = 'like',
conditionValueS = '',
defaultValueCheck,
timeType = 'fixed',
defaultValue,
optionValueSource,
defaultMapValue,
mapValue,
parameters = [],
timeGranularity = 'date',
displayType,
displayId,
multiple
} = item
const isTree = +displayType === 9
if ( if (
item.checkedFields.includes(curComponentId) && timeType === 'dynamic' &&
item.checkedFieldsMap[curComponentId] [1, 7].includes(+displayType) &&
firstLoad &&
defaultValueCheck
) { ) {
let selectValue if (+displayType === 1) {
const { selectValue = getDynamicRange(item)
selectValue: value, item.defaultValue = new Date(selectValue[0])
timeGranularityMultiple, item.selectValue = new Date(selectValue[0])
} else {
const {
timeNum,
relativeToCurrentType,
around,
relativeToCurrentRange,
arbitraryTime,
timeGranularity,
timeNumRange,
relativeToCurrentTypeRange,
aroundRange,
timeGranularityMultiple,
arbitraryTimeRange
} = item
let startTime = getCustomTime(
timeNum,
relativeToCurrentType,
timeGranularity,
around,
arbitraryTime,
timeGranularityMultiple,
'start-panel'
)
let endTime = getCustomTime(
timeNumRange,
relativeToCurrentTypeRange,
timeGranularity,
aroundRange,
arbitraryTimeRange,
timeGranularityMultiple,
'end-panel'
)
if (!!relativeToCurrentRange && relativeToCurrentRange !== 'custom') {
;[startTime, endTime] = getCustomRange(relativeToCurrentRange)
}
item.defaultValue = [startTime, endTime]
item.selectValue = [startTime, endTime]
selectValue = [startTime, endTime]
}
} else if (displayType === '8') {
selectValue = getResult(
conditionType,
defaultConditionValueF,
defaultConditionValueS,
conditionValueF,
conditionValueS,
firstLoad
)
} else if (displayType === '22') {
selectValue = getResultNum(
defaultNumValueEnd, defaultNumValueEnd,
numValueEnd, numValueEnd,
numValueStart, numValueStart,
defaultNumValueStart, defaultNumValueStart,
conditionType = 0,
treeFieldList = [],
defaultConditionValueOperatorF = 'eq',
defaultConditionValueF = '',
defaultConditionValueOperatorS = 'like',
defaultConditionValueS = '',
conditionValueOperatorF = 'eq',
conditionValueF = '',
conditionValueOperatorS = 'like',
conditionValueS = '',
defaultValueCheck, defaultValueCheck,
timeType = 'fixed', firstLoad
)
} else {
selectValue = getValueByDefaultValueCheckOrFirstLoad(
defaultValueCheck,
defaultValue, defaultValue,
optionValueSource, value,
firstLoad,
multiple,
defaultMapValue, defaultMapValue,
optionValueSource,
mapValue, mapValue,
parameters = [],
timeGranularity = 'date',
displayType, displayType,
displayId, displayId
multiple )
} = item }
if (
!!selectValue?.length ||
['[object Number]', '[object Date]'].includes(
Object.prototype.toString.call(selectValue)
) ||
displayType === '8'
) {
let result = forMatterValue(
+displayType,
selectValue,
timeGranularity,
timeGranularityMultiple
)
const operator = getOperator(
displayType,
multiple,
conditionType,
defaultConditionValueOperatorF,
defaultConditionValueF,
defaultConditionValueOperatorS,
defaultConditionValueS,
conditionValueOperatorF,
conditionValueF,
conditionValueOperatorS,
conditionValueS,
firstLoad
)
if (result?.length) {
const fieldId = isTree
? getFieldId(treeFieldList, result)
: item.checkedFieldsMap[curComponentId]
let parametersFilter = duplicateRemoval(
parameters.reduce((pre, next) => {
if (next.id === fieldId && !pre.length) {
pre.push(next)
}
return pre
}, [])
)
const isTree = +displayType === 9 if (item.checkedFieldsMapArr?.[curComponentId]?.length) {
const endTimeFieldId = item.checkedFieldsMapArr?.[curComponentId].find(
if ( element => element !== fieldId
timeType === 'dynamic' &&
[1, 7].includes(+displayType) &&
firstLoad &&
defaultValueCheck
) {
if (+displayType === 1) {
selectValue = getDynamicRange(item)
item.defaultValue = new Date(selectValue[0])
item.selectValue = new Date(selectValue[0])
} else {
const {
timeNum,
relativeToCurrentType,
around,
relativeToCurrentRange,
arbitraryTime,
timeGranularity,
timeNumRange,
relativeToCurrentTypeRange,
aroundRange,
timeGranularityMultiple,
arbitraryTimeRange
} = item
let startTime = getCustomTime(
timeNum,
relativeToCurrentType,
timeGranularity,
around,
arbitraryTime,
timeGranularityMultiple,
'start-panel'
) )
let endTime = getCustomTime( const resultEnd = Array(2).fill(
timeNumRange, endTimeFieldId === item.checkedFieldsMapEnd[curComponentId]
relativeToCurrentTypeRange, ? result[1]
timeGranularity, : result[0]
aroundRange, )
arbitraryTimeRange, result = Array(2).fill(
timeGranularityMultiple, endTimeFieldId === item.checkedFieldsMapEnd[curComponentId]
'end-panel' ? result[0]
: result[1]
)
parametersFilter = duplicateRemoval(
item.parametersArr[curComponentId].filter(e => e.id === fieldId)
) )
if (!!relativeToCurrentRange && relativeToCurrentRange !== 'custom') { const parametersFilterEnd = duplicateRemoval(
;[startTime, endTime] = getCustomRange(relativeToCurrentRange) item.parametersArr[curComponentId].filter(e => e.id === endTimeFieldId)
}
item.defaultValue = [startTime, endTime]
item.selectValue = [startTime, endTime]
selectValue = [startTime, endTime]
}
} else if (displayType === '8') {
selectValue = getResult(
conditionType,
defaultConditionValueF,
defaultConditionValueS,
conditionValueF,
conditionValueS,
firstLoad
)
} else if (displayType === '22') {
selectValue = getResultNum(
defaultNumValueEnd,
numValueEnd,
numValueStart,
defaultNumValueStart,
firstLoad
)
} else {
selectValue = getValueByDefaultValueCheckOrFirstLoad(
defaultValueCheck,
defaultValue,
value,
firstLoad,
multiple,
defaultMapValue,
optionValueSource,
mapValue,
displayType,
displayId
)
}
if (
!!selectValue?.length ||
['[object Number]', '[object Date]'].includes(
Object.prototype.toString.call(selectValue)
) ||
displayType === '8'
) {
let result = forMatterValue(
+displayType,
selectValue,
timeGranularity,
timeGranularityMultiple
)
const operator = getOperator(
displayType,
multiple,
conditionType,
defaultConditionValueOperatorF,
defaultConditionValueF,
defaultConditionValueOperatorS,
defaultConditionValueS,
conditionValueOperatorF,
conditionValueF,
conditionValueOperatorS,
conditionValueS,
firstLoad
)
if (result?.length) {
const fieldId = isTree
? getFieldId(treeFieldList, result)
: item.checkedFieldsMap[curComponentId]
let parametersFilter = duplicateRemoval(
parameters.reduce((pre, next) => {
if (next.id === fieldId && !pre.length) {
pre.push(next)
}
return pre
}, [])
) )
if (item.checkedFieldsMapArr?.[curComponentId]?.length) {
const endTimeFieldId = item.checkedFieldsMapArr?.[curComponentId].find(
element => element !== fieldId
)
const resultEnd = Array(2).fill(
endTimeFieldId === item.checkedFieldsMapEnd[curComponentId]
? result[1]
: result[0]
)
result = Array(2).fill(
endTimeFieldId === item.checkedFieldsMapEnd[curComponentId]
? result[0]
: result[1]
)
parametersFilter = duplicateRemoval(
item.parametersArr[curComponentId].filter(e => e.id === fieldId)
)
const parametersFilterEnd = duplicateRemoval(
item.parametersArr[curComponentId].filter(e => e.id === endTimeFieldId)
)
filter.push({
componentId: ele.id,
fieldId: endTimeFieldId,
operator,
value: resultEnd,
parameters: parametersFilterEnd,
isTree
})
}
if (item.checkedFieldsMapArrNum?.[curComponentId]?.length) {
const endTimeFieldId = item.checkedFieldsMapArrNum?.[curComponentId].find(
element => element !== fieldId
)
const resultEnd = Array(2).fill(
endTimeFieldId === item.checkedFieldsMapEndNum[curComponentId]
? result[1]
: result[0]
)
result = Array(2).fill(
endTimeFieldId === item.checkedFieldsMapEndNum[curComponentId]
? result[0]
: result[1]
)
parametersFilter = duplicateRemoval(
item.parametersArr[curComponentId].filter(e => e.id === fieldId)
)
const parametersFilterEnd = duplicateRemoval(
item.parametersArr[curComponentId].filter(e => e.id === endTimeFieldId)
)
filter.push({
componentId: ele.id,
fieldId: endTimeFieldId,
operator,
value: resultEnd,
parameters: parametersFilterEnd,
isTree
})
}
filter.push({ filter.push({
componentId: ele.id, componentId: ele.id,
fieldId, fieldId: endTimeFieldId,
operator, operator,
value: result, value: resultEnd,
parameters: parametersFilter, parameters: parametersFilterEnd,
isTree isTree
}) })
} }
if (item.checkedFieldsMapArrNum?.[curComponentId]?.length) {
const endTimeFieldId = item.checkedFieldsMapArrNum?.[curComponentId].find(
element => element !== fieldId
)
const resultEnd = Array(2).fill(
endTimeFieldId === item.checkedFieldsMapEndNum[curComponentId]
? result[1]
: result[0]
)
result = Array(2).fill(
endTimeFieldId === item.checkedFieldsMapEndNum[curComponentId]
? result[0]
: result[1]
)
parametersFilter = duplicateRemoval(
item.parametersArr[curComponentId].filter(e => e.id === fieldId)
)
const parametersFilterEnd = duplicateRemoval(
item.parametersArr[curComponentId].filter(e => e.id === endTimeFieldId)
)
filter.push({
componentId: ele.id,
fieldId: endTimeFieldId,
operator,
value: resultEnd,
parameters: parametersFilterEnd,
isTree
})
}
filter.push({
componentId: ele.id,
fieldId,
operator,
value: result,
parameters: parametersFilter,
isTree
})
} }
} }
}) }
})
} }
}) })
} }

View File

@ -11,6 +11,7 @@ export default {
add_component_hint: 'Click or drag the component on the left to add a field' add_component_hint: 'Click or drag the component on the left to add a field'
}, },
inputText: 'Please input', inputText: 'Please input',
selectText: 'Please select',
account: 'Account', account: 'Account',
email: 'Email', email: 'Email',
phone: 'Phone', phone: 'Phone',
@ -34,7 +35,9 @@ export default {
save_success: 'Save success', save_success: 'Save success',
roger_that: 'Roger that', roger_that: 'Roger that',
delete_success: 'Delete success', delete_success: 'Delete success',
no_auth_tips: 'Missing menu permissions, please contact the administrator' no_auth_tips: 'Missing menu permissions, please contact the administrator',
filter: 'Filter',
filter_condition: 'Filter Condition'
}, },
toolbox: { toolbox: {
name: 'Toolbox', name: 'Toolbox',
@ -99,7 +102,12 @@ export default {
delete_catalog_hint: 'Are You Sure You Want to Delete This Category?', delete_catalog_hint: 'Are You Sure You Want to Delete This Category?',
delete_catalog_tip: 'Deletion Is Irreversible. Do You Want to Continue?', delete_catalog_tip: 'Deletion Is Irreversible. Do You Want to Continue?',
illegal_name_hint: 'Illegal Name. Please Change!', illegal_name_hint: 'Illegal Name. Please Change!',
exists_name_hint: 'This Name Already Exists in Template Management. Please Modify' exists_name_hint: 'This Name Already Exists in Template Management. Please Modify',
get_download_link_hint:
'Please contact the official template marketplace if you have not obtained the template download link.',
search_result_count: 'The search results are {0} items.',
template_center: 'Template Center',
preview: 'Preview'
}, },
commons: { commons: {
date: { date: {
@ -384,6 +392,7 @@ export default {
last_edited_by: 'Last edited by', last_edited_by: 'Last edited by',
last_edit_time: 'last edit time', last_edit_time: 'last edit time',
big_data_screen: 'Big data screen', big_data_screen: 'Big data screen',
big_screen: 'Big screen',
dashboard: 'Dashboard', dashboard: 'Dashboard',
data_set: 'data set', data_set: 'data set',
data_source: 'data source', data_source: 'data source',
@ -411,7 +420,13 @@ export default {
password_null_hint: 'Password cannot be empty. Please re-enter!', password_null_hint: 'Password cannot be empty. Please re-enter!',
password_hint: password_hint:
'Password must be a 4-10 character string containing numbers, letters, and special characters [!@#$%^&*()_+]', 'Password must be a 4-10 character string containing numbers, letters, and special characters [!@#$%^&*()_+]',
max_ticket_count: 'Supports up to 5 Tickets creation' max_ticket_count: 'Supports up to 5 Tickets creation',
last: 'Previous',
next: 'Next',
recommend: 'Recommended',
recent: 'Recently Used',
all_types: 'All Types',
all_source: 'All Sources'
}, },
data_set: { data_set: {
ten_wan: '100000', ten_wan: '100000',
@ -1077,5 +1092,323 @@ export default {
switch_chart: 'Switch chart type', switch_chart: 'Switch chart type',
switch_table: 'Switch to detail table', switch_table: 'Switch to detail table',
download: 'Download' download: 'Download'
},
sync_manage: {
title: 'Sync Management',
ds_search_placeholder: 'Search by name or description'
},
sync_datasource: {
title: 'Data Connection Management',
source_ds: 'Source',
target_ds: 'Target',
add_source_ds: 'Add',
add_target_ds: 'Add',
name: 'Name',
desc: 'Description',
type: 'Type',
status: 'Status',
create_time: 'Creation Time',
update_time: 'Update Time',
operation: 'Operation',
edit: 'Edit',
delete: 'Delete',
confirm_batch_delete_target_ds: 'Are you sure you want to delete {0} target data sources?',
confirm_batch_delete_source_ds: 'Are you sure you want to delete {0} source data sources?',
recently_created: 'Recently Created',
has_running_task_msg:
'Once the running task is completed, synchronization will continue using the previous configuration. You need to manually resave the task',
edit_datasource: 'Edit',
add_datasource: 'Create New',
config_info: 'Configuration Information',
ds_type: 'Datasource Type',
valid: 'Valid',
invalid: 'Invalid',
start_time: 'Start Time',
end_time: 'End Time',
ds_delete_confirm: 'Are you sure you want to delete this data source?',
datasource: 'Data Source',
select_folder: 'Please select a folder',
sync_ds: 'Synchronize',
sync_to_datasource: 'Sync to the prepared data source list',
input_ds_name: 'Please enter the data source name',
folder: 'Parent Folder',
cancel: 'Cancel',
save: 'Save',
next: 'Next',
prev: 'Previous',
validate: 'Validate',
validate_success: 'Validation Successful',
select_type: 'Please select the data source type',
extra_params: 'Additional JDBC connection string',
remark: 'Remark',
input_name: 'Please enter name',
input_limit_2_25: '{0}-{1} characters',
input_limit_2_50: '2-50 characters',
input_limit_2_64: '2-64 characters',
input_limit_1_64: '1-64 characters',
data_source_configuration: 'Data source configuration',
data_source_table: 'Data source table',
auth_method: 'Authentication method',
passwd: 'Username and password',
kerbers_info:
'Please ensure krb5.conf and Keytab Key are added to the path: /opt/dataease2.0/conf',
client_principal: 'Client Principal',
keytab_Key_path: 'Keytab Key Path',
data_base: 'Database name',
user_name: 'Username',
password: 'Password',
host: 'Host name/IP address',
doris_host: 'Doris address',
query_port: 'Query Port',
http_port: 'HTTP Port',
port: 'Port',
datasource_url: 'Address',
please_input_datasource_url: 'Please enter Elasticsearch address, e.g., http://es_host:es_port',
please_input_data_base: 'Please enter database name',
please_input_jdbc_url: 'Please enter JDBC connection',
please_select_oracle_type: 'Select connection type',
please_input_user_name: 'Please enter username',
please_input_password: 'Please enter password',
please_input_host: 'Please enter host',
please_input_url: 'Please enter URL address',
please_input_port: 'Please enter port',
please_input_be_port: 'Please enter BE port',
modify: 'Edit data source',
validate_failed: 'Validation failed',
oracle_connection_type: 'Service name/SID',
oracle_sid: 'SID',
oracle_service_name: 'Service name',
get_schema: 'Get Schema',
schema: 'Schema',
charset: 'Character set',
targetCharset: 'Target character set',
please_choose_schema: 'Please select database Schema',
please_choose_charset: 'Please select database character set',
please_choose_targetCharset: 'Please select target character set',
edit_datasource_msg:
'Modifying data source information may cause datasets under this data source to become unavailable. Confirm modification?',
repeat_datasource_msg: 'Duplicate data source information with the same configuration exists.',
in_valid: 'Invalid data source',
initial_pool_size: 'Initial connection count',
min_pool_size: 'Minimum connection count',
max_pool_size: 'Maximum connection count',
max_idle_time: 'Maximum idle time (seconds)',
bucket_num: 'Bucket count',
replication_num: 'Replication count',
please_input_bucket_num: 'Please enter bucket count',
please_input_replication_num: 'Please enter replication count',
acquire_increment: 'Increment',
connect_timeout: 'Connection timeout (seconds)',
please_input_initial_pool_size: 'Please enter initial connection count',
please_input_min_pool_size: 'Please enter minimum connection count',
please_input_max_pool_size: 'Please enter maximum connection count',
please_input_max_idle_time: 'Please enter maximum idle time (seconds)',
please_input_acquire_increment: 'Please enter increment',
please_input_query_timeout: 'Please enter query timeout',
please_input_connect_timeout: 'Please enter connection timeout (seconds)',
no_less_then_0: 'Parameters in advanced settings cannot be less than zero',
port_no_less_then_0: 'Port cannot be less than zero',
priority: 'Advanced settings',
jdbcUrl: 'JDBC connection',
_ip_address: 'Please enter host name/IP address',
display_name: 'Display name',
connection_mode: 'Connection mode',
please_select: 'Please select',
query_timeout: 'Query timeout',
description: 'Description',
tips: 'Tips'
},
sync_summary: {
summary: 'Summary',
data_source_number: 'Number of data sources',
task_number: 'Number of task',
execution_count: 'Execution count',
execution_results_in_the_past_7_days: 'Execution performance in the past 7 days',
sync_status_distribution: 'Sync status distribution'
},
sync_task: {
title: 'Task Management',
task_list: 'Task List',
log_list: 'Task Logs',
add_task: 'Add Task',
name: 'Name',
desc: 'Description',
status: 'Status',
create_time: 'Creation Time',
update_time: 'Update Time',
operation: 'Operation',
edit: 'Edit',
delete: 'Delete',
start: 'Enable',
stop: 'Stop',
terminated: 'Terminate',
running_one: 'Execute Once',
trigger_last_time: 'Last Time',
trigger_next_time: 'Next Time',
status_success: 'Success',
status_running: 'Syncing',
status_failed: 'Failed',
status_stopped: 'Stopped',
status_waiting: 'Waiting',
status_done: 'Task Ended',
status_terminated: 'Terminated',
status_connection_lost: 'Lost',
log: 'Log',
show_log: 'View Log',
last_execute_result: 'Last Result',
execute_result: 'Execution Result',
task_status: 'Task Status',
sync: 'Sync',
target_table: 'Target Table',
batch_del: 'Batch Delete',
selection_info: 'Selected {0} items',
clear_button: 'Clear',
task_text: 'Task',
hour: 'Hour',
day: 'Day',
week: 'Week',
month: 'Month',
year: 'Year',
minute: 'Minute',
second: 'Second',
hour_minute_second: 'Hour:Minute:Second',
please_enter_task_name: 'Please enter task name',
input_limit_255: 'Length cannot exceed 255 characters',
please_enter: 'Please enter',
please_cron: 'Please enter a valid Cron expression',
please_choose: 'Please choose',
please_choose_start_time: 'Please choose start time',
please_choose_end_time: 'Please choose end time',
end_time_must_be_later_than_start_time: 'End time must be later than start time',
please_choose_database_type: 'Please choose database type',
please_choose_database: 'Please choose database',
please_choose_table: 'Please choose table',
please_enter_sql: 'Please enter SQL',
please_choose_incremental_field: 'Please choose incremental field',
please_enter_table_name: 'Please enter table name',
input_limit_64: 'Length cannot exceed 64 characters',
must_be_met_the_table_name:
'Table name must start with a letter and can only contain letters, numbers, and underscores',
please_choose_partition_type: 'Please choose partition type',
please_enter_end_offset: 'Please enter end offset',
please_choose_partition_interval_unit: 'Please choose partition interval unit',
please_enter_partition_column_value: 'Please enter partition column value',
input_limit_4096: 'Length cannot exceed 4096 characters',
please_enter_starting_value: 'Please enter starting value',
please_enter_end_value: 'Please enter end value',
please_enter_numerical_range_interval: 'Please enter numerical range interval',
please_choose_time_range: 'Please choose time range',
edit_success: 'Edit successful',
add_success: 'Add successful',
target_database_status_is_abnormal: 'Target database status is abnormal',
edit_task: 'Edit Task',
basic_information: 'Basic Information',
source_database: 'Source Database',
target_database: 'Target Database',
task_time_out_time: 'Task Timeout (seconds)',
effective_if_greater_than_0: 'In seconds, effective if greater than 0',
retry_attempts_on_failure: 'Retry attempts on failure',
sync_frequency: 'Sync Frequency',
sync_immediately: 'Sync Immediately',
sync_cron: 'Cron Expression Setup',
sync_fixed_frequency: 'Fixed Frequency',
cron_expression: 'Cron Expression',
each: 'Every',
sync_once: 'Sync Once',
confirm: 'Confirm',
msg_get_database_table_failed: 'Failed to get database table',
msg_source_database_status_is_abnormal: 'Source database status is abnormal',
database: 'Database',
database_type: 'Type',
query_method: 'Query Method',
please_choose_data_extraction_method: 'Please choose data extraction method',
table: 'Table',
sql_tip_1:
'This method does not always return the exact length or precision of column types as set by the user, but it can still serve as a reference for determining the maximum display length of each column in the result set.',
sql_tip_2:
'To obtain more accurate column type length and precision, please use the library table method, or set the length and precision in the field mapping of the next step.',
please_enter_sql: 'Please enter query SQL',
msg_confirm_delete_field: 'Are you sure you want to delete this field?',
source_field: 'Source Field',
field_type: 'Type',
field_length: 'Length',
field_precision: 'Precision',
field_key: 'Key',
field_index: 'Index',
field_comment: 'Comment',
confirm_delete_field: 'Are you sure you want to delete field {0}?',
msg_field_list_empty_tip:
'Field list cannot be empty, and fields with unknown types or empty names should not be included. Please check.',
next_week: 'Next Week',
next_month: 'Next Month',
next_three_month: 'Next Three Months',
must_be_start_less_end: 'End value of the range must be greater than the start value',
must_be_partition_interval_greater_than_0: 'Partition interval must be greater than 0',
must_be_partition_interval_less_end_start_difference:
'Partition interval must be less than the difference between the end and start values',
date: 'Date',
list: 'Column',
number: 'Number',
define_mapping_field: 'Define Mapping Field',
target_database_type: 'Target Database Type',
delete_field: 'Delete Field',
add_field: 'Add Field',
edit_field: 'Edit Field',
add_all_field: 'Add All Fields',
fault_tolerance_rate: 'Fault Tolerance Rate',
fault_tolerance_rate_tip:
'0 to 1, default is 0, meaning if there is one error data in the sync batch, the entire batch import task will fail.',
incremental_sync: 'Incremental Sync',
incremental_sync_tip_1: 'Full Sync: Full overwrite sync',
incremental_sync_tip_2:
'Incremental Sync: Sync based on incremental field, the incremental field must be of integer or time type',
incremental_field: 'Incremental Field',
enable_partition: 'Enable Partition',
enable_partition_tip:
'Enabling partition requires the field list to not contain any empty values',
partition_type: 'Partition Type',
partition_field: 'Partition Field',
on: 'Enable',
off: 'Disable',
picker_to: 'To',
picker_start: 'Start',
picker_end: 'End',
end_offset: 'End Offset',
number_range: 'Number Range',
partition_interval: 'Partition Interval',
partition_column_value: 'Partition Column Value',
partition_column_value_placeholder: 'Partition format: p1:"v1","v2","v3";p2:"v1","v2"',
partition_interval_unit: 'Partition Interval Unit',
input_limit: 'Length cannot exceed {0} characters',
cannot_begin_with_number: 'Field name cannot start with a number',
duplicate_field_tip:
'Duplicate field [{0}], the same source field cannot be mapped multiple times',
duplicate_name_error: 'Name duplication [{0}]',
confirm_batch_delete: 'Are you sure you want to batch delete the task?',
op_success: 'Operation successful',
search_input_name_desc_placeholder: 'Search by name or description',
confirm_delete_msg: 'Confirm Deletion?',
target_table_info: 'Target Table Information',
confirm_clear_msg: 'Are you sure you want to clear {0}?',
clear: 'Clear',
op_success_refresh: 'Operation successful, please refresh later',
execute_time: 'Execution Time',
clear_log: 'Clear Log',
search_input_name_id_placeholder: 'Search by Name or ID',
log_id: 'Log ID',
op: 'Operation',
view_execute_log: 'View Execution Log',
submit_true: 'Confirm',
please_choose_clear_method: 'Please choose a clearing method',
last_1_days_log: 'Logs from 1 day ago',
last_1_weeks_log: 'Logs from 1 week ago',
last_1_months_log: 'Logs from 1 month ago',
last_3_months_log: 'Logs from 3 months ago',
last_6_months_log: 'Logs from 6 months ago',
last_1_years_log: 'Logs from 1 year ago',
execute_log: 'Execution Log',
done: 'Done',
connection_lost: 'Connection Lost',
task_name: 'Task Name'
} }
} }

View File

@ -11,6 +11,7 @@ export default {
add_component_hint: '點擊或拖拽左側組件添加字段' add_component_hint: '點擊或拖拽左側組件添加字段'
}, },
inputText: '請輸入', inputText: '請輸入',
selectText: '請選擇',
add: '添加', add: '添加',
account: '賬號', account: '賬號',
email: '郵箱', email: '郵箱',
@ -122,7 +123,11 @@ export default {
delete_catalog_hint: '確定刪除該分類嗎', delete_catalog_hint: '確定刪除該分類嗎',
delete_catalog_tip: '刪除后不可恢復是否繼續', delete_catalog_tip: '刪除后不可恢復是否繼續',
illegal_name_hint: '不合法命名請更換', illegal_name_hint: '不合法命名請更換',
exists_name_hint: '當前名稱已在模版管理中存在請修改' exists_name_hint: '當前名稱已在模版管理中存在請修改',
get_download_link_hint: '未獲取模板下載鏈接請聯系模板市場官方',
search_result_count: '的搜索結果是 {0} ',
template_center: '模版中心',
preview: '預覽'
}, },
work_branch: { work_branch: {
back_to_work_branch: '返回工作台', back_to_work_branch: '返回工作台',
@ -137,6 +142,7 @@ export default {
last_edited_by: '最近編輯人', last_edited_by: '最近編輯人',
last_edit_time: '最近編輯時間', last_edit_time: '最近編輯時間',
big_data_screen: '數據大屏', big_data_screen: '數據大屏',
big_screen: '大屏',
dashboard: '儀表板', dashboard: '儀表板',
data_set: '數據集', data_set: '數據集',
data_source: '數據源', data_source: '數據源',
@ -161,7 +167,13 @@ export default {
error_link_hint: '鏈接格式錯誤請重新填寫', error_link_hint: '鏈接格式錯誤請重新填寫',
password_null_hint: '密碼不能為空請重新輸入', password_null_hint: '密碼不能為空請重新輸入',
password_hint: '密碼必須是包含數字字母特殊字符[!@#$%^&*()_+]的4-10位字符串', password_hint: '密碼必須是包含數字字母特殊字符[!@#$%^&*()_+]的4-10位字符串',
max_ticket_count: '最多支持創建5個Ticket' max_ticket_count: '最多支持創建5個Ticket',
last: '上一個',
next: '下一個',
recommend: '推薦',
recent: '最近使用',
all_types: '全部類型',
all_source: '全部來源'
}, },
data_set: { data_set: {
ten_wan: '10萬', ten_wan: '10萬',
@ -1868,7 +1880,8 @@ export default {
zoom_level: '縮放等級', zoom_level: '縮放等級',
central_point: '中心點', central_point: '中心點',
full_display: '全量顯示', full_display: '全量顯示',
show_hover_style: '顯示鼠標懸浮樣式' show_hover_style: '顯示鼠標懸浮樣式',
merge_cells: '合並單元格'
}, },
dataset: { dataset: {
scope_edit: '僅編輯時生效', scope_edit: '僅編輯時生效',
@ -2140,7 +2153,7 @@ export default {
calc_tips: { calc_tips: {
tip1: '表達式語法請遵循calcite語法', tip1: '表達式語法請遵循calcite語法',
tip1_1: '表達式語法請遵循該數據源對應的數據庫語法', tip1_1: '表達式語法請遵循該數據源對應的數據庫語法',
tip2: '聚合運算僅能在圖表中生效', tip2: '聚合運算僅能在圖表中生效在預覽時顯示為"-"',
tip3: '引用字段以 "[" 開始 "]" 結束', tip3: '引用字段以 "[" 開始 "]" 結束',
tip4: '請勿修改引用內容否則將引用失敗', tip4: '請勿修改引用內容否則將引用失敗',
tip5: '若輸入與引用字段相同格式的內容將被當作引用字段處理', tip5: '若輸入與引用字段相同格式的內容將被當作引用字段處理',
@ -2603,6 +2616,8 @@ export default {
enter_name_tips: '請輸入儀表板名稱', enter_name_tips: '請輸入儀表板名稱',
name: '名稱', name: '名稱',
apply_template: '應用模板', apply_template: '應用模板',
style_template: '樣式模板',
all_type: '全部分類',
enter_template_name_tips: '搜索模板名稱', enter_template_name_tips: '搜索模板名稱',
pic_adaptation: '適應組件', pic_adaptation: '適應組件',
pic_equiratio: '等比適應', pic_equiratio: '等比適應',
@ -2949,7 +2964,14 @@ export default {
pvp: '密碼有效期', pvp: '密碼有效期',
defaultLogin: '默認登錄方式', defaultLogin: '默認登錄方式',
shareDisable: '禁用分享', shareDisable: '禁用分享',
sharePeRequire: '分享有效期密碼必填' sharePeRequire: '分享有效期密碼必填',
defaultSort: '資源默認排序方式'
},
resource_sort: {
time_asc: '按創建時間升序',
time_desc: '按創建時間降序',
name_asc: '按名稱升序',
name_desc: '按名稱降序'
}, },
setting_email: { setting_email: {
title: '郵件設置', title: '郵件設置',
@ -2963,7 +2985,7 @@ export default {
}, },
sync_manage: { sync_manage: {
title: '同步管理', title: '同步管理',
ds_search_placeholder: '索名稱,描述' ds_search_placeholder: '尋名稱或描述'
}, },
sync_datasource: { sync_datasource: {
title: '數據連接管理', title: '數據連接管理',
@ -2976,18 +2998,127 @@ export default {
type: '類型', type: '類型',
status: '狀態', status: '狀態',
create_time: '創建時間', create_time: '創建時間',
update_time: '更新時間', update_time: '更新时间',
operation: '操作', operation: '操作',
edit: '編輯', edit: '編輯',
delete: '刪除', delete: '刪除',
confirm_batch_delete_target_ds: '確定刪除{0}個目標數據源嗎', confirm_batch_delete_target_ds: '確定刪除{0}個目標數據源嗎',
confirm_batch_delete_source_ds: '確定刪除{0}個源數據源嗎' confirm_batch_delete_source_ds: '確定刪除{0}個源數據源嗎',
recently_created: '最近創建',
has_running_task_msg:
'執行中的任務完成後將繼續使用修改之前的配置進行同步需手動對任務進行重新保存',
edit_datasource: '編輯數據源',
add_datasource: '新建數據源',
config_info: '配置信息',
ds_type: '數據源類型',
valid: '有效',
invalid: '無效',
start_time: '開始時間',
end_time: '結束時間',
ds_delete_confirm: '確定刪除該數據源嗎',
datasource: '數據源',
select_folder: '請選擇文件夾',
sync_ds: '同步數據源',
sync_to_datasource: '將同步至數據準備的數據源列表',
input_ds_name: '請輸入數據源名稱',
folder: '所屬文件夾',
cancel: '取消',
save: '儲存',
next: '下一步',
prev: '上一步',
validate: '驗證',
validate_success: '驗證成功',
select_type: '请选择數據源類型',
extra_params: '額外的 JDBC 連線字串',
remark: '備註',
input_name: '請輸入名稱',
input_limit_2_25: '{0}-{1}字符',
input_limit_2_50: '2-50字符',
input_limit_2_64: '2-64字符',
input_limit_1_64: '1-64字符',
data_source_configuration: '數據源配置',
data_source_table: '數據源表',
auth_method: '認證方式',
passwd: '用戶名和密碼',
kerbers_info: '請確保 krb5.conf Keytab Key 已經添加到路徑/opt/dataease2.0/conf',
client_principal: '客戶端主體',
keytab_Key_path: 'Keytab Key 路徑',
data_base: '數據庫名稱',
user_name: '用戶名',
password: '密碼',
host: '主機名/IP地址',
doris_host: 'Doris 地址',
query_port: '查詢端口',
http_port: 'HTTP 端口',
port: '端口',
datasource_url: '地址',
please_input_datasource_url: '請輸入 Elasticsearch 地址: http://es_host:es_port',
please_input_data_base: '請輸入數據庫名稱',
please_input_jdbc_url: '請輸入 JDBC 連接',
please_select_oracle_type: '選擇連接類型',
please_input_user_name: '請輸入用戶名',
please_input_password: '請輸入密碼',
please_input_host: '請輸入主機',
please_input_url: '請輸入URL地址',
please_input_port: '請輸入端口',
please_input_be_port: '請輸入 BE 端口',
modify: '編輯數據源',
validate_failed: '驗證失敗',
oracle_connection_type: '服務名/SID',
oracle_sid: 'SID',
oracle_service_name: '服務名',
get_schema: '獲取 Schema',
schema: 'Schema',
charset: '字符集',
targetCharset: '目標字符集',
please_choose_schema: '請選擇數據庫 Schema',
please_choose_charset: '請選擇數據庫字符集',
please_choose_targetCharset: '請選擇目標字符集',
edit_datasource_msg: '修改數據源信息可能會導致該數據源下的數據集不可用確認修改',
repeat_datasource_msg: '已經存在相同配置的數據源信息',
in_valid: '無效數據源',
initial_pool_size: '初始連接數',
min_pool_size: '最小連接數',
max_pool_size: '最大連接數',
max_idle_time: '最大空閒()',
bucket_num: 'Bucket 數量',
replication_num: '副本數量',
please_input_bucket_num: '請輸入 Bucket 數量',
please_input_replication_num: '請輸入副本數量',
acquire_increment: '增長數',
connect_timeout: '連接超時()',
please_input_initial_pool_size: '請輸入初始連接數',
please_input_min_pool_size: '請輸入最小連接數',
please_input_max_pool_size: '請輸入最大連接數',
please_input_max_idle_time: '請輸入最大空閒()',
please_input_acquire_increment: '請輸入增長數',
please_input_query_timeout: '請輸入查詢超時',
please_input_connect_timeout: '請輸入連接超時()',
no_less_then_0: '高級設置中的參數不能小於零',
port_no_less_then_0: '端口不能小於零',
priority: '高級設置',
jdbcUrl: 'JDBC 連接',
_ip_address: '請輸入主機名/IP地址',
display_name: '顯示名稱',
connection_mode: '連接方式',
please_select: '請選擇',
query_timeout: '查询超时',
description: '描述',
tips: '提示'
},
sync_summary: {
summary: '概覽',
data_source_number: '數據源數量',
task_number: '任務數量',
execution_count: '執行次數',
execution_results_in_the_past_7_days: '過去7天執行情況',
sync_status_distribution: '同步狀態分佈'
}, },
sync_task: { sync_task: {
title: '任務管理', title: '任務管理',
list: '任務列表', task_list: '任務列表',
log_list: '任務日志', log_list: '任務日',
add_task: '添加任務', add_task: '新增任務',
name: '名稱', name: '名稱',
desc: '描述', desc: '描述',
status: '狀態', status: '狀態',
@ -3010,17 +3141,158 @@ export default {
status_done: '任務結束', status_done: '任務結束',
status_terminated: '終止', status_terminated: '終止',
status_connection_lost: '連接丟失', status_connection_lost: '連接丟失',
log: '', log: '',
show_log: '查看日', show_log: '查看日',
last_execute_result: '上次執行結果', last_execute_result: '上次執行結果',
execute_result: '執行結果', execute_result: '執行結果',
task_status: '任務狀態', task_status: '任務狀態',
sync: '同步', sync: '同步',
target_table: '目標表', target_table: '目標表',
batch_del: '批量刪除', batch_del: '批量刪除',
selection_info: '已選 {0} ', selection_info: '已選 {0} ',
clear_button: '清空', clear_button: '清空',
task_text: '任務' task_text: '任務',
hour: '小時',
day: '天',
week: '週',
month: '月',
year: '年',
minute: '分鐘',
second: '秒',
hour_minute_second: '::',
please_enter_task_name: '請輸入任務名稱',
input_limit_255: '長度不能超過255個字符',
please_enter: '請輸入',
please_cron: '請輸入有效的Cron表達式',
please_choose: '請選擇',
please_choose_start_time: '請選擇開始時間',
please_choose_end_time: '請選擇結束時間',
end_time_must_be_later_than_start_time: '結束時間必須晚於開始時間',
please_choose_database_type: '請選擇數據庫類型',
please_choose_database: '請選擇數據庫',
please_choose_table: '請選擇表格',
please_enter_sql: '請輸入SQL',
please_choose_incremental_field: '請選擇增量字段',
please_enter_table_name: '請輸入表名',
input_limit_64: '長度不能超過64個字符',
must_be_met_the_table_name: '表名必須以字母開頭並且只能包含字母數字和下劃線',
please_choose_partition_type: '請選擇分區類型',
please_enter_end_offset: '請輸入結束偏移',
please_choose_partition_interval_unit: '請選擇分區間隔單位',
please_enter_partition_column_value: '請輸入分區列值',
input_limit_4096: '長度不能超過4096個字符',
please_enter_starting_value: '請輸入起始數值',
please_enter_end_value: '請輸入結束數值',
please_enter_numerical_range_interval: '請輸入數值範圍間隔',
please_choose_time_range: '請選擇時間範圍',
edit_success: '修改成功',
add_success: '新增成功',
target_database_status_is_abnormal: '目標數據庫狀態異常',
edit_task: '編輯任務',
basic_information: '基本信息',
source_database: '源數據庫',
target_database: '目標數據庫',
task_time_out_time: '任務超時時間',
effective_if_greater_than_0: '單位秒大於0時生效',
retry_attempts_on_failure: '失敗重試次數',
sync_frequency: '同步頻率',
sync_immediately: '立即同步',
sync_cron: '表達式設置',
sync_fixed_frequency: '固定頻率',
cron_expression: 'Cron表達式',
each: '每',
sync_once: '同步一次',
confirm: '確認',
msg_get_database_table_failed: '獲取數據庫表格失敗',
msg_source_database_status_is_abnormal: '源數據庫狀態異常',
database: '數據庫',
database_type: '類型',
query_method: '查詢方式',
please_choose_data_extraction_method: '請選擇數據抽取方式',
table: '表格',
sql_tip_1:
'此方式在獲取列類型的長度或精度時並不總是返回用戶設置的精確長度或精度但它仍然可以作為一個參考值用於確定結果集中每列的最大顯示長度',
sql_tip_2:
'若需要獲得更精確的列類型長度和精度請使用庫表方式或在下一步中的字段映射中進行長度精度的設置',
please_enter_sql: '請輸入查詢SQL',
msg_confirm_delete_field: '確定刪除該字段嗎',
source_field: '源字段',
field_type: '類型',
field_length: '長度',
field_precision: '精度',
field_key: '鍵',
field_index: '索引',
field_comment: '注釋',
confirm_delete_field: '確定刪除字段 {0} ',
msg_field_list_empty_tip: '字段列表不能為空且不能包含名稱為空或類型為UNKNOWN的數據請檢查',
next_week: '未來一週',
next_month: '未來一個月',
next_three_month: '未來三個月',
must_be_start_less_end: '數值範圍結束數值必須大於起始數值',
must_be_partition_interval_greater_than_0: '分區間隔必須大於0',
must_be_partition_interval_less_end_start_difference:
'分區間隔必須小於結束數值與起始數值的差值',
date: '日期',
list: '列',
number: '數值',
define_mapping_field: '定義映射字段',
target_database_type: '目標數據庫類型',
delete_field: '刪除字段',
add_field: '新增字段',
edit_field: '編輯字段',
add_all_field: '新增所有字段',
fault_tolerance_rate: '容錯率',
fault_tolerance_rate_tip:
'01默認為0即表示同步批次數據有一條錯誤數據時整個批次的導入任務將會失敗',
incremental_sync: '增量同步',
incremental_sync_tip_1: '全量全量覆蓋同步',
incremental_sync_tip_2: '增量根據增量字段增量同步增量字段必須是整型或時間類型',
incremental_field: '增量字段',
enable_partition: '啟用分區',
enable_partition_tip: '啟用分區字段列表不能有空值',
partition_type: '分區類型',
partition_field: '分區字段',
on: '啟用',
off: '關閉',
picker_to: '至',
picker_start: '開始',
picker_end: '截止',
end_offset: '結束偏移',
number_range: '數值範圍',
partition_interval: '分區間隔',
partition_column_value: '分區列值',
partition_column_value_placeholder: '分區格式為: p1:"v1","v2","v3";p2:"v1","v2"',
partition_interval_unit: '分區間隔單位',
input_limit: '長度不能超過 {0} 個字符',
cannot_begin_with_number: '字段名稱不能以數字開頭',
duplicate_field_tip: '重複字段 [{0}]同一源字段不能映射多次',
duplicate_name_error: '名稱重複 [{0}]',
confirm_batch_delete: '確定批量刪除任務',
op_success: '操作成功',
search_input_name_desc_placeholder: '搜索名稱描述',
confirm_delete_msg: '確定刪除?',
target_table_info: '目標表資訊',
confirm_clear_msg: '確定清理 {0} ',
clear: '清理',
op_success_refresh: '操作成功請稍後刷新',
execute_time: '執行時間',
clear_log: '清理日誌',
search_input_name_id_placeholder: '搜尋名稱或ID',
log_id: '日誌ID',
op: '操作',
view_execute_log: '查看執行日誌',
submit_true: '確定',
please_choose_clear_method: '請選擇清理方式',
last_1_days_log: '1 天前的日誌',
last_1_weeks_log: '1 週前的日誌',
last_1_months_log: '1 個月前的日誌',
last_3_months_log: '3 個月前的日誌',
last_6_months_log: '6 個月前的日誌',
last_1_years_log: '1 年前的日誌',
execute_log: '執行日誌',
done: '完成',
connection_lost: '連接斷開',
task_name: '任務名稱'
}, },
watermark: { watermark: {
support_params: '當前支持的參數', support_params: '當前支持的參數',

View File

@ -11,6 +11,7 @@ export default {
add_component_hint: '点击或拖拽左侧组件添加字段' add_component_hint: '点击或拖拽左侧组件添加字段'
}, },
inputText: '请输入', inputText: '请输入',
selectText: '请选择',
add: '添加', add: '添加',
account: '账号', account: '账号',
email: '邮箱', email: '邮箱',
@ -122,7 +123,11 @@ export default {
delete_catalog_hint: '确定删除该分类吗', delete_catalog_hint: '确定删除该分类吗',
delete_catalog_tip: '删除后不可恢复是否继续', delete_catalog_tip: '删除后不可恢复是否继续',
illegal_name_hint: '不合法命名请更换', illegal_name_hint: '不合法命名请更换',
exists_name_hint: '当前名称已在模版管理中存在请修改' exists_name_hint: '当前名称已在模版管理中存在请修改',
get_download_link_hint: '未获取模板下载链接请联系模板市场官方',
search_result_count: '的搜索结果是 {0} ',
template_center: '模版中心',
preview: '预览'
}, },
work_branch: { work_branch: {
back_to_work_branch: '返回工作台', back_to_work_branch: '返回工作台',
@ -137,6 +142,7 @@ export default {
last_edited_by: '最近编辑人', last_edited_by: '最近编辑人',
last_edit_time: '最近编辑时间', last_edit_time: '最近编辑时间',
big_data_screen: '数据大屏', big_data_screen: '数据大屏',
big_screen: '大屏',
dashboard: '仪表板', dashboard: '仪表板',
data_set: '数据集', data_set: '数据集',
data_source: '数据源', data_source: '数据源',
@ -161,7 +167,13 @@ export default {
error_link_hint: '链接格式错误请重新填写', error_link_hint: '链接格式错误请重新填写',
password_null_hint: '密码不能为空请重新输入', password_null_hint: '密码不能为空请重新输入',
password_hint: '密码必须是包含数字字母特殊字符[!@#$%^&*()_+]的4-10位字符串', password_hint: '密码必须是包含数字字母特殊字符[!@#$%^&*()_+]的4-10位字符串',
max_ticket_count: '最多支持创建5个Ticket' max_ticket_count: '最多支持创建5个Ticket',
last: '上一个',
next: '下一个',
recommend: '推荐',
recent: '最近使用',
all_types: '全部类型',
all_source: '全部来源'
}, },
data_set: { data_set: {
ten_wan: '10万', ten_wan: '10万',
@ -1868,7 +1880,8 @@ export default {
zoom_level: '缩放等级', zoom_level: '缩放等级',
central_point: '中心点', central_point: '中心点',
full_display: '全量显示', full_display: '全量显示',
show_hover_style: '显示鼠标悬浮样式' show_hover_style: '显示鼠标悬浮样式',
merge_cells: '合并单元格'
}, },
dataset: { dataset: {
scope_edit: '仅编辑时生效', scope_edit: '仅编辑时生效',
@ -2140,7 +2153,7 @@ export default {
calc_tips: { calc_tips: {
tip1: '表达式语法请遵循calcite语法', tip1: '表达式语法请遵循calcite语法',
tip1_1: '表达式语法请遵循该数据源对应的数据库语法', tip1_1: '表达式语法请遵循该数据源对应的数据库语法',
tip2: '聚合运算仅能在图表中生效', tip2: '聚合运算仅能在图表中生效在预览时显示为"-"',
tip3: '引用字段以 "[" 开始 "]" 结束', tip3: '引用字段以 "[" 开始 "]" 结束',
tip4: '请勿修改引用内容否则将引用失败', tip4: '请勿修改引用内容否则将引用失败',
tip5: '若输入与引用字段相同格式的内容将被当作引用字段处理', tip5: '若输入与引用字段相同格式的内容将被当作引用字段处理',
@ -2540,6 +2553,98 @@ export default {
sql_variable: { sql_variable: {
variable_mgm: '参数设置' variable_mgm: '参数设置'
}, },
v_query: {
the_minimum_value: '数值区间最大值必须大于最小值',
before_querying: '查询条件是必填项请设置选项值后再进行查询',
here_or_click: '将右侧的字段拖拽到这里 点击',
add_query_condition: '添加查询条件',
set_filter_condition: '设置过滤条件',
delete_condition: '删除条件',
last_3_months: '最近 3 ',
last_6_months: '最近 6 ',
last_12_months: '最近 12 ',
last_3_days: '最近 3 ',
month_to_date: '月初至今',
year_to_date: '年初至今',
exact_match: '精确匹配',
fuzzy_match: '模糊匹配',
option_type: '选项类型',
time_filter_range: '设置时间筛选范围',
configured: '已配置',
is_not_supported: '绑定参数后不支持传空数据',
contains_empty_data: '选项值包含空数据',
unnamed: '未命名',
cannot_be_empty: '查询条件或字段不能为空',
the_first_level: '第一级无需配置被级联字段',
configure_cascaded_fields: '与上一级使用同一个数据集,无需配置被级联字段',
condition_cascade_configuration: '查询条件级联配置',
not_reverse_cascade: '(仅上级能级联下级,不可反向级联)',
must_be_met: '基于当前查询组件的查询条件如果需要进行级联配置需要满足以下条件',
select_data_set: '1. 展示类型文本下拉组件和数字下拉组件2. 选项值来源选择数据集',
add_cascade_configuration: '添加级联配置',
add_cascade_condition: '添加级联条件',
query_condition_level: '查询条件层级',
select_query_condition: '请选择查询条件',
select_cascaded_field: '请选择被级联字段',
level_1: '{msg}',
to_modify_it: '数据集的修改会导致级联配置失效因此对应的级联关系将被清除确定修改吗',
be_linked_first: '请先勾选需要联动的图表及字段',
cannot_be_performed: '所选字段类型不一致无法进行查询配置',
numerical_parameter_configuration: '数值参数配置必须配置最大值和最小值',
format_is_inconsistent: '时间格式不一致',
cannot_be_empty_de: '查询条件为必填项,默认值不能为空',
the_start_time: '结束时间必须大于开始时间!',
and_end_time: '时间参数配置必须配置开始时间和结束时间',
cannot_be_empty_time: '默认时间不能为空!',
range_please_reset: '默认值超出日期筛选范围内请重新设置',
cannot_be_empty_input: '手工输入-选项值不能为空',
option_value_field: '请选择数据集及选项值字段',
the_data_set: '请选择数据集的选项值字段',
cannot_be_empty_name: '字段名称不能为空',
query_condition_setting: '查询条件设置',
query_condition: '查询条件',
chart_and_field: '选择关联图表及字段',
be_switched_to: '注意:自动模式支持同数据集自动关联字段可切换到',
to_automatic_again: '自定义模式切换到自定义模式后无法再切换为自动',
as_query_conditions: '脱敏字段不能被设置为查询条件',
query_condition_configuration: '查询条件配置',
required_items: '必填项',
display_type: '展示类型',
text_drop_down: '文本下拉',
text_search: '文本搜索',
drop_down_tree: '下拉树',
number_drop_down: '数字下拉',
number_range: '数值区间',
of_option_values: '选项值数量',
tree_structure_design: '下拉树结构设计',
the_tree_structure: '点击进行树结构设计',
time_granularity: '时间粒度',
the_time_granularity: '请选择时间粒度',
option_value_source: '选项值来源',
manual_input: '手动输入',
query_field: '查询字段',
display_field: '显示字段',
the_sorting_field: '请选择排序字段',
condition_type: '条件类型',
single_condition: '单条件',
with_condition: '与条件',
or_condition: '或条件',
hide_condition_switch: '隐藏条件切换',
cannot_be_displayed: '图表所使用的数据集不同, 无法展示配置项',
component_cascade_configuration: '查询组件级联配置',
time_type: '时间类型',
start_at: '开始于',
end_at: '结束于',
time_interval: '时间区间',
interval_type: '区间类型',
query_time_window: '动态查询时间窗口',
maximum_single_query: '单次查询最多',
empty_data: '空数据',
time_selection: '时间选择',
select_a_field: '层级字段不能为空,请选择字段!',
add_level: '添加层级',
tree_query_field: '下拉树查询字段'
},
panel: { panel: {
column_name: '字段名称' column_name: '字段名称'
}, },
@ -2603,6 +2708,8 @@ export default {
enter_name_tips: '请输入仪表板名称', enter_name_tips: '请输入仪表板名称',
name: '名称', name: '名称',
apply_template: '应用模板', apply_template: '应用模板',
style_template: '样式模板',
all_type: '全部分类',
enter_template_name_tips: '搜索模板名称', enter_template_name_tips: '搜索模板名称',
pic_adaptation: '适应组件', pic_adaptation: '适应组件',
pic_equiratio: '等比适应', pic_equiratio: '等比适应',
@ -2949,7 +3056,14 @@ export default {
pvp: '密码有效期', pvp: '密码有效期',
defaultLogin: '默认登录方式', defaultLogin: '默认登录方式',
shareDisable: '禁用分享', shareDisable: '禁用分享',
sharePeRequire: '分享有效期密码必填' sharePeRequire: '分享有效期密码必填',
defaultSort: '资源默认排序方式'
},
resource_sort: {
time_asc: '按创建时间升序',
time_desc: '按创建时间降序',
name_asc: '按名称升序',
name_desc: '按名称降序'
}, },
setting_email: { setting_email: {
title: '邮件设置', title: '邮件设置',
@ -2981,11 +3095,120 @@ export default {
edit: '编辑', edit: '编辑',
delete: '删除', delete: '删除',
confirm_batch_delete_target_ds: '确定删除{0}个目标数据源吗', confirm_batch_delete_target_ds: '确定删除{0}个目标数据源吗',
confirm_batch_delete_source_ds: '确定删除{0}个源数据源吗' confirm_batch_delete_source_ds: '确定删除{0}个源数据源吗',
recently_created: '最近创建',
has_running_task_msg:
'执行中的任务完成后将继续使用修改之前的配置进行同步需手动对任务进行重新保存',
edit_datasource: '编辑数据源',
add_datasource: '新建数据源',
config_info: '配置信息',
ds_type: '数据源类型',
valid: '有效',
invalid: '无效',
start_time: '开始时间',
end_time: '结束时间',
ds_delete_confirm: '确定删除该数据源吗',
datasource: '数据源',
select_folder: '请选择文件夹',
sync_ds: '同步数据源',
sync_to_datasource: '将同步至数据准备的数据源列表',
input_ds_name: '请输入数据源名称',
folder: '所属文件夹',
cancel: '取消',
save: '保存',
next: '下一步',
prev: '上一步',
validate: '校验',
validate_success: '校验成功',
select_type: '请选择数据源类型',
extra_params: '额外的 JDBC 连接字符串',
remark: '备注',
input_name: '请输入名称',
input_limit_2_25: '{0}-{1}字符',
input_limit_2_50: '2-50字符',
input_limit_2_64: '2-64字符',
input_limit_1_64: '1-64字符',
data_source_configuration: '数据源配置',
data_source_table: '数据源表',
auth_method: '认证方式',
passwd: '用户名密码',
kerbers_info: '请确保 krb5.ConfKeytab Key已经添加到路径/opt/dataease2.0/conf',
client_principal: 'Client Principal',
keytab_Key_path: 'Keytab Key Path',
data_base: '数据库名称',
user_name: '用户名',
password: '密码',
host: '主机名/IP地址',
doris_host: 'Doris 地址',
query_port: 'Query Port',
http_port: 'Http Port',
port: '端口',
datasource_url: '地址',
please_input_datasource_url: '请输入 Elasticsearch 地址: http://es_host:es_port',
please_input_data_base: '请输入数据库名称',
please_input_jdbc_url: '请输入 JDBC 连接',
please_select_oracle_type: '选择连接类型',
please_input_user_name: '请输入用户名',
please_input_password: '请输入密码',
please_input_host: '请输入主机',
please_input_url: '请输入URL地址',
please_input_port: '请输入端口',
please_input_be_port: '请输入BE端口',
modify: '编辑数据源',
validate_failed: '校验失败',
oracle_connection_type: '服务名/SID',
oracle_sid: 'SID',
oracle_service_name: '服务名',
get_schema: '获取 Schema',
schema: 'Schema',
charset: '字符集',
targetCharset: '目标字符集',
please_choose_schema: '请选择数据库 Schema',
please_choose_charset: '请选择数据库字符集',
please_choose_targetCharset: '请选择目标字符集',
edit_datasource_msg: '修改数据源信息可能会导致该数据源下的数据集不可用确认修改',
repeat_datasource_msg: '已经存在相同配置的数据源信息, ',
in_valid: '无效数据源',
initial_pool_size: '初始连接数',
min_pool_size: '最小连接数',
max_pool_size: '最大连接数',
max_idle_time: '最大空闲()',
bucket_num: 'Bucket 数量',
replication_num: '副本数量',
please_input_bucket_num: '请输入 Bucket 数量',
please_input_replication_num: '请输入副本数量',
acquire_increment: '增长数',
connect_timeout: '连接超时()',
please_input_initial_pool_size: '请输入初始连接数',
please_input_min_pool_size: '请输入最小连接数',
please_input_max_pool_size: '请输入最大连接数',
please_input_max_idle_time: '请输入最大空闲()',
please_input_acquire_increment: '请输入增长数',
please_input_query_timeout: '请输入查询超时',
please_input_connect_timeout: '请输入连接超时()',
no_less_then_0: '高级设置中的参数不能小于零',
port_no_less_then_0: '端口不能小于零',
priority: '高级设置',
jdbcUrl: 'JDBC 连接',
_ip_address: '请输入主机名/IP地址',
display_name: '显示名称',
connection_mode: '连接方式',
please_select: '请选择',
query_timeout: '查询超时',
description: '描述',
tips: '提示'
},
sync_summary: {
summary: '概览',
data_source_number: '数据源数量',
task_number: '任务数量',
execution_count: '执行次数',
execution_results_in_the_past_7_days: '过去7天执行情况',
sync_status_distribution: '同步状态分布'
}, },
sync_task: { sync_task: {
title: '任务管理', title: '任务管理',
list: '任务列表', task_list: '任务列表',
log_list: '任务日志', log_list: '任务日志',
add_task: '添加任务', add_task: '添加任务',
name: '名称', name: '名称',
@ -3020,7 +3243,148 @@ export default {
batch_del: '批量删除', batch_del: '批量删除',
selection_info: '已选 {0} ', selection_info: '已选 {0} ',
clear_button: '清空', clear_button: '清空',
task_text: '任务' task_text: '任务',
hour: '小时',
day: '天',
week: '周',
month: '月',
year: '年',
minute: '分钟',
second: '秒',
hour_minute_second: '::',
please_enter_task_name: '请输入任务名称',
input_limit_255: '长度不能超过255个字符',
please_enter: '请输入',
please_cron: '请输入可用的Cron表达式',
please_choose: '请选择',
please_choose_start_time: '请选择开始时间',
please_choose_end_time: '请选择结束时间',
end_time_must_be_later_than_start_time: '结束时间必须大于开始时间',
please_choose_database_type: '请选择数据库类型',
please_choose_database: '请选择数据库',
please_choose_table: '请选择表',
please_enter_sql: '请输入SQL',
please_choose_incremental_field: '请选择增量字段',
please_enter_table_name: '请输入表名',
input_limit_64: '长度不能超过64个字符',
must_be_met_the_table_name: '必须以字母开头并且只能包含字母数字下划线',
please_choose_partition_type: '请选择分区类型',
please_enter_end_offset: '请输入结束偏移度',
please_choose_partition_interval_unit: '请选择分区间隔的单位',
please_enter_partition_column_value: '请输入分区列值',
input_limit_4096: '长度不能超过4096个字符',
please_enter_starting_value: '请输入起始数值',
please_enter_end_value: '请输入结束数值',
please_enter_numerical_range_interval: '请输入数值分区间隔',
please_choose_time_range: '请选择时间范围',
edit_success: '修改成功',
add_success: '添加成功',
target_database_status_is_abnormal: '目标数据库状态异常',
edit_task: '编辑任务',
basic_information: '基本信息',
source_database: '源数据库',
target_database: '目标数据库',
task_time_out_time: '任务超时时间',
effective_if_greater_than_0: '单位秒大于0时生效',
retry_attempts_on_failure: '失败重试次数',
sync_frequency: '同步频率',
sync_immediately: '立即同步',
sync_cron: '表达式设定',
sync_fixed_frequency: '固定频率',
cron_expression: 'Cron表达式',
each: '每',
sync_once: '同步一次',
confirm: '确认',
msg_get_database_table_failed: '获取数据库表失败',
msg_source_database_status_is_abnormal: '源数据库状态异常',
database: '数据库',
database_type: '类型',
query_method: '查询方式',
please_choose_data_extraction_method: '请选择数据抽取方式',
table: '表',
sql_tip_1:
'该方式在获取列类型的长度或者精度时并不总是返回用户设置的精确和长度但它仍然可以作为一个参考值用于确定结果集中每列的最大显示长度',
sql_tip_2:
'如需获取更精确的列类型长度精度请使用库表方式或者在下一步中的字段映射中进行长度精度的设置',
please_enter_sql: '请输入查询SQL',
msg_confirm_delete_field: '确定删除该字段',
source_field: '源字段',
field_type: '类型',
field_length: '长度',
field_precision: '精度',
field_key: '键',
field_index: '索引',
field_comment: '注释',
confirm_delete_field: '确定删除 {0} 字段',
msg_field_list_empty_tip:
'字段列表不能为空不能存在名称为空或者字段类型为UNKNOWN的数据,请检查',
next_week: '未来一周',
next_month: '未来一个月',
next_three_month: '未来三个月',
must_be_start_less_end: '数值范围结束数值必须大于起始数值',
must_be_partition_interval_greater_than_0: '分区间隔必须大于0',
must_be_partition_interval_less_end_start_difference: '分区间隔必须小于结束数值与起始数值差值',
date: '日期',
list: '列',
number: '数值',
define_mapping_field: '定义映射字段',
target_database_type: '目标数据库类型',
delete_field: '删除字段',
add_field: '添加字段',
edit_field: '编辑字段',
add_all_field: '添加所有字段',
fault_tolerance_rate: '容错率',
fault_tolerance_rate_tip:
'01默认为0即表示同步批次数据有一条错误数据时整个批次的导入任务将会失败',
incremental_sync: '增量同步',
incremental_sync_tip_1: '全量全量覆盖同步',
incremental_sync_tip_2: '增量根据增量字段增量同步增量字段必须是整型或时间类型',
incremental_field: '增量字段',
enable_partition: '启用分区',
enable_partition_tip: '启用分区需要字段列表不能有空值',
partition_type: '分区类型',
partition_field: '分区字段',
on: '启用',
off: '关闭',
picker_to: '至',
picker_start: '开始',
picker_end: '截止',
end_offset: '结束偏移',
number_range: '数值范围',
partition_interval: '分区间隔',
partition_column_value: '分区列值',
partition_column_value_placeholder: '分区格式为:p1:"v1","v2","v3";p2:"v1","v2"',
partition_interval_unit: '分区间隔单位',
input_limit: '长度不能超过{0}个字符',
cannot_begin_with_number: '字段名称不能以数字开头',
duplicate_field_tip: '重复字段[{0}]同一个源字段不能映射多次',
duplicate_name_error: '名称重复[{0}]',
confirm_batch_delete: '确定批量删除任务',
op_success: '操作成功',
search_input_name_desc_placeholder: '搜索名称描述',
confirm_delete_msg: '确定删除',
target_table_info: '目标表信息',
confirm_clear_msg: '确定清理 {0} ?',
clear: '清理',
op_success_refresh: '执行成功,请稍后刷新',
execute_time: '执行时间',
clear_log: '清理日志',
search_input_name_id_placeholder: '搜索名称ID',
log_id: '日志ID',
op: '操作',
view_execute_log: '查看执行日志',
submit_true: '确定',
please_choose_clear_method: '请选择清理方式',
last_1_days_log: '1 天前的日志',
last_1_weeks_log: '1 周前的日志',
last_1_months_log: '1 个月前的日志',
last_3_months_log: '3 个月前的日志',
last_6_months_log: '6 个月前的日志',
last_1_years_log: '1 年前的日志',
execute_log: '执行日志',
done: '完成',
connection_lost: '连接断开',
task_name: '任务名称'
}, },
watermark: { watermark: {
support_params: '当前支持的参数', support_params: '当前支持的参数',

View File

@ -459,6 +459,10 @@ declare interface ChartTableCellAttr {
* 冻结行 * 冻结行
*/ */
tableRowFreezeHead: number tableRowFreezeHead: number
/**
* 合并单元格
*/
mergeCells: boolean
} }
/** /**

Some files were not shown because too many files have changed in this diff Show More