diff --git a/backend/src/main/java/io/dataease/commons/utils/ExcelUtils.java b/backend/src/main/java/io/dataease/commons/utils/ExcelUtils.java index 4f6fed9f0b..e03382babe 100644 --- a/backend/src/main/java/io/dataease/commons/utils/ExcelUtils.java +++ b/backend/src/main/java/io/dataease/commons/utils/ExcelUtils.java @@ -1,7 +1,9 @@ package io.dataease.commons.utils; +import java.io.BufferedOutputStream; import java.io.File; +import cn.hutool.core.io.FileUtil; import io.dataease.commons.model.excel.ExcelSheetModel; import java.util.List; @@ -9,29 +11,25 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.FillPatternType; -import org.apache.poi.ss.usermodel.Font; -import org.apache.poi.ss.usermodel.IndexedColors; + +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ExcelUtils { - private static final String suffix = ".xls"; + private static final String suffix = ".xlsx"; + private static final String BASE_ROOT = "/opt/dataease/data/"; - public static File exportExcel(List sheets, String fileName) throws Exception { + public static File exportExcel(List sheets, String fileName, String folderId) throws Exception { AtomicReference realFileName = new AtomicReference<>(fileName); - HSSFWorkbook wb = new HSSFWorkbook(); + Workbook wb = new XSSFWorkbook(); sheets.forEach(sheet -> { List> details = sheet.getData(); details.add(0, sheet.getHeads()); String sheetName = sheet.getSheetName(); - HSSFSheet curSheet = wb.createSheet(sheetName); + Sheet curSheet = wb.createSheet(sheetName); if (StringUtils.isBlank(fileName)) { String cName = sheetName + suffix; realFileName.set(cName); @@ -47,11 +45,11 @@ public class ExcelUtils { if (CollectionUtils.isNotEmpty(details)) { for (int i = 0; i < details.size(); i++) { - HSSFRow row = curSheet.createRow(i); + Row row = curSheet.createRow(i); List rowData = details.get(i); if (rowData != null) { for (int j = 0; j < rowData.size(); j++) { - HSSFCell cell = row.createCell(j); + Cell cell = row.createCell(j); cell.setCellValue(rowData.get(j)); if (i == 0) {// 头部 cell.setCellStyle(cellStyle); @@ -66,8 +64,28 @@ public class ExcelUtils { if (!StringUtils.endsWith(fileName, suffix)) { realFileName.set(realFileName.get() + suffix); } - File result = new File("/opt/dataease/data/" + realFileName.get()); - wb.write(result); + String folderPath = BASE_ROOT; + if (StringUtils.isNotBlank(folderId)) { + folderPath = BASE_ROOT + folderId + "/"; + } + + folderPath += Thread.currentThread().getId() + "/"; + + if (!FileUtil.exist(folderPath)) { + FileUtil.mkdir(folderPath); + } + File result = new File(folderPath + realFileName.get()); + BufferedOutputStream outputStream = FileUtil.getOutputStream(result); + try { + wb.write(outputStream); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + throw e; + } finally { + wb.close(); + outputStream.flush(); + outputStream.close(); + } return result; } diff --git a/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java b/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java index 8c36e7f45b..9674935d10 100644 --- a/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java +++ b/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java @@ -1,5 +1,7 @@ package io.dataease.controller.dataset; +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; import com.github.xiaoymin.knife4j.annotations.ApiSupport; import io.dataease.auth.annotation.DeLog; import io.dataease.auth.annotation.DePermission; @@ -7,10 +9,14 @@ import io.dataease.auth.annotation.DePermissions; import io.dataease.commons.constants.DePermissionType; import io.dataease.commons.constants.ResourceAuthLevel; import io.dataease.commons.constants.SysLogConstants; +import io.dataease.commons.utils.PageUtils; +import io.dataease.commons.utils.Pager; +import io.dataease.controller.ResultHolder; import io.dataease.controller.request.dataset.DataSetTableRequest; import io.dataease.controller.response.DataSetDetail; import io.dataease.dto.dataset.DataSetTableDTO; import io.dataease.dto.dataset.ExcelFileData; +import io.dataease.plugins.common.base.domain.DatasetSqlLog; import io.dataease.plugins.common.base.domain.DatasetTable; import io.dataease.plugins.common.base.domain.DatasetTableField; import io.dataease.plugins.common.base.domain.DatasetTableIncrementalConfig; @@ -152,10 +158,21 @@ public class DataSetTableController { @DePermission(type = DePermissionType.DATASET, value = "id", level = ResourceAuthLevel.DATASET_LEVEL_USE), @DePermission(type = DePermissionType.DATASOURCE, value = "dataSourceId", level = ResourceAuthLevel.DATASOURCE_LEVEL_USE) }, logical = Logical.AND) - public Map getSQLPreview(@RequestBody DataSetTableRequest dataSetTableRequest) throws Exception { + public ResultHolder getSQLPreview(@RequestBody DataSetTableRequest dataSetTableRequest) throws Exception { return dataSetTableService.getSQLPreview(dataSetTableRequest); } + @ApiOperation("根据sql查询预览数据") + @PostMapping("sqlLog/{goPage}/{pageSize}") + @DePermissions(value = { + @DePermission(type = DePermissionType.DATASET, value = "id", level = ResourceAuthLevel.DATASET_LEVEL_USE), + @DePermission(type = DePermissionType.DATASOURCE, value = "dataSourceId", level = ResourceAuthLevel.DATASOURCE_LEVEL_USE) + }, logical = Logical.AND) + public Pager> getSQLLog(@RequestBody DataSetTableRequest dataSetTableRequest, @PathVariable int goPage, @PathVariable int pageSize) throws Exception { + Page page = PageHelper.startPage(goPage, pageSize, true); + return PageUtils.setPageInfo(page, dataSetTableService.getSQLLog(dataSetTableRequest)); + } + @ApiOperation("预览自定义数据数据") @PostMapping("customPreview") public Map customPreview(@RequestBody DataSetTableRequest dataSetTableRequest) throws Exception { diff --git a/backend/src/main/java/io/dataease/controller/datasource/DatasourceController.java b/backend/src/main/java/io/dataease/controller/datasource/DatasourceController.java index 272304b63c..4de2848a3e 100644 --- a/backend/src/main/java/io/dataease/controller/datasource/DatasourceController.java +++ b/backend/src/main/java/io/dataease/controller/datasource/DatasourceController.java @@ -85,11 +85,7 @@ public class DatasourceController { @ApiOperation("查询数据源详情") @PostMapping("/get/{id}") public DatasourceDTO getDatasource(@PathVariable String id) throws Exception { - DatasourceUnionRequest request = new DatasourceUnionRequest(); - request.setUserId("1"); - request.setId(id); - List datasourceList = datasourceService.getDatasourceList(request); - return CollectionUtils.isNotEmpty(datasourceList) ? datasourceList.get(0) : null; + return datasourceService.getDataSourceDetails(id); } @ApiOperation("查询当前用户数据源") diff --git a/backend/src/main/java/io/dataease/controller/panel/PanelGroupController.java b/backend/src/main/java/io/dataease/controller/panel/PanelGroupController.java index b361b5d725..217ab70c06 100644 --- a/backend/src/main/java/io/dataease/controller/panel/PanelGroupController.java +++ b/backend/src/main/java/io/dataease/controller/panel/PanelGroupController.java @@ -190,6 +190,7 @@ public class PanelGroupController { return panelGroupService.findPanelElementInfo(viewId); } @GetMapping("/export2AppCheck/{panelId}") + @I18n public PanelExport2App export2AppCheck(@PathVariable String panelId){ return panelGroupService.panelExport2AppCheck(panelId); } diff --git a/backend/src/main/java/io/dataease/ext/ExtDataSourceMapper.java b/backend/src/main/java/io/dataease/ext/ExtDataSourceMapper.java index 21ddb7de91..d9d1b687e0 100644 --- a/backend/src/main/java/io/dataease/ext/ExtDataSourceMapper.java +++ b/backend/src/main/java/io/dataease/ext/ExtDataSourceMapper.java @@ -15,7 +15,7 @@ public interface ExtDataSourceMapper { List findByPanelId(@Param("panelId") String panelId); - + DatasourceDTO queryDetails(@Param("datasourceId") String datasourceId,@Param("userId") String userId); } diff --git a/backend/src/main/java/io/dataease/ext/ExtDataSourceMapper.xml b/backend/src/main/java/io/dataease/ext/ExtDataSourceMapper.xml index e7b7e1ca56..10ce945c85 100644 --- a/backend/src/main/java/io/dataease/ext/ExtDataSourceMapper.xml +++ b/backend/src/main/java/io/dataease/ext/ExtDataSourceMapper.xml @@ -130,5 +130,12 @@ WHERE panel_view.panel_id = #{panelId} + + diff --git a/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskHandler.java b/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskHandler.java index 965648465f..d96be6a985 100644 --- a/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskHandler.java +++ b/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskHandler.java @@ -1,5 +1,6 @@ package io.dataease.job.sechedule.strategy.impl; +import cn.hutool.core.io.FileUtil; import io.dataease.auth.entity.SysUserEntity; import io.dataease.auth.entity.TokenInfo; import io.dataease.auth.service.AuthUserService; @@ -160,6 +161,7 @@ public class EmailTaskHandler extends TaskHandler implements Job { EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class); AuthUserServiceImpl userService = SpringContextUtil.getBean(AuthUserServiceImpl.class); SysUserService sysUserService = SpringContextUtil.getBean(SysUserService.class); + List files = null; try { XpackEmailTaskRequest taskForm = emailXpackService.taskForm(taskInstance.getTaskId()); if (ObjectUtils.isEmpty(taskForm) || CronUtils.taskExpire(taskForm.getEndTime())) { @@ -199,7 +201,7 @@ public class EmailTaskHandler extends TaskHandler implements Job { contentStr = new String(content, "UTF-8"); } - List files = null; + String viewIds = emailTemplateDTO.getViewIds(); ChartViewService chartViewService = SpringContextUtil.getBean(ChartViewService.class); List viewOptions = chartViewService.viewOptions(panelId); @@ -210,7 +212,7 @@ public class EmailTaskHandler extends TaskHandler implements Job { List viewIdList = Arrays.asList(viewIds.split(",")).stream().map(s -> s.trim()).filter(viewId -> StringUtils.isNotBlank(viewId) && viewOptionIdList.contains(viewId)).collect(Collectors.toList()); PermissionProxy proxy = new PermissionProxy(); proxy.setUserId(user.getUserId()); - files = viewExportExcel.export(panelId, viewIdList, proxy, justExportView); + files = viewExportExcel.export(panelId, viewIdList, proxy, justExportView, taskInstance.getTaskId().toString()); } List channels = null; @@ -343,6 +345,14 @@ public class EmailTaskHandler extends TaskHandler implements Job { } catch (Exception e) { error(taskInstance, e); LogUtil.error(e.getMessage(), e); + } finally { + if (CollectionUtils.isNotEmpty(files)) { + files.forEach(file -> { + if (file.exists()) { + FileUtil.del(file); + } + }); + } } } diff --git a/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java b/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java index 09666aefbb..2378f8854a 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java @@ -233,7 +233,7 @@ public class XEmailTaskServer { ExcelSheetModel excelSheetModel = excelSheetModel(instanceDTOS); List sheetModels = new ArrayList<>(); sheetModels.add(excelSheetModel); - File file = ExcelUtils.exportExcel(sheetModels, null); + File file = ExcelUtils.exportExcel(sheetModels, null, null); InputStream inputStream = new FileInputStream(file); HttpServletResponse response = ServletUtils.response(); try { diff --git a/backend/src/main/java/io/dataease/provider/query/mysql/MysqlQueryProvider.java b/backend/src/main/java/io/dataease/provider/query/mysql/MysqlQueryProvider.java index 73a9837054..3b39c4f600 100644 --- a/backend/src/main/java/io/dataease/provider/query/mysql/MysqlQueryProvider.java +++ b/backend/src/main/java/io/dataease/provider/query/mysql/MysqlQueryProvider.java @@ -1312,4 +1312,8 @@ public class MysqlQueryProvider extends QueryProvider { return sql; } } + + public String sqlForPreview(String table, Datasource ds) { + return "SELECT * FROM " + String.format(MySQLConstants.KEYWORD_TABLE, table); + } } diff --git a/backend/src/main/java/io/dataease/service/chart/ViewExportExcel.java b/backend/src/main/java/io/dataease/service/chart/ViewExportExcel.java index e910178fb8..d442916cf0 100644 --- a/backend/src/main/java/io/dataease/service/chart/ViewExportExcel.java +++ b/backend/src/main/java/io/dataease/service/chart/ViewExportExcel.java @@ -40,7 +40,7 @@ public class ViewExportExcel { }.getType(); @DePermissionProxy(paramIndex = 2) - public List export(String panelId, List viewIds, PermissionProxy proxy, Boolean justView) throws Exception { + public List export(String panelId, List viewIds, PermissionProxy proxy, Boolean justView, String taskId) throws Exception { if (CollectionUtils.isEmpty(viewIds)) { return null; } @@ -51,7 +51,7 @@ public class ViewExportExcel { Map stringChartExtRequestMap = buildViewRequest(panelDto, justView); List results = new ArrayList<>(); List sheets = viewIds.stream().map(viewId -> viewFiles(viewId, stringChartExtRequestMap.get(viewId))).collect(Collectors.toList()); - File excelFile = ExcelUtils.exportExcel(sheets, panelDto.getName()); + File excelFile = ExcelUtils.exportExcel(sheets, panelDto.getName(), panelDto.getId() + "_" + taskId); results.add(excelFile); return results; } @@ -62,9 +62,12 @@ public class ViewExportExcel { List> components = gson.fromJson(componentsJson, tokenType); String panelStyle = panelDto.getPanelStyle(); Map map = gson.fromJson(panelStyle, Map.class); - Map panelMap = (LinkedTreeMap)map.get("panel"); + Map panelMap = (LinkedTreeMap) map.get("panel"); double resultCount = Double.parseDouble(panelMap.get("resultCount").toString()); - String resultMode = panelMap.get("resultMode").toString(); + String resultMode = null; + if (ObjectUtils.isNotEmpty(panelMap.get("resultMode"))) { + resultMode = panelMap.get("resultMode").toString(); + } Map result = new HashMap<>(); Map> panelFilters = justView ? FilterBuildTemplate.buildFilters(components) : FilterBuildTemplate.buildEmpty(components); @@ -73,7 +76,7 @@ public class ViewExportExcel { ChartExtRequest chartExtRequest = new ChartExtRequest(); chartExtRequest.setQueryFrom("panel"); chartExtRequest.setFilter(chartExtFilterRequests); - chartExtRequest.setResultCount((int)resultCount); + chartExtRequest.setResultCount((int) resultCount); chartExtRequest.setResultMode(resultMode); result.put(entry.getKey(), chartExtRequest); } diff --git a/backend/src/main/java/io/dataease/service/chart/build/NumberRangeBuild.java b/backend/src/main/java/io/dataease/service/chart/build/NumberRangeBuild.java index 42ea023770..abcec34ca9 100644 --- a/backend/src/main/java/io/dataease/service/chart/build/NumberRangeBuild.java +++ b/backend/src/main/java/io/dataease/service/chart/build/NumberRangeBuild.java @@ -7,8 +7,10 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @Service("numberRangeWidget") public class NumberRangeBuild extends FilterBuildTemplate { @@ -24,18 +26,22 @@ public class NumberRangeBuild extends FilterBuildTemplate { Map options = null; List values = null; - if((optionObj = component.get("options")) != null && (valueObj = (options = (Map) optionObj).get("value")) != null && CollectionUtil.isNotEmpty((values = (List) valueObj))) { + if ((optionObj = component.get("options")) != null && (valueObj = (options = (Map) optionObj).get("value")) != null) { + if (valueObj instanceof List) { + values = (List) valueObj; + } else { + return result; + } String min = values.get(0); String max = null; - if(values.size() > 1) { + if (values.size() > 1) { max = values.get(1); } result.setOperator("between"); - result.getValue().set(0, min); - result.getValue().set(1, max); if (StringUtils.isNotBlank(min) && StringUtils.isNotBlank(max)) { + result.setValue(values); return result; } diff --git a/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java b/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java index c3fe116d71..82953e556d 100644 --- a/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java +++ b/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java @@ -10,6 +10,7 @@ import io.dataease.auth.api.dto.CurrentUserDto; import io.dataease.commons.constants.*; import io.dataease.commons.exception.DEException; import io.dataease.commons.utils.*; +import io.dataease.controller.ResultHolder; import io.dataease.controller.request.dataset.DataSetGroupRequest; import io.dataease.controller.request.dataset.DataSetTableRequest; import io.dataease.controller.request.dataset.DataSetTaskRequest; @@ -131,6 +132,8 @@ public class DataSetTableService { private PermissionsTreeService permissionsTreeService; @Resource private DatasourceService datasourceService; + @Resource + private DatasetSqlLogMapper datasetSqlLogMapper; private static boolean isUpdatingDatasetTableStatus = false; private static final String lastUpdateTime = "${__last_update_time__}"; @@ -347,6 +350,7 @@ public class DataSetTableService { || StringUtils.equalsIgnoreCase(datasetTable.getType(), DatasetType.UNION.name())) { saveTableField(datasetTable); } + extractData(datasetTable); DeLogUtils.save(SysLogConstants.OPERATE_TYPE.MODIFY, SysLogConstants.SOURCE_TYPE.DATASET, datasetTable.getId(), datasetTable.getSceneId(), null, null); } } @@ -1175,9 +1179,22 @@ public class DataSetTableService { return map; } - public Map getSQLPreview(DataSetTableRequest dataSetTableRequest) throws Exception { + public List getSQLLog(DataSetTableRequest dataSetTableRequest) { + if (StringUtils.isEmpty(dataSetTableRequest.getId())) { + return new ArrayList<>(); + } + DatasetSqlLogExample example = new DatasetSqlLogExample(); + example.createCriteria().andDatasetIdEqualTo(dataSetTableRequest.getId()); + example.setOrderByClause(" start_time desc "); + return datasetSqlLogMapper.selectByExample(example); + } + + public ResultHolder getSQLPreview(DataSetTableRequest dataSetTableRequest) throws Exception { + DatasetSqlLog datasetSqlLog = new DatasetSqlLog(); + DataTableInfoDTO dataTableInfo = new Gson().fromJson(dataSetTableRequest.getInfo(), DataTableInfoDTO.class); String sql = dataTableInfo.isBase64Encryption() ? new String(java.util.Base64.getDecoder().decode(dataTableInfo.getSql())) : dataTableInfo.getSql(); + datasetSqlLog.setSql(sql); Datasource ds = datasourceMapper.selectByPrimaryKey(dataSetTableRequest.getDataSourceId()); if (ds == null) { throw new Exception(Translator.get("i18n_invalid_ds")); @@ -1202,7 +1219,25 @@ public class DataSetTableService { QueryProvider qp = ProviderFactory.getQueryProvider(ds.getType()); String sqlAsTable = qp.createSQLPreview(sql, null); datasourceRequest.setQuery(sqlAsTable); - Map result = datasourceProvider.fetchResultAndField(datasourceRequest); + + Map result = new HashMap<>(); + try { + datasetSqlLog.setStartTime(System.currentTimeMillis()); + result = datasourceProvider.fetchResultAndField(datasourceRequest); + datasetSqlLog.setEndTime(System.currentTimeMillis()); + datasetSqlLog.setSpend(datasetSqlLog.getEndTime() - datasetSqlLog.getStartTime()); + datasetSqlLog.setStatus("Completed"); + } catch (Exception e) { + datasetSqlLog.setStatus("Error"); + return ResultHolder.error(e.getMessage(), datasetSqlLog); + } finally { + if (StringUtils.isNotEmpty(dataSetTableRequest.getId())) { + datasetSqlLog.setDatasetId(dataSetTableRequest.getId()); + datasetSqlLog.setId(UUID.randomUUID().toString()); + datasetSqlLogMapper.insert(datasetSqlLog); + } + } + List data = result.get("dataList"); List fields = result.get("fieldList"); String[] fieldArray = fields.stream().map(TableField::getFieldName).toArray(String[]::new); @@ -1223,8 +1258,9 @@ public class DataSetTableService { Map map = new HashMap<>(); map.put("fields", fields); map.put("data", jsonArray); + map.put("log", datasetSqlLog); - return map; + return ResultHolder.success(map); } public Map getUnionPreview(DataSetTableRequest dataSetTableRequest) throws Exception { diff --git a/backend/src/main/java/io/dataease/service/dataset/DataSetTableTaskService.java b/backend/src/main/java/io/dataease/service/dataset/DataSetTableTaskService.java index 758f7582c6..a0b34fe714 100644 --- a/backend/src/main/java/io/dataease/service/dataset/DataSetTableTaskService.java +++ b/backend/src/main/java/io/dataease/service/dataset/DataSetTableTaskService.java @@ -84,7 +84,7 @@ public class DataSetTableTaskService { } datasetTableTaskMapper.insert(datasetTableTask); } else { - datasetTableTask.setStatus(null); + datasetTableTask.setStatus(TaskStatus.Underway.name()); datasetTableTask.setLastExecTime(null); datasetTableTask.setLastExecStatus(null); datasetTableTaskMapper.updateByPrimaryKeySelective(datasetTableTask); diff --git a/backend/src/main/java/io/dataease/service/datasource/DatasourceService.java b/backend/src/main/java/io/dataease/service/datasource/DatasourceService.java index 25a89a4933..c60c17f22a 100644 --- a/backend/src/main/java/io/dataease/service/datasource/DatasourceService.java +++ b/backend/src/main/java/io/dataease/service/datasource/DatasourceService.java @@ -152,64 +152,75 @@ public class DatasourceService { request.setSort("update_time desc"); List datasourceDTOS = extDataSourceMapper.queryUnion(request); datasourceDTOS.forEach(datasourceDTO -> { - types().forEach(dataSourceType -> { - if (dataSourceType.getType().equalsIgnoreCase(datasourceDTO.getType())) { - datasourceDTO.setTypeDesc(dataSourceType.getName()); - datasourceDTO.setCalculationMode(dataSourceType.getCalculationMode()); - } - }); - if (!datasourceDTO.getType().equalsIgnoreCase(DatasourceTypes.api.toString())) { - JdbcConfiguration configuration = new Gson().fromJson(datasourceDTO.getConfiguration(), JdbcConfiguration.class); - if (StringUtils.isNotEmpty(configuration.getCustomDriver()) && !configuration.getCustomDriver().equalsIgnoreCase("default")) { - datasourceDTO.setCalculationMode(DatasourceCalculationMode.DIRECT); - } - JSONObject jsonObject = JSONObject.parseObject(datasourceDTO.getConfiguration()); - if (jsonObject.getString("queryTimeout") == null) { - jsonObject.put("queryTimeout", 30); - datasourceDTO.setConfiguration(jsonObject.toString()); - } - } - - if (datasourceDTO.getType().equalsIgnoreCase(DatasourceTypes.mysql.toString())) { - MysqlConfiguration mysqlConfiguration = new Gson().fromJson(datasourceDTO.getConfiguration(), MysqlConfiguration.class); - datasourceDTO.setConfiguration(new Gson().toJson(mysqlConfiguration)); - } - if (datasourceDTO.getType().equalsIgnoreCase(DatasourceTypes.api.toString())) { - List apiDefinitionList = new Gson().fromJson(datasourceDTO.getConfiguration(), new TypeToken>() { - }.getType()); - List apiDefinitionListWithStatus = new ArrayList<>(); - int success = 0; - if (StringUtils.isNotEmpty(datasourceDTO.getStatus())) { - JsonObject apiItemStatuses = JsonParser.parseString(datasourceDTO.getStatus()).getAsJsonObject(); - - for (int i = 0; i < apiDefinitionList.size(); i++) { - String status = null; - if (apiItemStatuses.get(apiDefinitionList.get(i).getName()) != null) { - status = apiItemStatuses.get(apiDefinitionList.get(i).getName()).getAsString(); - } - apiDefinitionList.get(i).setStatus(status); - apiDefinitionList.get(i).setSerialNumber(i); - apiDefinitionListWithStatus.add(apiDefinitionList.get(i)); - if (StringUtils.isNotEmpty(status) && status.equalsIgnoreCase("Success")) { - success++; - } - } - } - datasourceDTO.setApiConfiguration(apiDefinitionListWithStatus); - if (success == apiDefinitionList.size()) { - datasourceDTO.setStatus("Success"); - } else { - if (success > 0 && success < apiDefinitionList.size()) { - datasourceDTO.setStatus("Warning"); - } else { - datasourceDTO.setStatus("Error"); - } - } - } + datasourceTrans(datasourceDTO); }); return datasourceDTOS; } + private void datasourceTrans(DatasourceDTO datasourceDTO){ + types().forEach(dataSourceType -> { + if (dataSourceType.getType().equalsIgnoreCase(datasourceDTO.getType())) { + datasourceDTO.setTypeDesc(dataSourceType.getName()); + datasourceDTO.setCalculationMode(dataSourceType.getCalculationMode()); + } + }); + if (!datasourceDTO.getType().equalsIgnoreCase(DatasourceTypes.api.toString())) { + JdbcConfiguration configuration = new Gson().fromJson(datasourceDTO.getConfiguration(), JdbcConfiguration.class); + if (StringUtils.isNotEmpty(configuration.getCustomDriver()) && !configuration.getCustomDriver().equalsIgnoreCase("default")) { + datasourceDTO.setCalculationMode(DatasourceCalculationMode.DIRECT); + } + JSONObject jsonObject = JSONObject.parseObject(datasourceDTO.getConfiguration()); + if (jsonObject.getString("queryTimeout") == null) { + jsonObject.put("queryTimeout", 30); + datasourceDTO.setConfiguration(jsonObject.toString()); + } + } + + if (datasourceDTO.getType().equalsIgnoreCase(DatasourceTypes.mysql.toString())) { + MysqlConfiguration mysqlConfiguration = new Gson().fromJson(datasourceDTO.getConfiguration(), MysqlConfiguration.class); + datasourceDTO.setConfiguration(new Gson().toJson(mysqlConfiguration)); + } + if (datasourceDTO.getType().equalsIgnoreCase(DatasourceTypes.api.toString())) { + List apiDefinitionList = new Gson().fromJson(datasourceDTO.getConfiguration(), new TypeToken>() { + }.getType()); + List apiDefinitionListWithStatus = new ArrayList<>(); + int success = 0; + if (StringUtils.isNotEmpty(datasourceDTO.getStatus())) { + JsonObject apiItemStatuses = JsonParser.parseString(datasourceDTO.getStatus()).getAsJsonObject(); + + for (int i = 0; i < apiDefinitionList.size(); i++) { + String status = null; + if (apiItemStatuses.get(apiDefinitionList.get(i).getName()) != null) { + status = apiItemStatuses.get(apiDefinitionList.get(i).getName()).getAsString(); + } + apiDefinitionList.get(i).setStatus(status); + apiDefinitionList.get(i).setSerialNumber(i); + apiDefinitionListWithStatus.add(apiDefinitionList.get(i)); + if (StringUtils.isNotEmpty(status) && status.equalsIgnoreCase("Success")) { + success++; + } + } + } + datasourceDTO.setApiConfiguration(apiDefinitionListWithStatus); + if (success == apiDefinitionList.size()) { + datasourceDTO.setStatus("Success"); + } else { + if (success > 0 && success < apiDefinitionList.size()) { + datasourceDTO.setStatus("Warning"); + } else { + datasourceDTO.setStatus("Error"); + } + } + } + } + + public DatasourceDTO getDataSourceDetails(String datasourceId){ + DatasourceDTO result = extDataSourceMapper.queryDetails(datasourceId,String.valueOf(AuthUtils.getUser().getUserId())); + if(result != null){ + this.datasourceTrans(result); + } + return result; + } public List gridQuery(BaseGridRequest request) { //如果没有查询条件增加一个默认的条件 if (CollectionUtils.isEmpty(request.getConditions())) { diff --git a/backend/src/main/java/io/dataease/service/message/SysMsgService.java b/backend/src/main/java/io/dataease/service/message/SysMsgService.java index 3621bf8d66..721a466c5b 100644 --- a/backend/src/main/java/io/dataease/service/message/SysMsgService.java +++ b/backend/src/main/java/io/dataease/service/message/SysMsgService.java @@ -1,5 +1,6 @@ package io.dataease.service.message; +import io.dataease.commons.utils.LogUtil; import io.dataease.ext.ExtSysMsgMapper; import io.dataease.commons.constants.SysMsgConstants; import io.dataease.commons.utils.AuthUtils; @@ -25,6 +26,7 @@ import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; + import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; @@ -65,7 +67,7 @@ public class SysMsgService { orderClause = String.join(", ", orders); } - if (CollectionUtils.isNotEmpty(typeIds)){ + if (CollectionUtils.isNotEmpty(typeIds)) { criteria.andTypeIdIn(typeIds); } @@ -120,7 +122,7 @@ public class SysMsgService { return sysMsgTypeMapper.selectByExample(example); } - private List buildTree(List lists){ + private List buildTree(List lists) { List rootNodes = new ArrayList<>(); lists.forEach(node -> { SettingTreeNode settingTreeNode = convert(node); @@ -183,6 +185,7 @@ public class SysMsgService { /** * 修改了订阅信息 需要清除缓存 + * * @param request * @param userId */ @@ -241,22 +244,29 @@ public class SysMsgService { List subscribes = subscribes(userId); if (CollectionUtils.isNotEmpty(subscribes)) { - subscribes.stream().filter(item -> item.getTypeId().equals(typeId)).forEach(sub -> { - SendService sendService = serviceByChannel(sub.getChannelId()); - sendService.sendMsg(userId, typeId, content, param); - }); - + for (int i = 0; i < subscribes.size(); i++) { + SubscribeNode item = subscribes.get(i); + if (item.getTypeId().equals(typeId)) { + try { + SendService sendService = serviceByChannel(item.getChannelId()); + sendService.sendMsg(userId, typeId, content, param); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + } + } + } } } - private SendService serviceByChannel(Long channelId){ + private SendService serviceByChannel(Long channelId) { String beanName = sysMsgChannelMapper.selectByPrimaryKey(channelId).getServiceName(); - return (SendService)CommonBeanFactory.getBean(beanName); + return (SendService) CommonBeanFactory.getBean(beanName); } /** * 查询用户订阅的消息 并缓存 + * * @param userId * @return */ @@ -280,7 +290,7 @@ public class SysMsgService { List defaultSettings = defaultSettings(); defaultSettings.forEach(setting -> { - if (!sourceLists.stream().anyMatch(item -> item.match(setting))){ + if (!sourceLists.stream().anyMatch(item -> item.match(setting))) { sourceLists.add(setting); } }); @@ -297,7 +307,7 @@ public class SysMsgService { public Long overTime() { String msgTimeOut = systemParameterService.basicInfo().getMsgTimeOut(); - if(StringUtils.isNotBlank(msgTimeOut)) { + if (StringUtils.isNotBlank(msgTimeOut)) { overDays = Integer.parseInt(msgTimeOut); } Long currentTime = System.currentTimeMillis(); @@ -307,9 +317,8 @@ public class SysMsgService { long temp = overDays * oneDayTime; return currentTime - (currentTime + 8 * 60 * 60 * 1000) % oneDayTime - temp; - + } - } diff --git a/backend/src/main/java/io/dataease/service/panel/PanelAppTemplateService.java b/backend/src/main/java/io/dataease/service/panel/PanelAppTemplateService.java index db1c7dbb46..8b97b489f6 100644 --- a/backend/src/main/java/io/dataease/service/panel/PanelAppTemplateService.java +++ b/backend/src/main/java/io/dataease/service/panel/PanelAppTemplateService.java @@ -182,6 +182,7 @@ public class PanelAppTemplateService { for (DatasetTableField datasetTableField : datasetTableFieldsInfo) { String oldId = datasetTableField.getId(); datasetTableField.setTableId(datasetsRealMap.get(datasetTableField.getTableId())); + datasetTableField.setId(null); DatasetTableField newTableField = dataSetTableFieldsService.save(datasetTableField); datasetFieldsRealMap.put(oldId, newTableField.getId()); } diff --git a/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java b/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java index cb9af63d96..4e44e60753 100644 --- a/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java +++ b/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java @@ -806,23 +806,23 @@ public class PanelGroupService { //校验标准 1.存在视图且所有视图的数据来源必须是dataset 2.存在数据集且没有excel数据集 3.存在数据源且是单数据源 //1.view check if (CollectionUtils.isEmpty(chartViewsInfo)) { - return new PanelExport2App("this panel don't have views"); + return new PanelExport2App(Translator.get("I18N_APP_NO_VIEW_ERROR")); } else if (chartViewsInfo.stream().filter(chartView -> chartView.getDataFrom().equals("template")).collect(Collectors.toList()).size() > 0) { - return new PanelExport2App("this panel have view from template"); + return new PanelExport2App(Translator.get("I18N_APP_TEMPLATE_VIEW_ERROR")); } // dataset check if (CollectionUtils.isEmpty(datasetTablesInfo)) { - return new PanelExport2App("this panel don't have dataset"); - } else if (datasetTablesInfo.stream().filter(datasetTable -> datasetTable.getType().equals("excel")).collect(Collectors.toList()).size() > 0) { - return new PanelExport2App("this panel have dataset witch type is excel"); + return new PanelExport2App(Translator.get("I18N_APP_NO_DATASET_ERROR")); + } else if (datasetTablesInfo.stream().filter(datasetTable -> datasetTable.getType().equals("excel") || datasetTable.getType().equals("api")).collect(Collectors.toList()).size() > 0) { + return new PanelExport2App(Translator.get("I18N_APP_ERROR_DATASET")); } //datasource check if (CollectionUtils.isEmpty(datasourceDTOS)) { - return new PanelExport2App("this panel don't have datasource"); + return new PanelExport2App(Translator.get("I18N_APP_NO_DATASOURCE")); } else if (datasourceDTOS.size() > 1) { - return new PanelExport2App("this panel should have only one dataset"); + return new PanelExport2App(Translator.get("I18N_APP_ONE_DATASOURCE_TIPS")); } return new PanelExport2App(chartViewsInfo, chartViewFieldsInfo, datasetTablesInfo, datasetTableFieldsInfo, dataSetTasksInfo, datasourceDTOS,panelViews); } diff --git a/backend/src/main/resources/db/migration/V10__web_msg.sql b/backend/src/main/resources/db/migration/V10__web_msg.sql index c172c80854..9819b93602 100644 --- a/backend/src/main/resources/db/migration/V10__web_msg.sql +++ b/backend/src/main/resources/db/migration/V10__web_msg.sql @@ -55,7 +55,7 @@ INSERT INTO `sys_msg_type` VALUES (2, 1, 'i18n_msg_type_panel_share', 'panel', ' INSERT INTO `sys_msg_type` VALUES (3, 1, 'i18n_msg_type_panel_share_cacnel', 'panel', 'to-msg-share'); INSERT INTO `sys_msg_type` VALUES (4, 0, 'i18n_msg_type_dataset_sync', 'sys-task-dataset', 'to-msg-dataset'); INSERT INTO `sys_msg_type` VALUES (5, 4, 'i18n_msg_type_dataset_sync_success', 'sys-task-dataset', 'to-msg-dataset'); -INSERT INTO `sys_msg_type` VALUES (6, 4, 'i18n_msg_type_dataset_sync_faild', 'sys-task-dataset', 'to-msg-dataset'); +INSERT INTO `sys_msg_type` VALUES (6, 4, 'i18n_msg_type_dataset_sync_failed', 'sys-task-dataset', 'to-msg-dataset'); COMMIT; -- ---------------------------- @@ -74,7 +74,7 @@ BEGIN; INSERT INTO `sys_menu` VALUES (53, 1, 3, 1, '站内消息', 'sys-msg-web', 'msg/index', 1000, 'all-msg', 'system-msg-web', b'0', b'0', b'0', NULL, NULL, NULL, NULL, NULL); INSERT INTO `sys_menu` VALUES (54, 53, 0, 1, '所有消息', 'sys-msg-web-all', 'msg/all', 1, 'web-msg', 'all', b'0', b'0', b'0', NULL, NULL, NULL, NULL, NULL); INSERT INTO `sys_menu` VALUES (55, 53, 0, 1, '未读消息', 'sys-msg-web-unread', 'msg/unread', 2, 'unread-msg', 'unread', b'0', b'0', b'0', NULL, NULL, NULL, NULL, NULL); -INSERT INTO `sys_menu` VALUES (56, 53, 0, 1, '已读消息', 'sys-msg-web-readed', 'msg/readed', 3, 'readed-msg', 'readed', b'0', b'0', b'0', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sys_menu` VALUES (56, 53, 0, 1, '已读消息', 'sys-msg-web-read', 'msg/read', 3, 'read-msg', 'read', b'0', b'0', b'0', NULL, NULL, NULL, NULL, NULL); INSERT INTO `sys_menu` VALUES (59, 53, 0, 1, '接收管理', 'sys-msg-setting', 'msg/setting', 4, 'msg-setting', 'setting', b'0', b'0', b'0', NULL, NULL, NULL, NULL, NULL); COMMIT; diff --git a/backend/src/main/resources/db/migration/V42__1.16.sql b/backend/src/main/resources/db/migration/V42__1.16.sql index a44a6a190f..06804d06f3 100644 --- a/backend/src/main/resources/db/migration/V42__1.16.sql +++ b/backend/src/main/resources/db/migration/V42__1.16.sql @@ -54,6 +54,17 @@ VALUES ('Apache Kylin 数据源插件', 'default', '0', '0', 'datasource', 'Apac INSERT INTO `sys_msg_channel` (`msg_channel_id`, `channel_name`, `service_name`) VALUES ('6', 'webmsg.channel_larksuite_msg', 'sendLarksuite'); +CREATE TABLE `dataset_sql_log` ( + `id` varchar(50) NOT NULL DEFAULT '' COMMENT 'ID', + `dataset_id` varchar(50) NOT NULL DEFAULT '' COMMENT '数据集ID', + `start_time` bigint(13) DEFAULT NULL COMMENT '开始时间', + `end_time` bigint(13) DEFAULT NULL COMMENT '结束时间', + `spend` bigint(13) DEFAULT NULL COMMENT '耗时(毫秒)', + `sql` longtext NOT NULL COMMENT '详细信息', + `status` varchar(45) DEFAULT NULL COMMENT '状态', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci; + INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (204, 203, 0, 2, '删除记录', NULL, NULL, 999, NULL, NULL, 0, 0, 0, 'appLog:del', NULL, NULL, 1614930903502, 1614930903502); INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (205, 203, 0, 2, '编辑记录', NULL, NULL, 999, NULL, NULL, 0, 0, 0, 'appLog:edit', NULL, NULL, 1614930935529, 1614930935529); @@ -270,3 +281,7 @@ RETURN 'success'; END ;; delimiter ; + +UPDATE `panel_subject` +SET `details` = '{\"width\":1600,\"height\":900,\"scale\":100,\"scaleWidth\":100,\"scaleHeight\":100,\"selfAdaption\":true,\"auxiliaryMatrix\":true,\"openCommonStyle\":true,\"panel\":{\"themeColor\":\"dark\",\"color\":\"#030B2E\",\"imageUrl\":{},\"backgroundType\":\"color\",\"gap\":\"yes\",\"resultMode\":\"all\",\"resultCount\":1000},\"aidedDesign\":{\"showGrid\":false,\"matrixBase\":4},\"refreshViewLoading\":true,\"refreshUnit\":\"minute\",\"refreshTime\":5,\"themeId\":\"f9f46a50-58f5-11ed-889b-91ab7371e877\",\"chartInfo\":{\"chartTitle\":{\"show\":true,\"fontSize\":\"18\",\"color\":\"#FFFFFF\",\"hPosition\":\"left\",\"vPosition\":\"top\",\"isItalic\":false,\"isBolder\":true,\"remarkShow\":false,\"remark\":\"\",\"remarkBackgroundColor\":\"#5A5C62\",\"fontFamily\":\"Microsoft YaHei\",\"letterSpace\":\"0\",\"fontShadow\":false},\"chartColor\":{\"value\":\"default\",\"colors\":[\"#5470c6\",\"#91cc75\",\"#fac858\",\"#ee6666\",\"#73c0de\",\"#3ba272\",\"#fc8452\",\"#9a60b4\",\"#ea7ccc\"],\"alpha\":100,\"tableHeaderBgColor\":\"#5470C6\",\"tableItemBgColor\":\"#131E42\",\"tableFontColor\":\"#ffffff\",\"tableStripe\":true,\"dimensionColor\":\"#ffffff\",\"quotaColor\":\"#5470C6\",\"tableBorderColor\":\"#CCCCCC\",\"seriesColors\":[],\"areaBorderColor\":\"#EBEEF5\",\"tableHeaderFontColor\":\"#ffffff\",\"modifyName\":\"colors\"},\"chartCommonStyle\":{\"backgroundColorSelect\":true,\"color\":\"#131E42\",\"alpha\":100,\"borderRadius\":5,\"innerPadding\":0},\"filterStyle\":{\"horizontal\":\"left\",\"vertical\":\"top\",\"color\":\"#FFFFFF\",\"brColor\":\"#4E4B4B\",\"wordColor\":\"#FFFFFF\",\"innerBgColor\":\"#131E42\"},\"tabStyle\":{\"headFontColor\":\"#FFFFFF\",\"headFontActiveColor\":\"#FFFFFF\",\"headBorderColor\":\"#FFFFFF\",\"headBorderActiveColor\":\"#FFFFFF\",\"headPosition\":\"left\"}}}' +WHERE `id` = 'system_2'; diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index df1effdcd3..dfe388f61f 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -240,3 +240,10 @@ I18N_PANEL_EXIST=The current panel name already exists under this directory I18N_DATASET_GROUP_EXIST=The current dataset grouping name already exists under this directory I18N_NOT_JAR=File is not jar! +I18N_APP_NO_VIEW_ERROR=This panel don't have views +I18N_APP_TEMPLATE_VIEW_ERROR=This panel have view from template +I18N_APP_NO_DATASET_ERROR=This panel don't have dataset +I18N_APP_ERROR_DATASET=This panel have dataset witch type is excel or api +I18N_APP_NO_DATASOURCE=This panel don't have datasource +I18N_APP_ONE_DATASOURCE_TIPS=This panel should have only one datasource + diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties index a0972f0da7..c3724a160f 100644 --- a/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -194,7 +194,7 @@ I18N_DATASOURCE_LEVEL_GRANT=\u6388\u6743 I18N_NO_PERMISSION=\u5F53\u524D\u7528\u6237\u6CA1\u6709\u6743\u9650 I18N_PLEASE_CONCAT_ADMIN=\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u5F00\u901A I18N_SQL_variable_limit=SQL \u53D8\u91CF\u53EA\u80FD\u5728 WHERE \u6761\u4EF6\u4E2D\u4F7F\u7528 -I18N_SQL_variable_direct_limit=SQL变量只能用于直连 +I18N_SQL_variable_direct_limit=SQL\u53D8\u91CF\u53EA\u80FD\u7528\u4E8E\u76F4\u8FDE I18N_EMAIL_CONFIG_ERROR=\u90AE\u4EF6\u914D\u7F6E\u9519\u8BEF I18N_EMAIL_HOST_ERROR=\u90AE\u4EF6\u4E3B\u673A\u4E0D\u80FD\u4E3A\u7A7A I18N_EMAIL_PORT_ERROR=\u90AE\u4EF6\u7AEF\u53E3\u4E0D\u80FD\u4E3A\u7A7A @@ -238,5 +238,11 @@ I18N_ACCOUNT_LOCKED=\u8D26\u53F7\u3010%s\u3011\u5DF2\u9501\u5B9A(\u8BF7\u8054\u7 I18N_PANEL_EXIST=\u5F53\u524D\u4EEA\u8868\u677F\u540D\u79F0\u5728\u8BE5\u76EE\u5F55\u4E0B\u9762\u5DF2\u7ECF\u5B58\u5728 I18N_DATASET_GROUP_EXIST=\u5F53\u524D\u6570\u636E\u96C6\u5206\u7EC4\u540D\u79F0\u5728\u8BE5\u76EE\u5F55\u4E0B\u9762\u5DF2\u7ECF\u5B58\u5728 -I18N_NOT_JAR=文件不是 jar 包! +I18N_NOT_JAR=\u6587\u4EF6\u4E0D\u662F jar \u5305! +I18N_APP_NO_VIEW_ERROR=\u8BE5\u4EEA\u8868\u677F\u6CA1\u6709\u89C6\u56FE +I18N_APP_TEMPLATE_VIEW_ERROR=\u8BE5\u4EEA\u8868\u677F\u5B58\u5728\u6A21\u677F\u4E2D\u7684\u89C6\u56FE +I18N_APP_NO_DATASET_ERROR=\u8BE5\u4EEA\u8868\u7248\u6CA1\u6709\u6570\u636E\u96C6 +I18N_APP_ERROR_DATASET=\u4EEA\u8868\u677F\u4E2D\u4E0D\u80FD\u5B58\u5728API\u6570\u636E\u6E90\u6216\u8005Excel\u6570\u636E\u96C6 +I18N_APP_NO_DATASOURCE=\u6CA1\u6709\u627E\u5230\u6570\u636E\u6E90 +I18N_APP_ONE_DATASOURCE_TIPS=\u8BE5\u4EEA\u8868\u677F\u53EA\u80FD\u5B58\u5728\u4E00\u4E2A\u6570\u636E\u6E90 diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index fb269a8bda..93400397eb 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -190,7 +190,7 @@ I18N_DATASOURCE_LEVEL_GRANT=\u6388\u6B0A I18N_NO_PERMISSION=\u7576\u524D\u7528\u6236\u6C92\u6709\u6B0A\u9650 I18N_PLEASE_CONCAT_ADMIN=\u8ACB\u806F\u7CFB\u7BA1\u7406\u54E1\u958B\u901A I18N_SQL_variable_limit=SQL\u8B8A\u6578\u53EA\u80FD\u5728WHERE\u689D\u4EF6\u4E2D\u4F7F\u7528 -I18N_SQL_variable_direct_limit=SQL變數只能用於直連 +I18N_SQL_variable_direct_limit=SQL\u8B8A\u6578\u53EA\u80FD\u7528\u65BC\u76F4\u9023 I18N_EMAIL_CONFIG_ERROR=\u90F5\u4EF6\u914D\u7F6E\u932F\u8AA4 I18N_EMAIL_HOST_ERROR=\u90F5\u4EF6\u4E3B\u6A5F\u4E0D\u80FD\u70BA\u7A7A I18N_EMAIL_PORT_ERROR=\u90F5\u4EF6\u7AEF\u53E3\u4E0D\u80FD\u70BA\u7A7A @@ -234,4 +234,10 @@ I18N_ACCOUNT_LOCKED=\u8CEC\u865F\u3010%s\u3011\u5DF2\u9396\u5B9A(\u8ACB\u806F\u7 I18N_PANEL_EXIST=\u7576\u524D\u5100\u9336\u95C6\u540D\u7A31\u5728\u8A72\u76EE\u9304\u4E0B\u9762\u5DF2\u7D93\u5B58\u5728 I18N_DATASET_GROUP_EXIST=\u7576\u524D\u6578\u64DA\u96C6\u5206\u7D44\u540D\u7A31\u5728\u8A72\u76EE\u9304\u4E0B\u9762\u5DF2\u7D93\u5B58\u5728 -I18N_NOT_JAR=文件不是 jar 包! +I18N_NOT_JAR=\u6587\u4EF6\u4E0D\u662F jar \u5305! +I18N_APP_NO_VIEW_ERROR=\u8A72\u5100\u8868\u677F\u6C92\u6709\u8996\u5716 +I18N_APP_TEMPLATE_VIEW_ERROR=\u8A72\u5100\u8868\u677F\u5B58\u5728\u6A21\u677F\u4E2D\u7684\u8996\u5716 +I18N_APP_NO_DATASET_ERROR=\u8A72\u5100\u8868\u7248\u6C92\u6709\u6578\u64DA\u96C6 +I18N_APP_ERROR_DATASET=\u5100\u8868\u677F\u4E2D\u4E0D\u80FD\u5B58\u5728API\u6578\u64DA\u6E90\u6216\u8005Excel\u6578\u64DA\u96C6 +I18N_APP_NO_DATASOURCE=\u6C92\u6709\u627E\u5230\u6578\u64DA\u6E90 +I18N_APP_ONE_DATASOURCE_TIPS=\u8A72\u5100\u8868\u677F\u53EA\u80FD\u5B58\u5728\u4E00\u500B\u6578\u64DA\u6E90 diff --git a/frontend/package.json b/frontend/package.json index f2fc11ddf0..878dfb942d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -45,6 +45,7 @@ "js-cookie": "2.2.0", "jsencrypt": "^3.0.0-rc.1", "jspdf": "^2.3.1", + "jszip": "^3.10.1", "lodash": "^4.17.21", "lodash.isboolean": "^3.0.3", "lodash.isempty": "^4.4.0", diff --git a/frontend/src/api/panel/panel.js b/frontend/src/api/panel/panel.js index f892134606..5b9be4774f 100644 --- a/frontend/src/api/panel/panel.js +++ b/frontend/src/api/panel/panel.js @@ -313,7 +313,7 @@ export function appApply(data) { return request({ url: 'panel/group/appApply', method: 'post', - loading: false, + loading: true, data }) } @@ -322,7 +322,7 @@ export function appEdit(data) { return request({ url: 'panel/group/appEdit', method: 'post', - loading: false, + loading: true, data }) } diff --git a/frontend/src/components/DeDrag/index.vue b/frontend/src/components/DeDrag/index.vue index 2d38230a34..e6c4b96bc9 100644 --- a/frontend/src/components/DeDrag/index.vue +++ b/frontend/src/components/DeDrag/index.vue @@ -12,6 +12,7 @@ [classNameActive]: enabled , ['linkageSetting']:linkageActive, ['batchSetting']:batchOptActive, + ['drag-on-tab-collision']:dragCollision, ['positionChange']:!(dragging || resizing||rotating) }, className @@ -433,6 +434,9 @@ export default { } }, computed: { + dragCollision() { + return this.dragging && Boolean(this.tabCollisionActiveId) + }, parentWidthOffset() { if (this.canvasId === 'canvas-main') { return 0 @@ -2114,4 +2118,8 @@ export default { width: 100%; height: 100%; } + +.drag-on-tab-collision { + z-index: 1000!important; +} diff --git a/frontend/src/components/GradientColorSelector/index.vue b/frontend/src/components/GradientColorSelector/index.vue index 8bffc71dab..1dcec6bf38 100644 --- a/frontend/src/components/GradientColorSelector/index.vue +++ b/frontend/src/components/GradientColorSelector/index.vue @@ -106,6 +106,7 @@ @@ -423,4 +424,7 @@ export default { width: 20px; height: 20px; } +.gradient-picker-dropdown .el-color-dropdown__link-btn { + display: none; +} diff --git a/frontend/src/components/canvas/components/Editor/SettingMenu.vue b/frontend/src/components/canvas/components/Editor/SettingMenu.vue index 8c0b7cdf1e..2f34abf834 100644 --- a/frontend/src/components/canvas/components/Editor/SettingMenu.vue +++ b/frontend/src/components/canvas/components/Editor/SettingMenu.vue @@ -11,16 +11,25 @@ v-if="editFilter.includes(curComponent.type)" icon="el-icon-edit-outline" @click.native="edit" - >{{ $t('panel.edit') }} + >{{ $t('panel.edit') }} + {{ $t('panel.copy') }} + >{{ $t('panel.copy') }} + {{ $t('panel.delete') }} + >{{ $t('panel.delete') }} + + {{ $t('chart.sort') }} + @@ -30,19 +39,23 @@ {{ $t('panel.topComponent') }} + >{{ $t('panel.topComponent') }} + {{ $t('panel.bottomComponent') }} + >{{ $t('panel.bottomComponent') }} + {{ $t('panel.upComponent') }} + >{{ $t('panel.upComponent') }} + {{ $t('panel.downComponent') }} + >{{ $t('panel.downComponent') }} + @@ -50,22 +63,26 @@ v-if="linkageSettingShow" icon="el-icon-link" @click.native="linkageSetting" - >{{ $t('panel.linkage_setting') }} + >{{ $t('panel.linkage_setting') }} + {{ $t('panel.add_tab') }} + >{{ $t('panel.add_tab') }} + {{ $t('panel.setting_jump') }} + >{{ $t('panel.setting_jump') }} + {{ $t('panel.component_style') }} + >{{ $t('panel.component_style') }} + + + + + + @@ -100,11 +149,13 @@ import { mapState } from 'vuex' import bus from '@/utils/bus' import { getViewLinkageGather } from '@/api/panel/linkage' import HyperlinksDialog from '@/components/canvas/components/Editor/HyperlinksDialog' +import CustomTabsSort from '@/components/widget/DeWidget/CustomTabsSort' export default { - components: { HyperlinksDialog }, + components: { CustomTabsSort, HyperlinksDialog }, data() { return { + showCustomSort: false, jumpExcludeViewType: [ 'richTextView', 'liquid', @@ -150,6 +201,18 @@ export default { ]) }, methods: { + openCustomSort() { + this.showCustomSort = true + }, + closeCustomSort() { + this.showCustomSort = false + }, + saveCustomSort() { + this.$refs.customTabsSort.save() + this.$nextTick(() => { + this.showCustomSort = false + }) + }, edit() { if (this.curComponent.type === 'custom') { bus.$emit('component-dialog-edit', 'update') @@ -157,7 +220,9 @@ export default { bus.$emit('button-dialog-edit') } else if (this.curComponent.type === 'v-text' || this.curComponent.type === 'de-rich-text' || this.curComponent.type === 'rect-shape') { bus.$emit('component-dialog-style') - } else { bus.$emit('change_panel_right_draw', true) } + } else { + bus.$emit('change_panel_right_draw', true) + } }, lock() { this.$store.commit('lock') @@ -266,36 +331,36 @@ export default { diff --git a/frontend/src/components/canvas/components/TextAttr.vue b/frontend/src/components/canvas/components/TextAttr.vue index 20a9bacfa8..c9412d7710 100644 --- a/frontend/src/components/canvas/components/TextAttr.vue +++ b/frontend/src/components/canvas/components/TextAttr.vue @@ -414,9 +414,10 @@ import StreamMediaLinks from '@/components/canvas/components/Editor/StreamMediaL import DateFormat from '@/components/canvas/components/Editor/DateFormat' import { COLOR_PANEL } from '@/views/chart/chart/chart' import FrameLinks from '@/components/canvas/components/Editor/FrameLinks' +import TitlePosition from '@/components/widget/DeWidget/TitlePosition' export default { - components: { FrameLinks, DateFormat, VideoLinks, StreamMediaLinks }, + components: { TitlePosition, FrameLinks, DateFormat, VideoLinks, StreamMediaLinks }, props: { canvasId: { type: String, @@ -517,6 +518,7 @@ export default { ], // tab组件显示的属性 'de-tabs': [ + 'fontSize', 'borderStyle', 'borderWidth', 'borderColor', @@ -717,39 +719,42 @@ export default { diff --git a/frontend/src/components/canvas/custom-component/component-list.js b/frontend/src/components/canvas/custom-component/component-list.js index 844f31a2a7..0c79e78f02 100644 --- a/frontend/src/components/canvas/custom-component/component-list.js +++ b/frontend/src/components/canvas/custom-component/component-list.js @@ -388,7 +388,8 @@ const list = [ height: 200, borderStyle: 'solid', borderWidth: 0, - borderColor: '#000000' + borderColor: '#000000', + fontSize: 16 }, options: { tabList: [{ diff --git a/frontend/src/components/canvas/utils/style.js b/frontend/src/components/canvas/utils/style.js index 0cfe1137af..98a1cfbfcf 100644 --- a/frontend/src/components/canvas/utils/style.js +++ b/frontend/src/components/canvas/utils/style.js @@ -8,7 +8,7 @@ export const LIGHT_THEME_PANEL_BACKGROUND = '#F1F3F5' export const LIGHT_THEME_COMPONENT_BACKGROUND = '#FFFFFF' export const DARK_THEME_COLOR_MAIN = '#FFFFFF' -export const DARK_THEME_COLOR_SLAVE1 = '#CCCCCC' +export const DARK_THEME_COLOR_SLAVE1 = '#858383' export const DARK_THEME_PANEL_BACKGROUND = '#030B2E' export const DARK_THEME_COMPONENT_BACKGROUND = '#131E42' export const DARK_THEME_COMPONENT_BACKGROUND_BACK = '#5a5c62' @@ -361,7 +361,7 @@ export function adaptCurTheme(customStyle, customAttr, chartType) { } } customAttr['color'] = { ...canvasStyle.chartInfo.chartColor } - customStyle['text'] = { ...canvasStyle.chartInfo.chartTitle, title: customStyle['text']['title'], show: customStyle['text']['show'] } + customStyle['text'] = { ...canvasStyle.chartInfo.chartTitle, title: customStyle['text']['title'], show: customStyle['text']['show'], remarkShow: customStyle['text']['remarkShow'], remark: customStyle['text']['remark'] } if (customStyle.background) { delete customStyle.background } diff --git a/frontend/src/components/canvas/utils/utils.js b/frontend/src/components/canvas/utils/utils.js index d3ab9c2e14..3edae4b655 100644 --- a/frontend/src/components/canvas/utils/utils.js +++ b/frontend/src/components/canvas/utils/utils.js @@ -99,6 +99,9 @@ export function panelDataPrepare(componentData, componentStyle, callback) { item.options.attrs.accuracy = 'HH:mm' } } + if (item.type === 'de-tabs') { + item.style.fontSize = item.style.fontSize || 16 + } if (item.type === 'custom') { item.options.manualModify = false } diff --git a/frontend/src/components/widget/DeWidget/CustomTabsSort.vue b/frontend/src/components/widget/DeWidget/CustomTabsSort.vue new file mode 100644 index 0000000000..479501d77f --- /dev/null +++ b/frontend/src/components/widget/DeWidget/CustomTabsSort.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/frontend/src/components/widget/DeWidget/DeSelectGrid.vue b/frontend/src/components/widget/DeWidget/DeSelectGrid.vue index 75e7758c6f..1cebdb8346 100644 --- a/frontend/src/components/widget/DeWidget/DeSelectGrid.vue +++ b/frontend/src/components/widget/DeWidget/DeSelectGrid.vue @@ -24,18 +24,19 @@ v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange" - > - {{ $t('commons.all') }} + />{{ $t('commons.all') }} - {{ item.id }} + @@ -407,13 +408,11 @@ export default { .checkbox-group-container { label.el-checkbox { - display: block !important; - margin: 10px !important; + margin: 10px 10px 0 10px !important; } .el-checkbox-group>label { - display: block !important; - margin: 10px !important; + margin: 10px 10px 0 10px !important; } } diff --git a/frontend/src/components/widget/DeWidget/DeTabs.vue b/frontend/src/components/widget/DeWidget/DeTabs.vue index b97cd577fd..d9526cad50 100644 --- a/frontend/src/components/widget/DeWidget/DeTabs.vue +++ b/frontend/src/components/widget/DeWidget/DeTabs.vue @@ -1,6 +1,8 @@ @@ -167,7 +170,8 @@ export default { borderRadius: '0px', mapCenter: null, linkageActiveParam: null, - buttonTextColor: null + buttonTextColor: null, + loading: true } }, @@ -222,6 +226,7 @@ export default { } }, preDraw() { + this.loading = true // 基于准备好的dom,初始化echarts实例 // 渲染echart等待dom加载完毕,渲染之前先尝试销毁具有相同id的echart 放置多次切换仪表板有重复id情况 const that = this @@ -253,6 +258,10 @@ export default { that.$refs.viewTrack.trackButtonClick() } }) + this.myChart.off('finished') + this.myChart.on('finished', () => { + this.loading = false + }) }) }, loadThemeStyle() { diff --git a/frontend/src/views/chart/components/ChartComponentG2.vue b/frontend/src/views/chart/components/ChartComponentG2.vue index c55b9c80fe..fe9cca5dfa 100644 --- a/frontend/src/views/chart/components/ChartComponentG2.vue +++ b/frontend/src/views/chart/components/ChartComponentG2.vue @@ -18,21 +18,8 @@ :style="title_class" style="cursor: default;display: block;" > -
- -

{{ chart.title }}

+
+ { - const chartView = JSON.parse(JSON.stringify(response.data)) - chartView.viewFields = chartView.viewFields ? JSON.parse(chartView.viewFields) : [] - chartView.xaxis = chartView.xaxis ? JSON.parse(chartView.xaxis) : [] - chartView.xaxisExt = chartView.xaxisExt ? JSON.parse(chartView.xaxisExt) : [] - chartView.yaxis = chartView.yaxis ? JSON.parse(chartView.yaxis) : [] - chartView.yaxisExt = chartView.yaxisExt ? JSON.parse(chartView.yaxisExt) : [] - chartView.extStack = chartView.extStack ? JSON.parse(chartView.extStack) : [] - chartView.drillFields = chartView.drillFields ? JSON.parse(chartView.drillFields) : [] - chartView.extBubble = chartView.extBubble ? JSON.parse(chartView.extBubble) : [] - chartView.customAttr = chartView.customAttr ? JSON.parse(chartView.customAttr) : {} - chartView.customStyle = chartView.customStyle ? JSON.parse(chartView.customStyle) : {} - chartView.customFilter = chartView.customFilter ? JSON.parse(chartView.customFilter) : {} - chartView.senior = chartView.senior ? JSON.parse(chartView.senior) : {} - const viewSave = this.buildParam(chartView, true, 'chart', false, false) - if (!viewSave) return - viewEditSave(this.panelInfo.id, viewSave).then(() => { - bus.$emit('aside-set-title', this.chart.title) - }) - this.$store.commit('recordViewEdit', { viewId: this.chart.id, hasEdit: true }) - }) - }, - handleTitleEditer() { - if (this.mainActiveName !== 'PanelEdit' || this.mobileLayoutStatus || this.previewVisible) return - this.chartTitleEditer = true - this.chartTitleUpdate = this.chart.title - this.$nextTick(() => { - this.$refs.chartTitle.focus() - }) - }, - buildParam(chartView, getData, trigger, needRefreshGroup = false, switchType = false, switchRender = false) { - if (!chartView.resultCount || - chartView.resultCount === '' || - isNaN(Number(chartView.resultCount)) || - String(chartView.resultCount).includes('.') || - parseInt(chartView.resultCount) < 1) { - chartView.resultCount = '1000' - } - const view = JSON.parse(JSON.stringify(chartView)) - view.id = chartView.id - view.sceneId = chartView.sceneId - view.name = this.chartTitleUpdate - view.title = this.chartTitleUpdate - view.tableId = chartView.tableId - if (view.type === 'map' && view.xaxis.length > 1) { - view.xaxis = [view.xaxis[0]] - } - view.xaxis.forEach(function(ele) { - if (!ele.dateStyle || ele.dateStyle === '') { - ele.dateStyle = 'y_M_d' - } - if (!ele.datePattern || ele.datePattern === '') { - ele.datePattern = 'date_sub' - } - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - if (!ele.filter) { - ele.filter = [] - } - }) - if (view.type === 'table-pivot' || view.type === 'bar-group') { - view.xaxisExt.forEach(function(ele) { - if (!ele.dateStyle || ele.dateStyle === '') { - ele.dateStyle = 'y_M_d' - } - if (!ele.datePattern || ele.datePattern === '') { - ele.datePattern = 'date_sub' - } - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - if (!ele.filter) { - ele.filter = [] - } - }) - } - if (view.type === 'map' && view.yaxis.length > 1) { - view.yaxis = [view.yaxis[0]] - } - view.yaxis.forEach(function(ele) { - if (!ele.chartType) { - ele.chartType = 'bar' - } - if (ele.chartId) { - ele.summary = '' - } else { - if (!ele.summary || ele.summary === '') { - if (ele.id === 'count' || ele.deType === 0 || ele.deType === 1) { - ele.summary = 'count' - } else { - ele.summary = 'sum' - } - } - } - - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - if (!ele.filter) { - ele.filter = [] - } - if (!ele.compareCalc) { - ele.compareCalc = compareItem - } - }) - if (view.type === 'chart-mix') { - view.yaxisExt.forEach(function(ele) { - if (!ele.chartType) { - ele.chartType = 'bar' - } - if (ele.chartId) { - ele.summary = '' - } else { - if (!ele.summary || ele.summary === '') { - if (ele.id === 'count' || ele.deType === 0 || ele.deType === 1) { - ele.summary = 'count' - } else { - ele.summary = 'sum' - } - } - } - - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - if (!ele.filter) { - ele.filter = [] - } - if (!ele.compareCalc) { - ele.compareCalc = compareItem - } - }) - } - view.extStack.forEach(function(ele) { - if (!ele.dateStyle || ele.dateStyle === '') { - ele.dateStyle = 'y_M_d' - } - if (!ele.datePattern || ele.datePattern === '') { - ele.datePattern = 'date_sub' - } - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - }) - view.extBubble.forEach(function(ele) { - if (!ele.summary || ele.summary === '') { - if (ele.id === 'count' || ele.deType === 0 || ele.deType === 1) { - ele.summary = 'count' - } else { - ele.summary = 'sum' - } - } - }) - if (view.type === 'label') { - if (view.xaxis.length > 1) { - view.xaxis.splice(1, view.xaxis.length) - } - } - if (view.type.startsWith('pie') || - view.type.startsWith('funnel') || - view.type.startsWith('text') || - view.type.startsWith('gauge') || - view.type === 'treemap' || - view.type === 'liquid' || - view.type === 'word-cloud' || - view.type === 'waterfall' || - view.type.includes('group')) { - if (view.yaxis.length > 1) { - view.yaxis.splice(1, view.yaxis.length) - } - } - if (view.type === 'line-stack' && trigger === 'chart') { - view.customAttr.size.lineArea = true - } - if (view.type === 'line' && trigger === 'chart') { - view.customAttr.size.lineArea = false - } - if (view.type === 'treemap' && trigger === 'chart') { - view.customAttr.label.show = true - } - if (view.type === 'liquid' || - (view.type.includes('table') && view.render === 'echarts') || - view.type.includes('text') || - view.type.includes('gauge') || - view.type === 'table-pivot') { - view.drillFields = [] - } - view.customFilter.forEach(function(ele) { - if (ele && !ele.filter) { - ele.filter = [] - } - }) - view.xaxis = JSON.stringify(view.xaxis) - view.viewFields = JSON.stringify(view.viewFields) - view.xaxisExt = JSON.stringify(view.xaxisExt) - view.yaxis = JSON.stringify(view.yaxis) - view.yaxisExt = JSON.stringify(view.yaxisExt) - view.customAttr = JSON.stringify(view.customAttr) - view.customStyle = JSON.stringify(view.customStyle) - view.customFilter = JSON.stringify(view.customFilter) - view.extStack = JSON.stringify(view.extStack) - view.drillFields = JSON.stringify(view.drillFields) - view.extBubble = JSON.stringify(view.extBubble) - view.senior = JSON.stringify(view.senior) - delete view.data - return view - }, - changeEditStatus() { - this.lostFocus() - if (this.chartTitleUpdate.length > 50) { - this.$error(this.$t('chart.title_limit')) - return - } - if (this.chartTitleUpdate === this.chart.title) return - this.chart.title = this.chartTitleUpdate - this.getChartDetail() - }, initRemark() { this.remarkCfg = getRemark(this.chart) } } } - - diff --git a/frontend/src/views/chart/components/ChartComponentS2.vue b/frontend/src/views/chart/components/ChartComponentS2.vue index f64e4a338e..5729228c25 100644 --- a/frontend/src/views/chart/components/ChartComponentS2.vue +++ b/frontend/src/views/chart/components/ChartComponentS2.vue @@ -18,21 +18,8 @@ :style="title_class" style="cursor: default;display: block;" > -
- -

{{ chart.title }}

+
+ { - const chartView = JSON.parse(JSON.stringify(response.data)) - chartView.viewFields = chartView.viewFields ? JSON.parse(chartView.viewFields) : [] - chartView.xaxis = chartView.xaxis ? JSON.parse(chartView.xaxis) : [] - chartView.xaxisExt = chartView.xaxisExt ? JSON.parse(chartView.xaxisExt) : [] - chartView.yaxis = chartView.yaxis ? JSON.parse(chartView.yaxis) : [] - chartView.yaxisExt = chartView.yaxisExt ? JSON.parse(chartView.yaxisExt) : [] - chartView.extStack = chartView.extStack ? JSON.parse(chartView.extStack) : [] - chartView.drillFields = chartView.drillFields ? JSON.parse(chartView.drillFields) : [] - chartView.extBubble = chartView.extBubble ? JSON.parse(chartView.extBubble) : [] - chartView.customAttr = chartView.customAttr ? JSON.parse(chartView.customAttr) : {} - chartView.customStyle = chartView.customStyle ? JSON.parse(chartView.customStyle) : {} - chartView.customFilter = chartView.customFilter ? JSON.parse(chartView.customFilter) : {} - chartView.senior = chartView.senior ? JSON.parse(chartView.senior) : {} - const viewSave = this.buildParam(chartView, true, 'chart', false, false) - if (!viewSave) return - viewEditSave(this.panelInfo.id, viewSave).then(() => { - bus.$emit('aside-set-title', this.chart.title) - }) - this.$store.commit('recordViewEdit', { viewId: this.chart.id, hasEdit: true }) - }) - }, - handleTitleEditer() { - if (this.mainActiveName !== 'PanelEdit' || this.mobileLayoutStatus || this.previewVisible) return - this.chartTitleEditer = true - this.chartTitleUpdate = this.chart.title - this.$nextTick(() => { - this.$refs.chartTitle.focus() - }) - }, - buildParam(chartView, getData, trigger, needRefreshGroup = false, switchType = false, switchRender = false) { - if (!chartView.resultCount || - chartView.resultCount === '' || - isNaN(Number(chartView.resultCount)) || - String(chartView.resultCount).includes('.') || - parseInt(chartView.resultCount) < 1) { - chartView.resultCount = '1000' - } - const view = JSON.parse(JSON.stringify(chartView)) - view.id = chartView.id - view.sceneId = chartView.sceneId - view.name = this.chartTitleUpdate - view.title = this.chartTitleUpdate - view.tableId = chartView.tableId - if (view.type === 'map' && view.xaxis.length > 1) { - view.xaxis = [view.xaxis[0]] - } - view.xaxis.forEach(function(ele) { - if (!ele.dateStyle || ele.dateStyle === '') { - ele.dateStyle = 'y_M_d' - } - if (!ele.datePattern || ele.datePattern === '') { - ele.datePattern = 'date_sub' - } - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - if (!ele.filter) { - ele.filter = [] - } - }) - if (view.type === 'table-pivot' || view.type.includes('bar-group')) { - view.xaxisExt.forEach(function(ele) { - if (!ele.dateStyle || ele.dateStyle === '') { - ele.dateStyle = 'y_M_d' - } - if (!ele.datePattern || ele.datePattern === '') { - ele.datePattern = 'date_sub' - } - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - if (!ele.filter) { - ele.filter = [] - } - }) - } - if (view.type === 'map' && view.yaxis.length > 1) { - view.yaxis = [view.yaxis[0]] - } - view.yaxis.forEach(function(ele) { - if (!ele.chartType) { - ele.chartType = 'bar' - } - if (ele.chartId) { - ele.summary = '' - } else { - if (!ele.summary || ele.summary === '') { - if (ele.id === 'count' || ele.deType === 0 || ele.deType === 1) { - ele.summary = 'count' - } else { - ele.summary = 'sum' - } - } - } - - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - if (!ele.filter) { - ele.filter = [] - } - if (!ele.compareCalc) { - ele.compareCalc = compareItem - } - }) - if (view.type === 'chart-mix') { - view.yaxisExt.forEach(function(ele) { - if (!ele.chartType) { - ele.chartType = 'bar' - } - if (ele.chartId) { - ele.summary = '' - } else { - if (!ele.summary || ele.summary === '') { - if (ele.id === 'count' || ele.deType === 0 || ele.deType === 1) { - ele.summary = 'count' - } else { - ele.summary = 'sum' - } - } - } - - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - if (!ele.filter) { - ele.filter = [] - } - if (!ele.compareCalc) { - ele.compareCalc = compareItem - } - }) - } - view.extStack.forEach(function(ele) { - if (!ele.dateStyle || ele.dateStyle === '') { - ele.dateStyle = 'y_M_d' - } - if (!ele.datePattern || ele.datePattern === '') { - ele.datePattern = 'date_sub' - } - if (!ele.sort || ele.sort === '') { - ele.sort = 'none' - } - }) - view.extBubble.forEach(function(ele) { - if (!ele.summary || ele.summary === '') { - if (ele.id === 'count' || ele.deType === 0 || ele.deType === 1) { - ele.summary = 'count' - } else { - ele.summary = 'sum' - } - } - }) - if (view.type === 'label') { - if (view.xaxis.length > 1) { - view.xaxis.splice(1, view.xaxis.length) - } - } - if (view.type.startsWith('pie') || - view.type.startsWith('funnel') || - view.type.startsWith('text') || - view.type.startsWith('gauge') || - view.type === 'treemap' || - view.type === 'liquid' || - view.type === 'word-cloud' || - view.type === 'waterfall' || - view.type.includes('group')) { - if (view.yaxis.length > 1) { - view.yaxis.splice(1, view.yaxis.length) - } - } - if (view.type === 'line-stack' && trigger === 'chart') { - view.customAttr.size.lineArea = true - } - if (view.type === 'line' && trigger === 'chart') { - view.customAttr.size.lineArea = false - } - if (view.type === 'treemap' && trigger === 'chart') { - view.customAttr.label.show = true - } - if (view.type === 'liquid' || - (view.type.includes('table') && view.render === 'echarts') || - view.type.includes('text') || - view.type.includes('gauge') || - view.type === 'table-pivot') { - view.drillFields = [] - } - view.customFilter.forEach(function(ele) { - if (ele && !ele.filter) { - ele.filter = [] - } - }) - view.xaxis = JSON.stringify(view.xaxis) - view.viewFields = JSON.stringify(view.viewFields) - view.xaxisExt = JSON.stringify(view.xaxisExt) - view.yaxis = JSON.stringify(view.yaxis) - view.yaxisExt = JSON.stringify(view.yaxisExt) - view.customAttr = JSON.stringify(view.customAttr) - view.customStyle = JSON.stringify(view.customStyle) - view.customFilter = JSON.stringify(view.customFilter) - view.extStack = JSON.stringify(view.extStack) - view.drillFields = JSON.stringify(view.drillFields) - view.extBubble = JSON.stringify(view.extBubble) - view.senior = JSON.stringify(view.senior) - delete view.data - return view - }, - changeEditStatus() { - this.lostFocus() - if (this.chartTitleUpdate.length > 50) { - this.$error(this.$t('chart.title_limit')) - return - } - if (this.chartTitleUpdate === this.chart.title) return - this.chart.title = this.chartTitleUpdate - this.getChartDetail() - }, pageChange(val) { this.currentPage.pageSize = val this.initData() @@ -778,28 +514,4 @@ export default { .page-style ::v-deep li{ background: transparent!important; } - -.chart-input-title{ - word-break: break-word; - font: 12px / 1.231 -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, "Microsoft YaHei", "PingFang SC", sans-serif, "Segoe UI Symbol"; - overflow: visible; - margin: 0; - padding: 0; - font-weight: 400; - font-family: inherit; - border-radius: 2px; - color: #182b50; - font-size: 12px; - line-height: 26px; - padding-left: 10px; - padding-right: 10px; - background: transparent; - outline: none; - border-width: 0px 0px 1px; - border-image: initial; - border-bottom: 1px solid rgb(200, 203, 204); - z-index: 2; - height: 21px; - min-width: 100px; -} diff --git a/frontend/src/views/chart/components/ChartTitleUpdate.vue b/frontend/src/views/chart/components/ChartTitleUpdate.vue new file mode 100644 index 0000000000..334c4d53bf --- /dev/null +++ b/frontend/src/views/chart/components/ChartTitleUpdate.vue @@ -0,0 +1,382 @@ + + + + + diff --git a/frontend/src/views/chart/components/component-style/TitleSelector.vue b/frontend/src/views/chart/components/component-style/TitleSelector.vue index d5691cc72e..b674de0668 100644 --- a/frontend/src/views/chart/components/component-style/TitleSelector.vue +++ b/frontend/src/views/chart/components/component-style/TitleSelector.vue @@ -12,10 +12,10 @@ :label="$t('chart.show')" class="form-item" > - {{ $t('chart.show') }} + />
- {{ $t('chart.show') }} + />
-
+
import tinymce from 'tinymce/tinymce' // tinymce默认hidden,不引入不显示 -import Editor from '@tinymce/tinymce-vue'// 编辑器引入 +import Editor from '@tinymce/tinymce-vue' +import { imgUrlTrans } from '@/components/canvas/utils/utils' +import { mapState } from 'vuex' +import { hexColorToRGBA } from '@/views/chart/chart/util' +// 编辑器引入 export default { name: 'RemarkEditor', components: { @@ -21,6 +28,10 @@ export default { type: String, required: true }, + background: { + type: String, + required: false + }, showTable: { type: Boolean, default: true @@ -61,6 +72,38 @@ export default { } } }, + computed: { + customStyle() { + let style = {} + if (this.canvasStyleData.openCommonStyle) { + if (this.canvasStyleData.panel.backgroundType === 'image' && this.canvasStyleData.panel.imageUrl) { + style = { + background: `url(${imgUrlTrans(this.canvasStyleData.panel.imageUrl)}) no-repeat`, + ...style + } + } else if (this.canvasStyleData.panel.backgroundType === 'color') { + style = { + background: this.canvasStyleData.panel.color, + ...style + } + } + } + if (!style.background) { + style.background = '#FFFFFF' + } + return style + }, + commonStyle() { + return { + background: this.background + } + }, + ... + mapState([ + 'curComponent', + 'canvasStyleData' + ]) + }, watch: { content: { handler(newValue) { @@ -68,7 +111,6 @@ export default { } } }, - created() { if (!this.showTable) { this.init.plugins = this.init.plugins.replace(' table', '') @@ -86,4 +128,8 @@ export default { diff --git a/frontend/src/views/chart/components/normal/LabelNormal.vue b/frontend/src/views/chart/components/normal/LabelNormal.vue index 30aee75973..a83de2a35a 100644 --- a/frontend/src/views/chart/components/normal/LabelNormal.vue +++ b/frontend/src/views/chart/components/normal/LabelNormal.vue @@ -10,8 +10,8 @@ :style="title_class" style="cursor: default;display: block;" > -
-

{{ chart.title }}

+
+ -
-

{{ chart.title }}

+
+ - diff --git a/frontend/src/views/dataset/add/AddDB.vue b/frontend/src/views/dataset/add/AddDB.vue index ba39fb8381..791f839d8c 100644 --- a/frontend/src/views/dataset/add/AddDB.vue +++ b/frontend/src/views/dataset/add/AddDB.vue @@ -33,7 +33,7 @@ v-model="dataSource" class="ds-list" filterable - popper-class="db-select-pop" + popper-class="db-multiple-select-pop" :placeholder="$t('dataset.pls_slc_data_source')" size="small" > @@ -640,20 +640,3 @@ export default { } } - diff --git a/frontend/src/views/dataset/add/AddSQL.vue b/frontend/src/views/dataset/add/AddSQL.vue index 6be3cebd14..2c46970430 100644 --- a/frontend/src/views/dataset/add/AddSQL.vue +++ b/frontend/src/views/dataset/add/AddSQL.vue @@ -208,8 +208,149 @@ @input="onCmCodeChange" />
+ + + + -
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
{{ $t('deDataset.running_results') }} {{ @@ -456,9 +597,10 @@ import { engineMode } from '@/api/system/engine' import msgCfm from '@/components/msgCfm/index' import cancelMix from './cancelMix' import _ from 'lodash' +import GridTable from '@/components/gridTable/index.vue' export default { name: 'AddSQL', - components: { codemirror }, + components: { codemirror, GridTable }, mixins: [msgCfm, cancelMix], props: { param: { @@ -468,6 +610,13 @@ export default { }, data() { return { + tabActive: 'result', + paginationConfig: { + currentPage: 1, + pageSize: 10, + total: 0 + }, + data: [], dataSource: '', loading: false, dataTable: '', @@ -592,6 +741,24 @@ export default { }) }, methods: { + copy(text) { + this.$copyText(text).then((e) => { + this.openMessageSuccess('commons.copy_success') + }, (e) => { + this.openMessageSuccess('commons.copy_success') + }) + }, + changeTab() { + }, + handleSizeChange(pageSize) { + this.paginationConfig.currentPage = 1 + this.paginationConfig.pageSize = pageSize + this.listSqlLog() + }, + handleCurrentChange(currentPage) { + this.paginationConfig.currentPage = currentPage + this.listSqlLog() + }, getField(name) { post('/dataset/table/getFields', { dataSourceId: this.dataSource, @@ -687,7 +854,6 @@ export default { }) } }, - getSQLPreview() { this.errMsg = false this.errMsgCont = '' @@ -700,6 +866,7 @@ export default { this.fields = [] this.$refs.plxTable?.reloadData([]) post('/dataset/table/sqlPreview', { + id: this.param.tableId, dataSourceId: this.dataSource, type: 'sql', mode: parseInt(this.mode), @@ -710,17 +877,49 @@ export default { }) }, true, 60000, true) .then((response) => { - this.fields = response.data.fields - this.$nextTick(() => { - this.$refs.plxTable?.reloadData(response.data.data) - }) + if (response.success) { + this.fields = response.data.fields + this.$nextTick(() => { + this.$refs.plxTable?.reloadData(response.data.data) + }) + if (!this.param.tableId) { + this.data.unshift(response.data.log) + this.$refs.tableLog?.reloadData(this.data) + } else { + this.listSqlLog() + } + } else { + this.errMsgCont = response.message + this.errMsg = true + if (!this.param.tableId) { + this.data.unshift(response.data) + this.$refs.tableLog?.reloadData(this.data) + } else { + this.listSqlLog() + } + } }) - .catch((err, msg) => { + .catch((err, msg, response) => { this.errMsgCont = err this.errMsg = true + if (!this.param.tableId) { + this.data.unshift(response.data) + this.$refs.tableLog?.reloadData(this.data) + } else { + this.listSqlLog() + } }) }, + listSqlLog() { + post('/dataset/table/sqlLog/' + this.paginationConfig.currentPage + '/' + this.paginationConfig.pageSize, { id: this.param.tableId, dataSourceId: this.dataSource }) + .then((response) => { + this.data = response.data.listObject + this.paginationConfig.total = response.data.itemCount + }) + .catch(() => { + }) + }, save() { if (!this.dataSource || this.datasource === '') { this.openMessageSuccess('dataset.pls_slc_data_source', 'error') @@ -1062,5 +1261,17 @@ export default { } } } + .table-container { + height: calc(100% - 50px); + .mar6 { + margin-right: 6px; + } + .mar3 { + margin-left: -3px; + } + } + .table-container-filter { + height: calc(100% - 110px); + } } diff --git a/frontend/src/views/dataset/form.vue b/frontend/src/views/dataset/form.vue index fa397647c1..6612092422 100644 --- a/frontend/src/views/dataset/form.vue +++ b/frontend/src/views/dataset/form.vue @@ -21,7 +21,7 @@ style="left: 55px" class="el-form-item__error" > - {{ $t('deDataset.already_Exists') }} + {{ $t('deDataset.already_exists') }}
@@ -64,6 +66,7 @@ import { save, update, nameCheck } from '@/api/system/appTemplate' import msgCfm from '@/components/msgCfm/index' import { find } from '@/api/system/template' import { imgUrlTrans } from '@/components/canvas/utils/utils' +import JSZip from 'jszip' export default { mixins: [msgCfm], @@ -186,22 +189,31 @@ export default { }) }, handleFileChange(e) { + const jsZip = new JSZip() const file = e.target.files[0] - const reader = new FileReader() const _this = this - reader.onload = (res) => { - _this.appResultInfo = JSON.parse(res.target.result) - _this.importTemplateInfo = JSON.parse(this.appResultInfo.panelInfo) - _this.templateInfo.name = this.importTemplateInfo.name - _this.templateInfo.templateStyle = this.importTemplateInfo.panelStyle - _this.templateInfo.templateData = this.importTemplateInfo.panelData - _this.templateInfo.snapshot = this.importTemplateInfo.snapshot - _this.templateInfo.dynamicData = this.importTemplateInfo.dynamicData - _this.templateInfo.staticResource = - _this.importTemplateInfo.staticResource - _this.templateInfo.nodeType = 'template' - } - reader.readAsText(file) + jsZip.loadAsync(file).then(function(file) { + jsZip.file('DATA_RELATION.DE').async('string').then(function(content) { + _this.appResultInfo = { ...JSON.parse(content), ..._this.appResultInfo } + }) + jsZip.file('APP.json').async('string').then(function(content) { + _this.appResultInfo['applicationInfo'] = content + const appInfo = JSON.parse(content) + _this.templateInfo.name = appInfo.appName + }) + jsZip.file('TEMPLATE.DET').async('string').then(function(content) { + _this.appResultInfo['panelInfo'] = content + _this.importTemplateInfo = JSON.parse(content) + _this.templateInfo.templateStyle = _this.importTemplateInfo.panelStyle + _this.templateInfo.templateData = _this.importTemplateInfo.panelData + _this.templateInfo.snapshot = _this.importTemplateInfo.snapshot + _this.templateInfo.dynamicData = _this.importTemplateInfo.dynamicData + _this.templateInfo.staticResource = _this.importTemplateInfo.staticResource + _this.templateInfo.nodeType = 'template' + }) + }).catch(() => { + _this.$warning(this.$t('app_template.file_error_tips')) + }) }, goFile() { this.$refs.files.click() @@ -216,10 +228,12 @@ export default { border: none; padding: 0 0; } + .my_table ::v-deep .el-table th.is-leaf { /* 去除上边框 */ border: none; } + .my_table ::v-deep .el-table::before { /* 去除下边框 */ height: 0; @@ -229,6 +243,7 @@ export default { margin-top: 24px; text-align: right; } + .preview { margin-top: -12px; border: 1px solid #e6e6e6; @@ -237,6 +252,7 @@ export default { background-size: 100% 100% !important; border-radius: 4px; } + .preview-show { border-left: 1px solid #e6e6e6; height: 300px; @@ -250,6 +266,7 @@ export default { display: flex; align-items: center; justify-content: space-between; + .el-input { margin-right: 2px; flex: 1; diff --git a/frontend/src/views/panel/appTemplate/component/TemplateList.vue b/frontend/src/views/panel/appTemplate/component/TemplateList.vue index d14b3259b3..16b8414afe 100644 --- a/frontend/src/views/panel/appTemplate/component/TemplateList.vue +++ b/frontend/src/views/panel/appTemplate/component/TemplateList.vue @@ -158,8 +158,8 @@ export default { }, templateDelete(template) { const options = { - title: this.$('app_template.app_group_delete_tips'), - content: this.$('app_template.app_group_delete_content'), + title: this.$t('app_template.app_group_delete_tips'), + content: this.$t('app_template.app_group_delete_content'), type: 'primary', cb: () => this.$emit('templateDelete', template.id) } diff --git a/frontend/src/views/panel/appTemplateMarket/log/index.vue b/frontend/src/views/panel/appTemplateMarket/log/index.vue index fb000a9004..226f2479a9 100644 --- a/frontend/src/views/panel/appTemplateMarket/log/index.vue +++ b/frontend/src/views/panel/appTemplateMarket/log/index.vue @@ -224,6 +224,7 @@ import { import { deleteLogAndResource, logGrid } from '@/api/appTemplateMarket/log' import { findOneWithParent } from '@/api/panel/panel' import AppTemplateApply from '@/views/panel/appTemplate/component/AppTemplateApply' +import { hasDataPermission } from '@/utils/permission' export default { name: 'AppTemplateLog', @@ -308,7 +309,8 @@ export default { panelName: item.panelName, datasourcePrivileges: item.datasourcePrivileges, panelPrivileges: item.panelPrivileges, - datasetPrivileges: item.datasetPrivileges + datasetPrivileges: item.datasetPrivileges, + appMarketEdit: hasDataPermission('manage', item.datasourcePrivileges) } this.$refs.templateEditApply.init(param) }, diff --git a/frontend/src/views/panel/list/AppExportForm.vue b/frontend/src/views/panel/list/AppExportForm.vue new file mode 100644 index 0000000000..565b21f96b --- /dev/null +++ b/frontend/src/views/panel/list/AppExportForm.vue @@ -0,0 +1,195 @@ + + + + diff --git a/frontend/src/views/panel/list/PanelViewShow.vue b/frontend/src/views/panel/list/PanelViewShow.vue index f4c4072332..93dc150180 100644 --- a/frontend/src/views/panel/list/PanelViewShow.vue +++ b/frontend/src/views/panel/list/PanelViewShow.vue @@ -120,7 +120,7 @@ >{{ $t('panel.export_to_img') }} {{ $t('panel.export_to_app') }} @@ -278,6 +278,48 @@ @closePreExport="closePreExport" /> + + + + + + + + + + + + + +