Merge branch 'dev' into pr@dev@fix_table_wrong_index_number

# Conflicts:
#	frontend/src/views/chart/chart/common/common_table.js
#	frontend/src/views/chart/chart/table/table-info.js
#	frontend/src/views/chart/components/ChartComponentS2.vue
This commit is contained in:
wisonic-s 2022-10-31 19:19:13 +08:00
commit 49c61f6a42
70 changed files with 1793 additions and 1000 deletions

View File

@ -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<ExcelSheetModel> sheets, String fileName) throws Exception {
public static File exportExcel(List<ExcelSheetModel> sheets, String fileName, String folderId) throws Exception {
AtomicReference<String> realFileName = new AtomicReference<>(fileName);
HSSFWorkbook wb = new HSSFWorkbook();
Workbook wb = new XSSFWorkbook();
sheets.forEach(sheet -> {
List<List<String>> 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<String> 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;
}

View File

@ -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<String, Object> 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<List<DatasetSqlLog>> getSQLLog(@RequestBody DataSetTableRequest dataSetTableRequest, @PathVariable int goPage, @PathVariable int pageSize) throws Exception {
Page<DatasetSqlLog> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, dataSetTableService.getSQLLog(dataSetTableRequest));
}
@ApiOperation("预览自定义数据数据")
@PostMapping("customPreview")
public Map<String, Object> customPreview(@RequestBody DataSetTableRequest dataSetTableRequest) throws Exception {

View File

@ -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<DatasourceDTO> datasourceList = datasourceService.getDatasourceList(request);
return CollectionUtils.isNotEmpty(datasourceList) ? datasourceList.get(0) : null;
return datasourceService.getDataSourceDetails(id);
}
@ApiOperation("查询当前用户数据源")

View File

@ -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);
}

View File

@ -15,7 +15,7 @@ public interface ExtDataSourceMapper {
List<DatasourceDTO> findByPanelId(@Param("panelId") String panelId);
DatasourceDTO queryDetails(@Param("datasourceId") String datasourceId,@Param("userId") String userId);
}

View File

@ -130,5 +130,12 @@
WHERE panel_view.panel_id = #{panelId}
</select>
<select id="queryDetails" resultMap="BaseResultMapDTO">
select datasource.*,
get_auths(id, 'link', #{userId}) as `privileges`
from datasource
where id = #{datasourceId}
</select>
</mapper>

View File

@ -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<File> 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<File> files = null;
String viewIds = emailTemplateDTO.getViewIds();
ChartViewService chartViewService = SpringContextUtil.getBean(ChartViewService.class);
List<ViewOption> viewOptions = chartViewService.viewOptions(panelId);
@ -210,7 +212,7 @@ public class EmailTaskHandler extends TaskHandler implements Job {
List<String> 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<String> 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);
}
});
}
}
}

View File

@ -233,7 +233,7 @@ public class XEmailTaskServer {
ExcelSheetModel excelSheetModel = excelSheetModel(instanceDTOS);
List<ExcelSheetModel> 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 {

View File

@ -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);
}
}

View File

@ -40,7 +40,7 @@ public class ViewExportExcel {
}.getType();
@DePermissionProxy(paramIndex = 2)
public List<File> export(String panelId, List<String> viewIds, PermissionProxy proxy, Boolean justView) throws Exception {
public List<File> export(String panelId, List<String> viewIds, PermissionProxy proxy, Boolean justView, String taskId) throws Exception {
if (CollectionUtils.isEmpty(viewIds)) {
return null;
}
@ -51,7 +51,7 @@ public class ViewExportExcel {
Map<String, ChartExtRequest> stringChartExtRequestMap = buildViewRequest(panelDto, justView);
List<File> results = new ArrayList<>();
List<ExcelSheetModel> 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<Map<String, Object>> 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<String, ChartExtRequest> result = new HashMap<>();
Map<String, List<ChartExtFilterRequest>> 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);
}

View File

@ -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<String, Object> options = null;
List<String> values = null;
if((optionObj = component.get("options")) != null && (valueObj = (options = (Map<String, Object>) optionObj).get("value")) != null && CollectionUtil.isNotEmpty((values = (List<String>) valueObj))) {
if ((optionObj = component.get("options")) != null && (valueObj = (options = (Map<String, Object>) optionObj).get("value")) != null) {
if (valueObj instanceof List) {
values = (List<String>) 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;
}

View File

@ -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<String, Object> getSQLPreview(DataSetTableRequest dataSetTableRequest) throws Exception {
public List<DatasetSqlLog> 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<String, List> result = datasourceProvider.fetchResultAndField(datasourceRequest);
Map<String, List> 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<String[]> data = result.get("dataList");
List<TableField> fields = result.get("fieldList");
String[] fieldArray = fields.stream().map(TableField::getFieldName).toArray(String[]::new);
@ -1223,8 +1258,9 @@ public class DataSetTableService {
Map<String, Object> map = new HashMap<>();
map.put("fields", fields);
map.put("data", jsonArray);
map.put("log", datasetSqlLog);
return map;
return ResultHolder.success(map);
}
public Map<String, Object> getUnionPreview(DataSetTableRequest dataSetTableRequest) throws Exception {

View File

@ -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);

View File

@ -152,6 +152,12 @@ public class DatasourceService {
request.setSort("update_time desc");
List<DatasourceDTO> datasourceDTOS = extDataSourceMapper.queryUnion(request);
datasourceDTOS.forEach(datasourceDTO -> {
datasourceTrans(datasourceDTO);
});
return datasourceDTOS;
}
private void datasourceTrans(DatasourceDTO datasourceDTO){
types().forEach(dataSourceType -> {
if (dataSourceType.getType().equalsIgnoreCase(datasourceDTO.getType())) {
datasourceDTO.setTypeDesc(dataSourceType.getName());
@ -206,10 +212,15 @@ public class DatasourceService {
}
}
}
});
return datasourceDTOS;
}
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<DatasourceDTO> gridQuery(BaseGridRequest request) {
//如果没有查询条件增加一个默认的条件
if (CollectionUtils.isEmpty(request.getConditions())) {

View File

@ -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<SettingTreeNode> buildTree(List<SysMsgType> lists){
private List<SettingTreeNode> buildTree(List<SysMsgType> lists) {
List<SettingTreeNode> 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<SubscribeNode> subscribes = subscribes(userId);
if (CollectionUtils.isNotEmpty(subscribes)) {
subscribes.stream().filter(item -> item.getTypeId().equals(typeId)).forEach(sub -> {
SendService sendService = serviceByChannel(sub.getChannelId());
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<SysMsgSetting> 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();
@ -311,5 +321,4 @@ public class SysMsgService {
}
}

View File

@ -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());
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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';

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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
})
}

View File

@ -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;
}
</style>

View File

@ -106,6 +106,7 @@
<el-color-picker
v-else
v-model="option.colors[index]"
popper-class="gradient-picker-dropdown"
@change="switchColorItem(option.colors, option.value)"
/>
</span>
@ -423,4 +424,7 @@ export default {
width: 20px;
height: 20px;
}
.gradient-picker-dropdown .el-color-dropdown__link-btn {
display: none;
}
</style>

View File

@ -11,16 +11,25 @@
v-if="editFilter.includes(curComponent.type)"
icon="el-icon-edit-outline"
@click.native="edit"
>{{ $t('panel.edit') }}</el-dropdown-item>
>{{ $t('panel.edit') }}
</el-dropdown-item>
<el-dropdown-item
v-if="curComponent.type != 'custom-button'"
icon="el-icon-document-copy"
@click.native="copy"
>{{ $t('panel.copy') }}</el-dropdown-item>
>{{ $t('panel.copy') }}
</el-dropdown-item>
<el-dropdown-item
icon="el-icon-delete"
@click.native="deleteComponent"
>{{ $t('panel.delete') }}</el-dropdown-item>
>{{ $t('panel.delete') }}
</el-dropdown-item>
<el-dropdown-item
v-if="curComponent.type ==='de-tabs'"
icon="el-icon-sort"
@click.native="openCustomSort"
>{{ $t('chart.sort') }}
</el-dropdown-item>
<el-dropdown-item v-if="!curComponent.auxiliaryMatrix">
<el-dropdown placement="right-start">
<span class="el-icon-copy-document">
@ -30,19 +39,23 @@
<el-dropdown-item
icon="el-icon-upload2"
@click.native="topComponent"
>{{ $t('panel.topComponent') }}</el-dropdown-item>
>{{ $t('panel.topComponent') }}
</el-dropdown-item>
<el-dropdown-item
icon="el-icon-download"
@click.native="bottomComponent"
>{{ $t('panel.bottomComponent') }}</el-dropdown-item>
>{{ $t('panel.bottomComponent') }}
</el-dropdown-item>
<el-dropdown-item
icon="el-icon-arrow-up"
@click.native="upComponent"
>{{ $t('panel.upComponent') }}</el-dropdown-item>
>{{ $t('panel.upComponent') }}
</el-dropdown-item>
<el-dropdown-item
icon="el-icon-arrow-down"
@click.native="downComponent"
>{{ $t('panel.downComponent') }}</el-dropdown-item>
>{{ $t('panel.downComponent') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-dropdown-item>
@ -50,22 +63,26 @@
v-if="linkageSettingShow"
icon="el-icon-link"
@click.native="linkageSetting"
>{{ $t('panel.linkage_setting') }}</el-dropdown-item>
>{{ $t('panel.linkage_setting') }}
</el-dropdown-item>
<el-dropdown-item
v-if="'de-tabs'===curComponent.type"
icon="el-icon-plus"
@click.native="addTab"
>{{ $t('panel.add_tab') }}</el-dropdown-item>
>{{ $t('panel.add_tab') }}
</el-dropdown-item>
<el-dropdown-item
v-if="linkJumpSetShow"
icon="el-icon-connection"
@click.native="linkJumpSet"
>{{ $t('panel.setting_jump') }}</el-dropdown-item>
>{{ $t('panel.setting_jump') }}
</el-dropdown-item>
<el-dropdown-item
v-if="curComponent.type != 'custom-button'"
icon="el-icon-magic-stick"
@click.native="boardSet"
>{{ $t('panel.component_style') }}</el-dropdown-item>
>{{ $t('panel.component_style') }}
</el-dropdown-item>
<el-dropdown-item
v-if="curComponent.type != 'custom-button'"
@click.native="hyperlinksSet"
@ -91,6 +108,38 @@
@onClose="hyperlinksSetVisible = false"
/>
</el-dialog>
<el-dialog
v-if="showCustomSort"
v-dialogDrag
:title="$t('chart.custom_sort')"
:visible="showCustomSort"
:show-close="false"
width="500px"
:append-to-body="true"
class="dialog-css"
>
<custom-tabs-sort
ref="customTabsSort"
:element="curComponent"
/>
<div
slot="footer"
class="dialog-footer"
>
<el-button
size="mini"
@click="closeCustomSort"
>{{ $t('chart.cancel') }}
</el-button>
<el-button
type="primary"
size="mini"
@click="saveCustomSort"
>{{ $t('chart.confirm') }}
</el-button>
</div>
</el-dialog>
</div>
</template>
@ -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,7 +331,7 @@ export default {
</script>
<style lang="scss" scoped>
.contextmenu {
.contextmenu {
position: absolute;
z-index: 1000;
@ -274,7 +339,7 @@ export default {
border: 1px solid #e4e7ed;
border-radius: 4px;
background-color: #fff;
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
box-sizing: border-box;
margin: 5px 0;
padding: 6px 0;
@ -297,5 +362,5 @@ export default {
}
}
}
}
}
</style>

View File

@ -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 {
</script>
<style lang="scss" scoped>
.attr-list {
.attr-list {
overflow: auto;
padding: 20px;
padding-top: 0;
height: 100%;
}
.el-card-main {
}
.el-card-main {
height: 34px;
z-index: 10;
padding-right: 2px;
position: absolute;
}
.el-card-main ::v-deep .el-card__body {
padding: 0px!important;
}
}
.el-card-main ::v-deep .el-card__body {
padding: 0px !important;
::v-deep .el-radio-button__inner{
padding: 5px!important;
width: 30px!important;
}
}
::v-deep .el-color-dropdown__link-btn {
display: inline!important;
}
::v-deep .el-radio-button__inner {
padding: 5px !important;
width: 30px !important;
}
::v-deep input::-webkit-outer-spin-button,
::v-deep input::-webkit-inner-spin-button {
::v-deep .el-color-dropdown__link-btn {
display: inline !important;
}
::v-deep input::-webkit-outer-spin-button,
::v-deep input::-webkit-inner-spin-button {
-webkit-appearance: none !important;
}
::v-deep input[type='number'] {
}
::v-deep input[type='number'] {
-moz-appearance: textfield !important;
}
}
</style>

View File

@ -388,7 +388,8 @@ const list = [
height: 200,
borderStyle: 'solid',
borderWidth: 0,
borderColor: '#000000'
borderColor: '#000000',
fontSize: 16
},
options: {
tabList: [{

View File

@ -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
}

View File

@ -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
}

View File

@ -0,0 +1,121 @@
<template>
<div>
<draggable
v-model="sortList"
group="drag"
animation="300"
class="drag-list"
>
<transition-group class="draggable-group">
<span
v-for="(item) in sortList"
:key="item.name"
class="item-dimension"
:title="item.title"
>
<svg-icon
icon-class="drag"
class="item-icon"
/>
<span class="item-span">
{{ item.title }}
</span>
</span>
</transition-group>
</draggable>
</div>
</template>
<script>
import { deepCopy } from '@/components/canvas/utils/utils'
export default {
name: 'CustomTabsSort',
props: {
element: {
type: Object,
required: true
}
},
data() {
return {
sortList: []
}
},
computed: {
},
watch: {
chart() {
this.init()
}
},
mounted() {
this.init()
},
methods: {
init() {
this.sortList = deepCopy(this.element.options.tabList)
},
save() {
this.element.options.tabList = this.sortList
}
}
}
</script>
<style scoped>
.drag-list {
overflow: auto;
height: 50vh;
}
.item-dimension {
padding: 2px;
margin: 2px;
border: solid 1px #eee;
text-align: left;
color: #606266;
/*background-color: rgba(35,46,64,.05);*/
background-color: white;
display: flex;
align-items: center;
}
.item-icon{
cursor: move;
margin: 0 2px;
}
.item-span{
display: inline-block;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.blackTheme .item-dimension {
border: solid 1px;
border-color: var(--TableBorderColor);
color: var(--TextPrimary);
background-color: var(--MainBG);
}
.item-dimension + .item-dimension {
margin-top: 6px;
}
.item-dimension:hover {
color: #1890ff;
background: #e8f4ff;
border-color: #a3d3ff;
cursor: pointer;
}
.blackTheme .item-dimension:hover {
color: var(--Main);
background: var(--ContentBG);
cursor: pointer;
}
</style>

View File

@ -24,18 +24,19 @@
v-model="checkAll"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
>
{{ $t('commons.all') }}</el-checkbox>
/>{{ $t('commons.all') }}
<el-checkbox-group
v-model="value"
@change="handleCheckedChange"
>
<template v-for="item in data.filter(node => !keyWord || (node.id && node.id.includes(keyWord)))">
<el-checkbox
v-for="item in data.filter(node => !keyWord || (node.id && node.id.includes(keyWord)))"
:key="item.id"
:label="item.id"
>{{ item.id }}</el-checkbox>
<br :key="item.id">
</template>
</el-checkbox-group>
</div>
@ -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;
}
}

View File

@ -1,6 +1,8 @@
<template>
<div class="de-tabs-div">
<div
class="de-tabs-div"
:class="headClass"
>
<dataease-tabs
v-model="activeTabName"
type="card"
@ -23,8 +25,7 @@
:name="item.name"
>
<span slot="label">
<span>{{ item.title }}</span>
<span :style="titleStyle">{{ item.title }}</span>
<el-dropdown
v-if="dropdownShow"
slot="label"
@ -33,7 +34,6 @@
@command="handleCommand"
>
<span class="el-dropdown-link">
<i
v-if="isEdit"
class="de-tab-i el-icon-arrow-down el-icon--right"
@ -293,6 +293,14 @@ export default {
}
},
computed: {
titleStyle() {
return {
fontSize: (this.element.style.fontSize || 16) + 'px'
}
},
headClass() {
return 'tab-head-' + this.element.style.headPosition
},
curCanvasScaleSelf() {
return this.curCanvasScaleMap[this.canvasId]
},
@ -634,5 +642,20 @@ export default {
.canvas_move_in {
border-color: blueviolet;
}
::v-deep .el-tabs__nav{
width: 100%;
}
.tab-head-left ::v-deep .el-tabs__nav{
width: 100%;
text-align: left;
}
.tab-head-right ::v-deep .el-tabs__nav{
width: 100%;
text-align: right;
}
.tab-head-center ::v-deep .el-tabs__nav{
width: 100%;
text-align: center;
}
</style>

View File

@ -8,7 +8,7 @@
ref="tabsStyleForm"
:model="styleInfo"
size="small"
class="demo-form-inline"
class="de-form-item"
>
<el-form-item
label="头部字体颜色"
@ -102,8 +102,17 @@
</el-input>
</div>
</el-form-item>
<el-form-item :label="$t('detabs.head_position')">
<el-radio-group
v-model="styleInfo.headPosition"
size="mini"
>
<el-radio-button label="left">{{ $t('chart.text_pos_left') }}</el-radio-button>
<el-radio-button label="center">{{ $t('chart.text_pos_center') }}</el-radio-button>
<el-radio-button label="right">{{ $t('chart.text_pos_right') }}</el-radio-button>
</el-radio-group>
</el-form-item>
</el-form>
<i
slot="reference"
class="iconfont icon-tabs"
@ -114,6 +123,7 @@
<script>
import { mapState } from 'vuex'
export default {
name: 'TabStyle',
props: {
@ -123,9 +133,7 @@ export default {
}
},
data() {
return {
}
return {}
},
computed: {

View File

@ -530,11 +530,13 @@ export default {
the_running_results: 'You can view the running results'
},
detabs: {
custom_sort: 'Custom Sort',
eidttitle: 'Edit Title',
selectview: 'Select View',
selectOthers: 'Select Others',
availableComponents: 'Available Components',
please: 'Please'
please: 'Please',
head_position: 'Head Position'
},
example: {
warning: 'Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all pages directly. See details'
@ -912,6 +914,7 @@ export default {
password_input_error: 'Original password input error'
},
chart: {
chart_background: 'Component background',
solid_color: 'Solid color',
split_gradient: 'Split gradient',
continuous_gradient: 'Continuous gradient',
@ -1438,6 +1441,9 @@ export default {
table_index_desc: 'Index Header Name'
},
dataset: {
spend_time: 'Spend',
sql: 'SQL',
sql_result: 'Result',
parse_filed: 'Parse Field',
field_rename: 'Rename Field',
params_work: 'Effective only when editing SQL',
@ -2641,8 +2647,13 @@ export default {
dataset_group: 'Dataset group',
panel: 'Panel',
log_delete_tips: 'Are you sure to delete this application record?',
log_resource_delete_tips: 'Delete related resources (irrecoverable after deletion)'
log_resource_delete_tips: 'Delete related resources (irrecoverable after deletion)',
file_error_tips: 'The relevant data file is not found. The current file may not be a DataEase application file, or the file may be damaged ',
app_export: 'Application export',
app_version: 'Application version',
program_version: 'DataEase minimum version',
creator: 'Author',
export: 'Export'
},
logout: {

View File

@ -530,11 +530,13 @@ export default {
the_running_results: '即可查看運行結果'
},
detabs: {
custom_sort: '自定義排序',
eidttitle: '編輯標題',
selectview: '選擇視圖',
selectOthers: '選擇組件',
availableComponents: '可選組件',
please: '未'
please: '未',
head_position: '頭部位置'
},
example: {
warning: '創建和編輯頁面是不能被 keep-alive 緩存的因爲keep-alive 的 include 目前不支持根據路由來緩存,所以目前都是基於 component name 來進行緩存的。如果妳想類似的實現緩存效果,可以使用 localStorage 等瀏覽器緩存方案。或者不要使用 keep-alive 的 include直接緩存所有頁面。詳情見'
@ -912,6 +914,7 @@ export default {
password_input_error: '原始密碼輸入錯誤'
},
chart: {
chart_background: '組件背景',
solid_color: '純色',
split_gradient: '分離漸變',
continuous_gradient: '連續漸變',
@ -1438,6 +1441,9 @@ export default {
table_index_desc: '表頭名稱'
},
dataset: {
spend_time: '耗時',
sql: 'SQL 語句',
sql_result: '運行結果',
parse_filed: '解析字段',
field_rename: '字段重命名',
params_work: '僅在編輯 sql 時生效',
@ -2631,7 +2637,6 @@ export default {
search_by_keyword: '通過關鍵字搜索',
apply_logs: '應用記錄',
app_group_delete_tips: '確定刪除該應用分類嗎?',
app_group_delete_content: '刪除後,該分類中所有的應用模板也將被刪除。',
panel_position: '儀表板位置',
panel_name: '儀表板名稱',
@ -2642,8 +2647,13 @@ export default {
dataset_group: '數據集分組',
panel: '儀表板',
log_delete_tips: '確定刪除該條應用記錄嗎?',
log_resource_delete_tips: '刪除相關資源(刪除後不可恢復)'
log_resource_delete_tips: '刪除相關資源(刪除後不可恢復)',
file_error_tips: '未找到相關數據文件當前文件可能不是DataEase應用文件或者文件已經損壞',
app_export: '應用導出',
app_version: '應用版本',
program_version: 'DataEase最低版本',
creator: '作者',
export: '導出'
},
logout: {

View File

@ -529,11 +529,13 @@ export default {
the_running_results: '即可查看运行结果'
},
detabs: {
custom_sort: '自定义排序',
eidttitle: '编辑标题',
selectview: '选择视图',
selectOthers: '选择组件',
availableComponents: '可选组件',
please: '未'
please: '未',
head_position: '头部位置'
},
example: {
warning: '创建和编辑页面是不能被 keep-alive 缓存的因为keep-alive 的 include 目前不支持根据路由来缓存,所以目前都是基于 component name 来进行缓存的。如果你想类似的实现缓存效果,可以使用 localStorage 等浏览器缓存方案。或者不要使用 keep-alive 的 include直接缓存所有页面。详情见'
@ -911,6 +913,7 @@ export default {
password_input_error: '原始密码输入错误'
},
chart: {
chart_background: '组件背景',
solid_color: '纯色',
split_gradient: '分离渐变',
continuous_gradient: '连续渐变',
@ -1437,6 +1440,9 @@ export default {
table_index_desc: '表头名称'
},
dataset: {
spend_time: '耗时',
sql: 'SQL 语句',
sql_result: '运行结果',
parse_filed: '解析字段',
field_rename: '字段重命名',
params_work: '仅在编辑sql时生效',
@ -2631,7 +2637,6 @@ export default {
search_by_keyword: '通过关键字搜索',
apply_logs: '应用记录',
app_group_delete_tips: '确定删除该应用分类吗?',
app_group_delete_content: '删除后,该分类中所有的应用模板也将被删除。',
panel_position: '仪表板位置',
panel_name: '仪表板名称',
@ -2642,8 +2647,13 @@ export default {
dataset_group: '数据集分组',
panel: '仪表板',
log_delete_tips: '确定删除该条应用记录吗?',
log_resource_delete_tips: '删除相关资源(删除后不可恢复)'
log_resource_delete_tips: '删除相关资源(删除后不可恢复)',
file_error_tips: '未找到相关数据文件当前文件可能不是DataEase应用文件或者文件已经损坏',
app_export: '应用导出',
app_version: '应用版本',
program_version: 'DataEase最低版本',
creator: '作者',
export: '导出'
},
logout: {

View File

@ -263,7 +263,7 @@ const data = {
} else {
state.componentData.push(component)
}
this.commit('setCurComponent', { component: component, index: index ? index : state.componentData.length - 1 })
this.commit('setCurComponent', { component: component, index: index || state.componentData.length - 1 })
},
removeViewFilter(state, componentId) {
state.componentData = state.componentData.map(item => {

View File

@ -1633,3 +1633,28 @@ div:focus {
height: 24px;
}
}
.db-multiple-select-pop {
.selected::after {
content: '';
width: 6px;
height: 12px;
position: absolute;
right: 12px;
top: 9px;
border: 2px solid #3370ff;
border-top-color: rgba(0, 0, 0, 0);
border-left-color: rgba(0, 0, 0, 0);
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
}
.role-add-name {
.el-select-dropdown__item.selected::after {
content: '';
position: absolute;
right: 12px;
top: 9px;
}
}

View File

@ -1,15 +1,17 @@
export const DEFAULT_TAB_COLOR_CASE_DARK = {
headFontColor: '#FFFFFF',
headFontActiveColor: '#FFFFFF',
headBorderColor: '',
headBorderActiveColor: ''
headBorderColor: '#131E42',
headBorderActiveColor: '#131E42',
headPosition: 'left'
}
export const DEFAULT_TAB_COLOR_CASE_LIGHT = {
headFontColor: '#OOOOOO',
headFontActiveColor: '#OOOOOO',
headBorderColor: '',
headBorderActiveColor: ''
headBorderColor: '#OOOOOO',
headBorderActiveColor: '#OOOOOO',
headPosition: 'left'
}
export const DEFAULT_COLOR_CASE = {
@ -22,25 +24,27 @@ export const DEFAULT_COLOR_CASE = {
tableFontColor: '#000000',
tableStripe: true,
dimensionColor: '#000000',
quotaColor: '#4E81BB',
quotaColor: '#5470c6',
tableBorderColor: '#E6E7E4',
seriesColors: [], // 格式:{"name":"s1","color":"","isCustom":false}
areaBorderColor: '#303133'
areaBorderColor: '#303133',
areaBaseColor: '#FFFFFF'
}
export const DEFAULT_COLOR_CASE_DARK = {
value: 'default',
colors: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
alpha: 100,
tableHeaderBgColor: '#4E81BB',
tableHeaderBgColor: '#5470c6',
tableItemBgColor: '#131E42',
tableFontColor: '#ffffff',
tableStripe: true,
dimensionColor: '#ffffff',
quotaColor: '#4E81BB',
quotaColor: '#5470c6',
tableBorderColor: '#CCCCCC',
seriesColors: [], // 格式:{"name":"s1","color":"","isCustom":false}
areaBorderColor: '#EBEEF5'
areaBorderColor: '#EBEEF5',
areaBaseColor: '5470C6'
}
export const DEFAULT_SIZE = {
barDefault: true,
@ -209,7 +213,7 @@ export const DEFAULT_TITLE_STYLE_DARK = {
isBolder: true,
remarkShow: false,
remark: '',
remarkBackgroundColor: '#ffffffff',
remarkBackgroundColor: '#5A5C62',
fontFamily: 'Microsoft YaHei',
letterSpace: '0',
fontShadow: false

View File

@ -154,7 +154,7 @@ export function componentStyle(chart_option, chart) {
chart_option.yAxis[0].axisLabel = customStyle.yAxis.axisLabel
chart_option.yAxis[0].splitLine = customStyle.yAxis.splitLine
chart_option.yAxis[0].nameTextStyle = customStyle.yAxis.nameTextStyle
const axisLine0 = customStyle.yAxis[0].axisLine ? customStyle.yAxis[0].axisLine : DEFAULT_YAXIS_STYLE.axisLine
const axisLine0 = customStyle.yAxis.axisLine ? customStyle.yAxis.axisLine : DEFAULT_YAXIS_STYLE.axisLine
chart_option.yAxis[0].axisLine = axisLine0
chart_option.yAxis[0].axisTick = axisLine0
@ -187,7 +187,7 @@ export function componentStyle(chart_option, chart) {
chart_option.yAxis[1].axisLabel = customStyle.yAxisExt.axisLabel
chart_option.yAxis[1].splitLine = customStyle.yAxisExt.splitLine
chart_option.yAxis[1].nameTextStyle = customStyle.yAxisExt.nameTextStyle
const axisLine1 = customStyle.yAxis[1].axisLine ? customStyle.yAxis[1].axisLine : DEFAULT_YAXIS_EXT_STYLE.axisLine
const axisLine1 = customStyle.yAxisExt.axisLine ? customStyle.yAxisExt.axisLine : DEFAULT_YAXIS_EXT_STYLE.axisLine
chart_option.yAxis[1].axisLine = axisLine1
chart_option.yAxis[1].axisTick = axisLine1

View File

@ -21,7 +21,7 @@ export function getCustomTheme(chart) {
backgroundColor: headerColor,
horizontalBorderColor: borderColor,
verticalBorderColor: borderColor,
verticalBorderWidth: 0
verticalBorderWidth: chart.type === 'table-pivot' ? 1 : 0
},
text: {
fill: DEFAULT_COLOR_CASE.tableHeaderFontColor,
@ -49,7 +49,7 @@ export function getCustomTheme(chart) {
fill: DEFAULT_COLOR_CASE.tableHeaderFontColor,
fontSize: DEFAULT_SIZE.tableTitleFontSize,
textAlign: headerAlign,
textBaseline: 'middle' // 行头字体绘制基线设置为中心,不然序号列的内容会靠上
textBaseline: chart.type === 'table-pivot' ? 'top' : 'middle'
},
bolderText: {
fill: DEFAULT_COLOR_CASE.tableHeaderFontColor,
@ -127,12 +127,21 @@ export function getCustomTheme(chart) {
theme.cornerCell.text.fill = c.tableHeaderFontColor ? c.tableHeaderFontColor : c.tableFontColor
theme.cornerCell.measureText.fill = c.tableHeaderFontColor ? c.tableHeaderFontColor : c.tableFontColor
if (chart.type === 'table-pivot') {
theme.rowCell.cell.backgroundColor = h_c
theme.rowCell.cell.horizontalBorderColor = b_c
theme.rowCell.cell.verticalBorderColor = b_c
theme.rowCell.bolderText.fill = c.tableHeaderFontColor ? c.tableHeaderFontColor : c.tableFontColor
theme.rowCell.text.fill = c.tableHeaderFontColor ? c.tableHeaderFontColor : c.tableFontColor
theme.rowCell.measureText.fill = c.tableHeaderFontColor ? c.tableHeaderFontColor : c.tableFontColor
} else {
theme.rowCell.cell.backgroundColor = i_c // 这个参数其实只对开启序号列的行头生效
theme.rowCell.cell.horizontalBorderColor = i_c
theme.rowCell.cell.verticalBorderColor = i_c
theme.rowCell.bolderText.fill = c.tableFontColor
theme.rowCell.text.fill = c.tableFontColor
theme.rowCell.measureText.fill = c.tableFontColor
}
theme.colCell.cell.backgroundColor = h_c
theme.colCell.cell.horizontalBorderColor = b_c
@ -161,6 +170,14 @@ export function getCustomTheme(chart) {
theme.cornerCell.measureText.fontSize = parseInt(s.tableTitleFontSize)
theme.cornerCell.measureText.textAlign = h_a
if (chart.type === 'table-pivot') {
theme.rowCell.bolderText.fontSize = parseInt(s.tableTitleFontSize)
theme.rowCell.bolderText.textAlign = h_a
theme.rowCell.text.fontSize = parseInt(s.tableTitleFontSize)
theme.rowCell.text.textAlign = h_a
theme.rowCell.measureText.fontSize = parseInt(s.tableTitleFontSize)
theme.rowCell.measureText.textAlign = h_a
} else {
// 序号列的数字单元格内容样式使用指标的内容样式而不是表头的内容样式
theme.rowCell.bolderText.fontSize = parseInt(s.tableItemFontSize)
theme.rowCell.bolderText.textAlign = i_a
@ -168,6 +185,7 @@ export function getCustomTheme(chart) {
theme.rowCell.text.textAlign = i_a
theme.rowCell.measureText.fontSize = parseInt(s.tableItemFontSize)
theme.rowCell.measureText.textAlign = i_a
}
theme.rowCell.seriesNumberWidth = parseInt(s.tableColumnWidth)
theme.colCell.bolderText.fontSize = parseInt(s.tableTitleFontSize)

View File

@ -3,7 +3,6 @@ import { getCustomTheme, getSize } from '@/views/chart/chart/common/common_table
import { DEFAULT_COLOR_CASE, DEFAULT_TOTAL } from '@/views/chart/chart/chart'
import { formatterItem, valueFormatter } from '@/views/chart/chart/formatter'
import { hexColorToRGBA } from '@/views/chart/chart/util'
import Vue from 'vue'
export function baseTableInfo(s2, container, chart, action, tableData, pageInfo) {
const containerDom = document.getElementById(container)
@ -12,7 +11,6 @@ export function baseTableInfo(s2, container, chart, action, tableData, pageInfo)
if (!fields || fields.length === 0) {
if (s2) {
s2.destroy()
destroyS2()
}
return
}
@ -150,7 +148,6 @@ export function baseTableInfo(s2, container, chart, action, tableData, pageInfo)
// 开始渲染
if (s2) {
s2.destroy()
destroyS2
}
s2 = new TableSheet(containerDom, s2DataConfig, s2Options)
@ -173,7 +170,6 @@ export function baseTableNormal(s2, container, chart, action, tableData) {
if (!fields || fields.length === 0) {
if (s2) {
s2.destroy()
destroyS2
}
return
}
@ -292,7 +288,6 @@ export function baseTableNormal(s2, container, chart, action, tableData) {
// 开始渲染
if (s2) {
s2.destroy()
destroyS2()
}
s2 = new TableSheet(containerDom, s2DataConfig, s2Options)
@ -329,7 +324,6 @@ export function baseTablePivot(s2, container, chart, action, tableData) {
if (!fields || fields.length === 0) {
if (s2) {
s2.destroy()
destroyS2()
}
return
}
@ -451,7 +445,6 @@ export function baseTablePivot(s2, container, chart, action, tableData) {
// 开始渲染
if (s2) {
s2.destroy()
destroyS2()
}
s2 = new PivotSheet(containerDom, s2DataConfig, s2Options)
@ -465,13 +458,6 @@ export function baseTablePivot(s2, container, chart, action, tableData) {
return s2
}
function destroyS2(s2) {
for (const i in s2) {
Vue.$delete(s2, i)
}
s2 = null
}
function getCurrentField(valueFieldList, field) {
let list = []
let res = null

View File

@ -47,6 +47,9 @@
</div>
</div>
<div
:class="loading ? 'symbol-map-loading' : 'symbol-map-loaded'"
/>
</div>
</template>
@ -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
// domecharts
// echartdom,idechart 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() {

View File

@ -18,21 +18,8 @@
:style="title_class"
style="cursor: default;display: block;"
>
<div style="padding:6px 4px 0;margin: 0;">
<input
v-if="chartTitleEditer"
ref="chartTitle"
v-model.lazy="chartTitleUpdate"
v-clickoutside="lostFocus"
type="text"
class="chart-input-title"
@blur="changeEditStatus"
>
<p
v-else
style="overflow: hidden;white-space: pre;text-overflow: ellipsis;display: inline;min-width: 30px"
@click.stop="handleTitleEditer"
>{{ chart.title }}</p>
<div style="padding:6px 4px 0;margin: 0;display: flex;">
<chart-title-update :chart-info="chartInfo" />
<title-remark
v-if="remarkCfg.show"
style="text-shadow: none!important;"
@ -66,23 +53,10 @@ import { baseWordCloudOptionAntV } from '@/views/chart/chart/wordCloud/word_clou
import TitleRemark from '@/views/chart/view/TitleRemark'
import { DEFAULT_TITLE_STYLE } from '@/views/chart/chart/chart'
import { baseMixOptionAntV } from '@/views/chart/chart/mix/mix_antv'
import { compareItem } from '@/views/chart/chart/compare'
import { mapState } from 'vuex'
import clickoutside from 'element-ui/src/utils/clickoutside.js'
import bus from '@/utils/bus'
import {
getChartDetails
} from '@/api/chart/chart'
import {
viewEditSave
} from '@/api/chart/chart'
import ChartTitleUpdate from './ChartTitleUpdate.vue'
export default {
name: 'ChartComponentG2',
components: { TitleRemark, ViewTrackBar },
directives: {
clickoutside
},
components: { TitleRemark, ViewTrackBar, ChartTitleUpdate },
props: {
chart: {
type: Object,
@ -124,7 +98,6 @@ export default {
top: '0px'
},
pointParam: null,
chartTitleEditer: false,
dynamicAreaCode: null,
borderRadius: '0px',
chartHeight: '100%',
@ -159,16 +132,10 @@ export default {
borderRadius: this.borderRadius
}
},
panelInfo() {
return this.$store.state.panel.panelInfo
},
mainActiveName() {
return this.$store.state.panel.mainActiveName
},
...mapState([
'mobileLayoutStatus',
'previewVisible'
])
chartInfo() {
const { id, title } = this.chart
return { id, title }
}
},
watch: {
chart: {
@ -422,258 +389,9 @@ export default {
this.calcHeightRightNow()
}, 100)
},
lostFocus() {
this.chartTitleEditer = false
},
getChartDetail() {
getChartDetails(this.chart.id, this.panelInfo.id, { queryFrom: 'panel_edit' }).then(response => {
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)
}
}
}
</script>
<style scoped lang="scss">
.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;
}
</style>

View File

@ -18,21 +18,8 @@
:style="title_class"
style="cursor: default;display: block;"
>
<div style="padding:6px 4px 0;margin: 0;">
<input
v-if="chartTitleEditer"
ref="chartTitle"
v-model.lazy="chartTitleUpdate"
v-clickoutside="lostFocus"
type="text"
class="chart-input-title"
@blur="changeEditStatus"
>
<p
v-else
style="overflow: hidden;white-space: pre;text-overflow: ellipsis;display: inline;min-width: 30px"
@click.stop="handleTitleEditer"
>{{ chart.title }}</p>
<div style="padding:6px 4px 0;margin: 0;display: flex;">
<chart-title-update :chart-info="chartInfo" />
<title-remark
v-if="remarkCfg.show"
style="text-shadow: none!important;"
@ -96,22 +83,10 @@ import { getRemark, hexColorToRGBA } from '@/views/chart/chart/util'
import { baseTableInfo, baseTableNormal, baseTablePivot } from '@/views/chart/chart/table/table-info'
import TitleRemark from '@/views/chart/view/TitleRemark'
import { DEFAULT_TITLE_STYLE } from '@/views/chart/chart/chart'
import clickoutside from 'element-ui/src/utils/clickoutside.js'
import bus from '@/utils/bus'
import { mapState } from 'vuex'
import { compareItem } from '@/views/chart/chart/compare'
import {
getChartDetails
} from '@/api/chart/chart'
import {
viewEditSave
} from '@/api/chart/chart'
import ChartTitleUpdate from './ChartTitleUpdate.vue'
export default {
name: 'ChartComponentS2',
components: { TitleRemark, ViewTrackBar },
directives: {
clickoutside
},
components: { TitleRemark, ViewTrackBar, ChartTitleUpdate },
props: {
chart: {
type: Object,
@ -147,7 +122,6 @@ export default {
left: '0px',
top: '0px'
},
chartTitleEditer: false,
pointParam: null,
dynamicAreaCode: null,
borderRadius: '0px',
@ -167,7 +141,6 @@ export default {
},
title_show: true,
antVRenderStatus: false,
chartTitleUpdate: '',
currentPage: {
page: 1,
pageSize: 20,
@ -193,16 +166,10 @@ export default {
borderRadius: this.borderRadius
}
},
panelInfo() {
return this.$store.state.panel.panelInfo
},
mainActiveName() {
return this.$store.state.panel.mainActiveName
},
...mapState([
'mobileLayoutStatus',
'previewVisible'
])
chartInfo() {
const { id, title } = this.chart
return { id, title }
}
},
watch: {
chart: {
@ -225,7 +192,6 @@ export default {
},
beforeDestroy() {
clearInterval(this.scrollTimer)
this.destroyS2()
},
methods: {
initData() {
@ -268,13 +234,6 @@ export default {
})
}
},
destroyS2() {
if (!this.myChart) return
for (const i in this.myChart) {
this.$delete(this.myChart, i)
}
this.myChart = null
},
drawView() {
const chart = this.chart
// type
@ -300,7 +259,6 @@ export default {
if (this.myChart) {
this.antVRenderStatus = false
this.myChart.destroy()
this.destroyS2()
}
}
@ -457,228 +415,6 @@ export default {
this.calcHeightRightNow()
}, 100)
},
lostFocus() {
this.chartTitleEditer = false
},
getChartDetail() {
getChartDetails(this.chart.id, this.panelInfo.id, { queryFrom: 'panel_edit' }).then(response => {
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;
}
</style>

View File

@ -0,0 +1,382 @@
<template>
<el-input
v-if="chartTitleEditer"
ref="chartTitle"
v-model.lazy="chartTitleUpdate"
v-clickoutside="lostFocus"
clearable
type="text"
class="chart-input-title"
@blur="changeEditStatus"
/>
<p
v-else
style="overflow: hidden;white-space: pre;text-overflow: ellipsis;display: inline-block;min-width: 30px"
@click.stop="handleTitleEditer"
>{{ chart.title }}</p>
</template>
<script>
import clickoutside from 'element-ui/src/utils/clickoutside.js'
import { mapState } from 'vuex'
import { checkViewTitle } from '@/components/canvas/utils/utils'
import { getChartDetails, viewEditSave } from '@/api/chart/chart'
import bus from '@/utils/bus'
import { compareItem } from '@/views/chart/chart/compare'
export default {
directives: {
clickoutside
},
props: {
chartInfo: {
type: Object,
default: () => {}
}
},
data() {
return {
chartTitleEditer: false,
chartTitleUpdate: '',
chart: {}
}
},
computed: {
mainActiveName() {
return this.$store.state.panel.mainActiveName
},
...mapState(['mobileLayoutStatus', 'previewVisible']),
panelInfo() {
return this.$store.state.panel.panelInfo
}
},
watch: {
chartInfo: {
handler(val) {
const { id, title } = this.chartInfo
this.chart = { id, title }
},
immediate: true,
deep: true
}
},
methods: {
changeEditStatus() {
this.lostFocus()
if (this.chartTitleUpdate.length > 50) {
this.$error(this.$t('chart.title_limit'))
return
}
if (this.chartTitleUpdate.length < 1) {
this.$error(this.$t('chart.title_cannot_empty'))
this.chartTitleUpdate = this.chart.title
return
}
if (checkViewTitle('update', this.chart.id, this.chartTitleUpdate)) {
this.$error(this.$t('chart.title_repeat'))
this.chartTitleUpdate = this.chart.title
return
}
if (this.chartTitleUpdate === this.chart.title) return
this.chart.title = this.chartTitleUpdate
this.getChartDetail()
},
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
},
lostFocus() {
this.chartTitleEditer = false
},
handleTitleEditer() {
if (
this.mainActiveName !== 'PanelEdit' ||
this.mobileLayoutStatus ||
this.previewVisible
) { return }
this.chartTitleEditer = true
this.chartTitleUpdate = this.chart.title
this.$nextTick(() => {
this.$refs.chartTitle.focus()
})
},
getChartDetail() {
getChartDetails(this.chart.id, this.panelInfo.id, {
queryFrom: 'panel_edit'
}).then((response) => {
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(() => {
this.chart.title = this.chartTitleUpdate
bus.$emit('aside-set-title', this.chart.title)
})
this.$store.commit('recordViewEdit', {
viewId: this.chart.id,
hasEdit: true
})
})
}
}
}
</script>
<style scoped lang="scss">
::v-deep.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;
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: 20%;
max-width: 50%;
.el-input__inner {
height: 21px;
font-size: 12px;
color: #182b50;
font-weight: 400;
font-family: inherit;
border-radius: 0;
border: none;
line-height: 21px;
background: transparent;
}
.el-input__suffix {
.el-input__icon {
line-height: 21px;
}
}
}
</style>

View File

@ -12,10 +12,10 @@
:label="$t('chart.show')"
class="form-item"
>
<el-checkbox
<el-switch
v-model="titleForm.show"
@change="changeTitleStyle('show')"
>{{ $t('chart.show') }}</el-checkbox>
/>
</el-form-item>
<div v-show="showProperty('show') && titleForm.show">
<el-form-item

View File

@ -12,10 +12,10 @@
:label="$t('chart.show')"
class="form-item"
>
<el-checkbox
<el-switch
v-model="titleForm.show"
@change="changeTitleStyle('show')"
>{{ $t('chart.show') }}</el-checkbox>
/>
</el-form-item>
<div v-show="showProperty('show') && titleForm.show">
<el-form-item
@ -194,6 +194,7 @@
>
<remark-editor
:remark="titleForm.remark"
:background="titleForm.remarkBackgroundColor"
@onRemarkChange="onRemarkChange"
/>
<div

View File

@ -1,5 +1,8 @@
<template>
<div style="max-height: 50vh;overflow-y: auto;">
<div
style="max-height: 50vh;overflow-y: auto;"
:style="commonStyle"
>
<Editor
v-model="content"
style="width: 100%;height: 100%"
@ -10,7 +13,11 @@
<script>
import tinymce from 'tinymce/tinymce' // tinymcehidden
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 {
<style scoped>
::v-deep .tox-edit-area__iframe {
background: rgba(255, 255, 255, 0) !important;
}
</style>

View File

@ -10,8 +10,8 @@
:style="title_class"
style="cursor: default;display: block;"
>
<div>
<p style="padding:6px 4px 0;margin: 0;overflow: hidden;white-space: pre;text-overflow: ellipsis;display: inline;">{{ chart.title }}</p>
<div style="display: flex;">
<chart-title-update :chart-info="chartInfo" />
<title-remark
v-if="chart.render && chart.render === 'antv' && remarkCfg.show"
style="text-shadow: none!important;"
@ -47,10 +47,11 @@ import eventBus from '@/components/canvas/utils/eventBus'
import { formatterItem, valueFormatter } from '@/views/chart/chart/formatter'
import TitleRemark from '@/views/chart/view/TitleRemark'
import { DEFAULT_SIZE, DEFAULT_TITLE_STYLE } from '@/views/chart/chart/chart'
import ChartTitleUpdate from '../ChartTitleUpdate.vue'
export default {
name: 'LabelNormal',
components: { TitleRemark },
components: { TitleRemark, ChartTitleUpdate },
props: {
chart: {
type: Object,
@ -110,12 +111,10 @@ export default {
}
},
computed: {
// bg_class() {
// return {
// background: hexColorToRGBA('#ffffff', 0),
// borderRadius: this.borderRadius
// }
// }
chartInfo() {
const { id, title } = this.chart
return { id, title }
}
},
watch: {
chart() {

View File

@ -17,8 +17,8 @@
:style="title_class"
style="cursor: default;display: block;"
>
<div>
<p style="padding:6px 4px 0;margin: 0;overflow: hidden;white-space: pre;text-overflow: ellipsis;display: inline;">{{ chart.title }}</p>
<div style="display: flex;">
<chart-title-update :chart-info="chartInfo" />
<title-remark
v-if="chart.render && chart.render === 'antv' && remarkCfg.show"
style="text-shadow: none!important;"
@ -59,10 +59,11 @@ import eventBus from '@/components/canvas/utils/eventBus'
import ViewTrackBar from '@/components/canvas/components/Editor/ViewTrackBar'
import TitleRemark from '@/views/chart/view/TitleRemark'
import { DEFAULT_SIZE, DEFAULT_TITLE_STYLE } from '@/views/chart/chart/chart'
import ChartTitleUpdate from '../ChartTitleUpdate.vue'
export default {
name: 'LabelNormalText',
components: { TitleRemark, ViewTrackBar },
components: { TitleRemark, ViewTrackBar, ChartTitleUpdate },
props: {
chart: {
type: Object,
@ -137,13 +138,11 @@ export default {
computed: {
trackBarStyleTime() {
return this.trackBarStyle
},
chartInfo() {
const { id, title } = this.chart
return { id, title }
}
// bg_class() {
// return {
// background: hexColorToRGBA('#ffffff', 0),
// borderRadius: this.borderRadius
// }
// }
},
watch: {
chart() {

View File

@ -427,7 +427,7 @@ span {
.between-item {
position: relative;
display: inline-block;
width: 80px !important;
width: 90px !important;
}
.select-item {

View File

@ -39,6 +39,7 @@ export default {
max-height: 200px;
overflow-y: auto;
padding: 10px;
color: #000000;
border-radius: 4px;
}
::-webkit-scrollbar {

View File

@ -32,6 +32,7 @@
<el-select
v-model="dataSource"
class="ds-list"
popper-class="db-multiple-select-pop"
filterable
:placeholder="$t('dataset.pls_slc_data_source')"
size="small"
@ -623,20 +624,3 @@ export default {
}
}
</style>
<style lang="scss">
.db-select-pop {
.selected::after {
content: '';
width: 6px;
height: 12px;
position: absolute;
right: 12px;
top: 9px;
border: 2px solid #3370ff;
border-top-color: rgba(0, 0, 0, 0);
border-left-color: rgba(0, 0, 0, 0);
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
}
</style>

View File

@ -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 {
}
}
</style>
<style lang="scss">
.db-select-pop {
.selected::after {
content: '';
width: 6px;
height: 12px;
position: absolute;
right: 12px;
top: 9px;
border: 2px solid #3370ff;
border-top-color: rgba(0, 0, 0, 0);
border-left-color: rgba(0, 0, 0, 0);
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
}
</style>

View File

@ -208,8 +208,149 @@
@input="onCmCodeChange"
/>
</div>
<el-tabs
v-model="tabActive"
@tab-click="changeTab"
>
<el-tab-pane
:label="$t('dataset.task.list')"
name="result"
/>
<el-tab-pane
:label="$t('dataset.task.record')"
name="execLog"
/>
</el-tabs>
<div class="sql-result">
<div
v-show="tabActive === 'execLog'"
class="table-container"
>
<grid-table
v-if="param.tableId"
v-loading="loading"
:table-data="data"
:columns="[]"
:pagination="paginationConfig"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
<el-table-column
key="startTime"
min-width="200px"
prop="startTime"
:label="$t('dataset.start_time')"
>
<template slot-scope="scope">
<span>{{ scope.row.startTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
key="startTime"
min-width="200px"
prop="sql"
:label="$t('dataset.sql')"
/>
<el-table-column
key="startTime"
min-width="200px"
prop="spend"
:label="$t('dataset.spend_time')"
/>
<el-table-column
key="startTime"
min-width="200px"
prop="status"
:label="$t('dataset.sql_result')"
>
<template slot-scope="scope">
<span
v-if="scope.row.status"
:class="[`de-${scope.row.status}-pre`, 'de-status']"
>{{ $t(`dataset.${scope.row.status.toLocaleLowerCase()}`) }}
</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column
slot="__operation"
key="__operation"
:label="$t('commons.operating')"
fixed="right"
width="100"
>
<template slot-scope="scope">
<el-button
class="de-text-btn mar3 mar6"
type="text"
@click="copy(scope.row.sql)"
>
{{ $t("commons.copy") }}
</el-button>
</template>
</el-table-column>
</grid-table>
<ux-grid
v-else
ref="tableLog"
size="mini"
style="width: 100%"
:height="height"
:checkbox-config="{ highlight: true }"
:width-resize="true"
>
<ux-table-column
key="startTime"
min-width="200px"
field="startTime"
:title="$t('dataset.start_time')"
:resizable="true"
>
<template slot-scope="scope">
<span>{{ scope.row.startTime | timestampFormatDate }}</span>
</template>
</ux-table-column>
<ux-table-column
key="startTime"
min-width="200px"
field="sql"
:title="$t('dataset.sql')"
:resizable="true"
/>
<ux-table-column
key="startTime"
min-width="200px"
field="spend"
:title="$t('dataset.spend_time')"
:resizable="true"
/>
<ux-table-column
key="startTime"
min-width="200px"
field="status"
:title="$t('dataset.sql_result')"
:resizable="true"
>
<template slot-scope="scope">
<span
v-if="scope.row.status"
:class="[`de-${scope.row.status}-pre`, 'de-status']"
>{{ $t(`dataset.${scope.row.status.toLocaleLowerCase()}`) }}
</span>
<span v-else>-</span>
</template>
</ux-table-column>
</ux-grid>
</div>
<div
v-show="tabActive === 'result'"
class="sql-result"
>
<div class="sql-title">
{{ $t('deDataset.running_results') }}
<span class="result-num">{{
@ -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) => {
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);
}
}
</style>

View File

@ -21,7 +21,7 @@
style="left: 55px"
class="el-form-item__error"
>
{{ $t('deDataset.already_Exists') }}
{{ $t('deDataset.already_exists') }}
</div>
</template>
<template v-else>

View File

@ -7,7 +7,7 @@
style="margin-right: 10px;float: right"
@change="themeChange('backgroundColorSelect')"
>
<span style="font-size: 12px">{{ $t('panel.color') }}</span>
<span style="font-size: 12px">{{ $t('chart.chart_background') }}</span>
</el-checkbox>
</el-col>
<el-col :span="10">
@ -100,10 +100,10 @@ export default {
font-size: 12px;
}
.custom-item{
width: 70px;
width: 90px;
}
.custom-item-value{
width: calc(100% - 70px);;
width: calc(100% - 90px);;
}
</style>

View File

@ -11,10 +11,10 @@
:label="$t('chart.show')"
class="form-item"
>
<el-checkbox
<el-switch
v-model="titleForm.show"
@change="changeTitleStyle('show')"
>{{ $t('chart.show') }}</el-checkbox>
/>
</el-form-item>
<div v-show="titleForm.show">
<el-form-item

View File

@ -1,6 +1,7 @@
<template>
<el-drawer
v-closePress
v-loading="$store.getters.loadingMap[$store.getters.currentPath]"
:title="'应用模板'"
:visible.sync="applyDrawer"
custom-class="de-user-drawer"

View File

@ -31,7 +31,7 @@
id="input"
ref="files"
type="file"
accept=".DEAPP"
accept=".zip"
hidden
@change="handleFileChange"
>
@ -47,14 +47,16 @@
secondary
@click="cancel()"
>{{
$t("commons.cancel")
}}</deBtn>
$t('commons.cancel')
}}
</deBtn>
<deBtn
type="primary"
@click="save()"
>{{
$t("commons.confirm")
}}</deBtn>
$t('commons.confirm')
}}
</deBtn>
</el-row>
</div>
</template>
@ -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
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'
}
reader.readAsText(file)
})
}).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;

View File

@ -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)
}

View File

@ -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)
},

View File

@ -0,0 +1,195 @@
<template>
<el-drawer
v-closePress
:title="$t('app_template.app_export')"
:visible.sync="applyDownloadDrawer"
custom-class="de-user-drawer"
size="600px"
direction="rtl"
>
<div class="app-export">
<el-form
ref="applyDownloadForm"
:model="form"
:rules="rule"
size="small"
class="de-form-item"
label-width="180px"
label-position="right"
>
<el-form-item
:label="$t('app_template.app_name')"
prop="appName"
>
<el-input
v-model="form.appName"
autocomplete="off"
:placeholder="$t('commons.input_name')"
/>
</el-form-item>
<el-form-item
:label="$t('app_template.app_version')"
prop="version"
>
<el-input
v-model="form.version"
autocomplete="off"
/>
</el-form-item>
<el-form-item
:label="$t('app_template.program_version')"
prop="required"
>
<el-input
v-model="form.required"
autocomplete="off"
/>
</el-form-item>
<el-form-item
:label="$t('app_template.creator')"
prop="creator"
>
<el-input
v-model="form.creator"
autocomplete="off"
/>
</el-form-item>
<el-form-item
:label="$t('commons.description')"
prop="description"
>
<deTextarea
v-model="form.description"
class="w100-textarea"
/>
</el-form-item>
</el-form>
</div>
<div
class="app-export-bottom"
>
<div
class="apply"
style="width: 100%"
>
<deBtn
secondary
@click="close"
>{{ $t('commons.cancel') }}
</deBtn>
<deBtn
type="primary"
@click="downloadApp"
>{{ $t('app_template.export') }}
</deBtn>
</div>
</div>
</el-drawer>
</template>
<script>
import i18n from '@/lang/index'
import deTextarea from '@/components/deCustomCm/deTextarea.vue'
import msgCfm from '@/components/msgCfm'
export default {
name: 'AppExportForm',
components: {
deTextarea
},
mixins: [msgCfm],
props: {},
data() {
return {
applyDownloadDrawer: false,
form: {
appName: null,
icon: null,
version: null,
creator: null,
required: '1.16.0',
description: null
},
rule: {
appName: [
{
required: true,
min: 2,
max: 25,
message: i18n.t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
],
creator: [
{
required: true,
min: 2,
max: 25,
message: i18n.t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
],
required: [
{
required: true,
min: 2,
max: 25,
message: i18n.t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
],
version: [
{
required: true,
min: 2,
max: 25,
message: i18n.t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
]
}
}
},
created() {
},
methods: {
init(params) {
this.applyDownloadDrawer = true
this.form = params
},
close() {
this.$emit('closeDraw')
this.applyDownloadDrawer = false
},
downloadApp() {
this.$refs.applyDownloadForm.validate(valid => {
if (valid) {
this.$emit('downLoadApp', this.form)
this.applyDownloadDrawer = false
} else {
return false
}
})
}
}
}
</script>
<style lang="scss" scoped>
.app-export{
width: 100%;
height: calc(100% - 56px);
}
.app-export-bottom{
width: 100%;
height: 56px;
text-align: right;
}
::v-deep .el-drawer__body{
padding-bottom: 0px!important;
}
</style>

View File

@ -120,7 +120,7 @@
>{{ $t('panel.export_to_img') }}</el-dropdown-item>
<el-dropdown-item
icon="el-icon-s-data"
@click.native="downLoadToApp"
@click.native="downLoadToAppPre"
>{{ $t('panel.export_to_app') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
@ -278,6 +278,48 @@
@closePreExport="closePreExport"
/>
</el-dialog>
<el-dialog
v-if="appExportShow"
:title="$t('app_template.app_export')"
:visible.sync="appExportShow"
width="80%"
:top="'8vh'"
:destroy-on-close="true"
class="dialog-css2"
>
<span style="position: absolute;right: 70px;top:15px">
<svg-icon
icon-class="PDF"
class="ds-icon-pdf"
/>
<el-select
v-model="pdfTemplateSelectedIndex"
:placeholder="'切换PDF模板'"
@change="changePdfTemplate()"
>
<el-option
v-for="(item, index) in pdfTemplateAll"
:key="index"
:label="item.name"
:value="index"
/>
</el-select>
</span>
<PDFPreExport
:snapshot="snapshotInfo"
:panel-name="panelInfo.name"
:template-content="pdfTemplateContent"
@closePreExport="closePreExport"
/>
</el-dialog>
<keep-alive>
<app-export-form
ref="appExportForm"
@downLoadApp="downLoadApp"
/>
</keep-alive>
</el-row>
</template>
<script>
@ -287,6 +329,7 @@ import SaveToTemplate from '@/views/panel/list/SaveToTemplate'
import { mapState } from 'vuex'
import html2canvas from 'html2canvasde'
import FileSaver from 'file-saver'
import JSZip from 'jszip'
import { starStatus, saveEnshrine, deleteEnshrine } from '@/api/panel/enshrine'
import bus from '@/utils/bus'
import { queryAll } from '@/api/panel/pdfTemplate'
@ -296,10 +339,11 @@ import { proxyInitPanelData } from '@/api/panel/shareProxy'
import { dataURLToBlob, getNowCanvasComponentData } from '@/components/canvas/utils/utils'
import { findResourceAsBase64 } from '@/api/staticResource/staticResource'
import PanelDetailInfo from '@/views/panel/list/common/PanelDetailInfo'
import AppExportForm from '@/views/panel/list/AppExportForm'
export default {
name: 'PanelViewShow',
components: { PanelDetailInfo, Preview, SaveToTemplate, PDFPreExport, ShareHead },
components: { AppExportForm, PanelDetailInfo, Preview, SaveToTemplate, PDFPreExport, ShareHead },
props: {
activeTab: {
type: String,
@ -320,6 +364,7 @@ export default {
hasStar: false,
fullscreen: false,
pdfExportShow: false,
appExportShow: false,
snapshotInfo: '',
showType: 0,
dataLoading: false,
@ -385,6 +430,9 @@ export default {
bus.$off('set-panel-share-user', this.setPanelShareUser)
},
methods: {
downLoadApp(appAttachInfo) {
this.downLoadToApp(appAttachInfo)
},
setPanelShowType(type) {
this.showType = type || 0
},
@ -458,10 +506,11 @@ export default {
_this.dataLoading = false
}
},
saveAppFile(appAttachInfo) {
saveAppFile(appRelationInfo, appAttachInfo) {
const _this = this
_this.dataLoading = true
try {
const jsZip = new JSZip()
_this.findStaticSource(function(staticResource) {
html2canvas(document.getElementById(_this.canvasInfoTemp)).then(canvas => {
_this.dataLoading = false
@ -473,11 +522,19 @@ export default {
snapshot: snapshot,
panelStyle: JSON.stringify(_this.canvasStyleData),
panelData: JSON.stringify(_this.componentData),
dynamicData: JSON.stringify(_this.panelViewDetailsInfo),
staticResource: JSON.stringify(staticResource || {})
}
appAttachInfo['panelInfo'] = JSON.stringify(panelInfo)
const blob = new Blob([JSON.stringify(appAttachInfo)], { type: '' })
FileSaver.saveAs(blob, _this.$store.state.panel.panelInfo.name + '-APP.DEAPP')
const blobTemplate = new Blob([JSON.stringify(panelInfo)], { type: '' })
const blobRelation = new Blob([JSON.stringify(appRelationInfo)], { type: '' })
const blobAppInfo = new Blob([JSON.stringify(appAttachInfo)], { type: '' })
jsZip.file('TEMPLATE.DET', blobTemplate, { binary: true })
jsZip.file('DATA_RELATION.DE', blobRelation, { binary: true })
jsZip.file('APP.json', blobAppInfo, { binary: true })
jsZip.generateAsync({ type: 'blob' }).then(content => {
//
FileSaver.saveAs(content, appAttachInfo.appName + '.zip') // file-saver
})
}
})
})
@ -486,11 +543,21 @@ export default {
_this.dataLoading = false
}
},
downLoadToApp() {
downLoadToAppPre() {
this.$refs.appExportForm.init({
appName: this.$store.state.panel.panelInfo.name,
icon: null,
version: '1.0',
creator: this.$store.getters.user.nickName,
required: '1.16.0',
description: null
})
},
downLoadToApp(appAttachInfo) {
this.dataLoading = true
export2AppCheck(this.$store.state.panel.panelInfo.id).then(rsp => {
if (rsp.data.checkStatus) {
this.saveAppFile(rsp.data)
this.saveAppFile(rsp.data, appAttachInfo)
} else {
this.dataLoading = false
this.$message({

View File

@ -5,8 +5,9 @@ import { COMMON_BACKGROUND_BASE } from '@/components/canvas/custom-component/com
export const TAB_COMMON_STYLE = {
headFontColor: '#000000',
headFontActiveColor: '#000000',
headBorderColor: null,
headBorderActiveColor: null
headBorderColor: '#ffffff',
headBorderActiveColor: '#ffffff',
headPosition: 'left'
}
export const FILTER_COMMON_STYLE = {

View File

@ -293,7 +293,7 @@
class="schema-label"
>
<template slot="label">
{{ $t('datasource.schema') }}
<span class="name">{{ $t('datasource.schema') }}<i class="required" /></span>
<el-button
type="text"
icon="el-icon-plus"
@ -307,6 +307,8 @@
filterable
:placeholder="$t('fu.search_bar.please_select')"
class="de-select"
@change="validatorSchema"
@blur="validatorSchema"
>
<el-option
v-for="item in schemas"
@ -315,6 +317,12 @@
:value="item"
/>
</el-select>
<div
v-if="configurationSchema"
class="el-form-item__error"
>
{{ $t('datasource.please_choose_schema') }}
</div>
</el-form-item>
<el-form-item
@ -911,6 +919,7 @@ export default {
]
},
api_table_title: '',
configurationSchema: false,
schemas: [],
showEmpty: false,
canEdit: false,
@ -1005,9 +1014,10 @@ export default {
certinKey: false
}
},
watch: {},
created() {},
methods: {
validatorSchema() {
this.configurationSchema = !this.form.configuration.schema
},
getSchema() {
this.$refs.DsConfig.validate((valid) => {
if (valid) {
@ -1617,4 +1627,20 @@ export default {
}
}
}
.schema-label {
::v-deep.el-form-item__label {
display: flex;
justify-content: space-between;
&::after {
display: none;
}
.name {
.required::after {
content: "*";
color: #f54a45;
margin-left: 2px;
}
}
}
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div
v-loading="formLoading"
v-loading="positionCheck('datasource')?formLoading:false"
:class="positionCheck('datasource')?'de-ds-form':'de-ds-form-app'"
>
<div
@ -87,7 +87,7 @@
>
<treeselect
v-model="attachForm.panelGroupPid"
:disabled="!(formType === 'add' ? true : hasDataPermission('manage', outerParams.panelPrivileges))"
:disabled="baseInfoDisabledCheck(outerParams.panelPrivileges)"
:clearable="false"
:options="panelGroupList"
:normalizer="normalizer"
@ -103,7 +103,7 @@
>
<el-input
v-model="attachForm.panelName"
:disabled="!(formType === 'add' ? true : hasDataPermission('manage', outerParams.panelPrivileges))"
:disabled="baseInfoDisabledCheck(outerParams.panelPrivileges)"
/>
</el-form-item>
<el-form-item
@ -112,7 +112,7 @@
>
<treeselect
v-model="attachForm.datasetGroupPid"
:disabled="!(formType === 'add' ? true : hasDataPermission('manage', outerParams.datasetPrivileges))"
:disabled="baseInfoDisabledCheck(outerParams.datasetPrivileges)"
:clearable="false"
:options="datasetGroupList"
:normalizer="normalizer"
@ -128,7 +128,7 @@
>
<el-input
v-model="attachForm.datasetGroupName"
:disabled="!(formType === 'add' ? true : hasDataPermission('manage', outerParams.panelPrivileges))"
:disabled="baseInfoDisabledCheck(outerParams.datasetPrivileges)"
/>
</el-form-item>
</el-form>
@ -138,13 +138,7 @@
:model="form"
:rules="rule"
size="small"
:disabled="
params &&
params.id &&
params.showModel &&
params.showModel === 'show' &&
!canEdit
"
:disabled="disabled"
class="de-form-item"
label-width="180px"
label-position="right"
@ -218,13 +212,7 @@
ref="dsConfig"
:datasource-type="datasourceType"
:form="form"
:disabled="
params &&
params.id &&
params.showModel &&
params.showModel === 'show' &&
!canEdit
"
:disabled="disabled"
/>
<plugin-com
v-if="datasourceType.isPlugin"
@ -306,6 +294,7 @@ import msgCfm from '@/components/msgCfm'
import { dsGroupTree } from '@/api/dataset/dataset'
import { appApply, appEdit, groupTree } from '@/api/panel/panel'
import { deepCopy } from '@/components/canvas/utils/utils'
import { hasDataPermission } from '@/utils/permission'
export default {
name: 'DsForm',
@ -587,7 +576,9 @@ export default {
this.queryTreeData()
let { id, showModel, type, name } = this.$route.query
this.params = this.$route.query
if (this.positionCheck('appMarket')) {
const appMarketCheck = this.positionCheck('appMarket')
if (appMarketCheck) {
this.appMarketEdit = this.outerParams.appMarketEdit === undefined ? true : this.outerParams.appMarketEdit
id = this.outerParams.datasourceId
showModel = this.outerParams.showModel
type = this.outerParams.datasourceType
@ -615,16 +606,18 @@ export default {
this.changeType(true)
} else {
this.canEdit = true
this.disabled = false
if (type) {
this.typeMap = name
this.setType()
this.changeType()
}
}
this.disabled = Boolean(id) && showModel === 'show' && !this.canEdit
this.disabled = appMarketCheck ? !this.appMarketEdit : (Boolean(id) && showModel === 'show' && !this.canEdit)
},
methods: {
baseInfoDisabledCheck(privileges) {
return !(this.formType === 'add' ? true : hasDataPermission('manage', privileges))
},
normalizer(node) {
// children=null
if (node.children === null || node.children === 'null') {
@ -661,8 +654,11 @@ export default {
})
},
getDatasourceDetail(id, showModel) {
this.formLoading = true
return getDatasourceDetail(id).then((res) => {
this.params = { ...res.data, showModel }
}).finally(() => {
this.formLoading = false
})
},
queryTreeData() {
@ -717,12 +713,6 @@ export default {
changeEdit() {
this.canEdit = true
this.formType = 'modify'
this.disabled =
this.params &&
this.params.id &&
this.params.showModel &&
this.params.showModel === 'show' &&
!this.canEdit
},
edit(row) {
this.formType = 'modify'
@ -739,12 +729,6 @@ export default {
this.form.configuration = JSON.parse(this.form.configuration)
this.originConfiguration = JSON.stringify(this.form.configuration)
}
this.disabled =
this.params &&
this.params.id &&
this.params.showModel &&
this.params.showModel === 'show' &&
!this.canEdit
this.changeEdit()
},
reset() {
@ -1062,7 +1046,7 @@ export default {
} else {
this.openMessageSuccess(
res.message.substring(0, 2500) + '......',
'danger'
'error'
)
}
}
@ -1082,7 +1066,7 @@ export default {
} else {
this.openMessageSuccess(
res.message.substring(0, 2500) + '......',
'danger'
'error'
)
}
}