Merge branch 'dev' into pr@dev_one_dot_x

This commit is contained in:
dataeaseShu 2023-11-06 10:01:44 +08:00
commit 44eac3c9dd
70 changed files with 1120 additions and 268 deletions

View File

@ -7,6 +7,11 @@
<a href="https://github.com/dataease/dataease"><img src="https://img.shields.io/github/stars/dataease/dataease?color=%231890FF&style=flat-square" alt="Stars"></a>
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2F1dataease%2Fdataease?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2Fdataease%2Fdataease.svg?type=shield" alt="FOSSA Status"></a>
</p>
|说明|
|------------------|
|此分支为 DataEase v1.18 版本的开发分支。[DataEase v2.0.0](https://github.com/dataease/dataease/releases/tag/v2.0.0) 也已经正式发布v2 版本的开发分支为 [dev-v2](https://github.com/dataease/dataease/tree/dev-v2)。v2 版本正在快速迭代中,如是在生产环境部署 DataEase建议继续使用 v1.18.* 的最新稳定版本。|
<hr/>
## 什么是 DataEase

View File

@ -67,6 +67,10 @@ public class IndexController {
if (StringUtils.isNotEmpty(attachParams)) {
url = url + "&attachParams=" + attachParams;
}
String fromLink = request.getParameter("fromLink");
if (StringUtils.isNotEmpty(fromLink)) {
url = url + "&fromLink=" + fromLink;
}
response.sendRedirect(url);
} catch (IOException e) {
LogUtil.error(e.getMessage());

View File

@ -53,6 +53,7 @@ public class SysLogController {
@ApiOperation("导出操作日志")
@PostMapping("/export")
@ApiImplicitParam(name = "request", value = "查询条件", required = true)
@SqlInjectValidator(value = {"time"})
public void export(@RequestBody LogGridRequest request) throws Exception {
logService.exportExcel(request);
}

View File

@ -653,7 +653,7 @@ public class DorisQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {
@ -1187,7 +1187,7 @@ public class DorisQueryProvider extends QueryProvider {
} else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) {
if (request.getDatasetTableField().getDeType() == 1) {
if (request.getDatasetTableField().getDeExtractType() == 1) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String startTime = simpleDateFormat.format(new Date(Long.parseLong(value.get(0))));
String endTime = simpleDateFormat.format(new Date(Long.parseLong(value.get(1))));
whereValue = String.format(DorisConstants.WHERE_BETWEEN, startTime, endTime);

View File

@ -602,7 +602,7 @@ public class MysqlQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -633,7 +633,7 @@ public class CKQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -621,7 +621,7 @@ public class Db2QueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -627,7 +627,7 @@ public class EsQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -586,7 +586,7 @@ public class HiveQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -573,7 +573,7 @@ public class ImpalaQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -557,7 +557,7 @@ public class MongoQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -7,6 +7,7 @@ import io.dataease.plugins.common.base.domain.DatasetTableFieldExample;
import io.dataease.plugins.common.base.domain.Datasource;
import io.dataease.plugins.common.base.mapper.DatasetTableFieldMapper;
import io.dataease.plugins.common.constants.DeTypeConstants;
import io.dataease.plugins.common.constants.datasource.DorisConstants;
import io.dataease.plugins.common.constants.datasource.MySQLConstants;
import io.dataease.plugins.common.constants.datasource.SQLConstants;
import io.dataease.plugins.common.constants.engine.MysqlConstants;
@ -160,6 +161,19 @@ public class MysqlQueryProvider extends QueryProvider {
.tableAlias(String.format(TABLE_ALIAS_PREFIX, 0))
.build();
List<SQLObj> xFields = new ArrayList<>();
int originSize = fields.size();
List<String> fieldList = fields.stream().map(DatasetTableField::getId).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(sortFields)) {
sortFields.forEach(item -> {
int indexOf = fieldList.indexOf(item.getId());
if (indexOf == -1) {
fields.add(item);
} else {
fields.set(indexOf, item);
}
});
}
List<SQLObj> xOrders = new ArrayList<>();
if (CollectionUtils.isNotEmpty(fields)) {
for (int i = 0; i < fields.size(); i++) {
DatasetTableField f = fields.get(i);
@ -212,6 +226,14 @@ public class MysqlQueryProvider extends QueryProvider {
.fieldName(fieldName)
.fieldAlias(fieldAlias)
.build());
if (f instanceof DeSortField) {
DeSortField x = (DeSortField) f;
xOrders.add(SQLObj.builder()
.orderField(originField)
.orderAlias(fieldAlias)
.orderDirection(x.getOrderDirection())
.build());
}
}
}
@ -229,20 +251,27 @@ public class MysqlQueryProvider extends QueryProvider {
if (whereTrees != null) wheres.add(whereTrees);
if (CollectionUtils.isNotEmpty(wheres)) st_sql.add("filters", wheres);
List<SQLObj> xOrders = new ArrayList<>();
if (CollectionUtils.isNotEmpty(sortFields)) {
int step = fields.size();
for (int i = step; i < (step + sortFields.size()); i++) {
DeSortField deSortField = sortFields.get(i - step);
SQLObj order = buildSortField(deSortField, tableObj, i);
xOrders.add(order);
}
}
if (ObjectUtils.isNotEmpty(xOrders)) {
st_sql.add("orders", xOrders);
}
String sql = st_sql.render();
ST st = stg.getInstanceOf("previewSql");
st.add("isGroup", false);
SQLObj tableSQL = SQLObj.builder()
.tableName(String.format(DorisConstants.BRACKETS, sql))
.tableAlias(String.format(TABLE_ALIAS_PREFIX, 1))
.build();
st.add("table", tableSQL);
return st_sql.render();
List<SQLObj> outFieldList = new ArrayList<>();
for (int i = 0; i < originSize; i++) {
SQLObj fieldObj = xFields.get(i);
String outFieldAlias = tableSQL.getTableAlias() + "." + fieldObj.getFieldAlias();
outFieldList.add(SQLObj.builder().fieldName(outFieldAlias).fieldAlias(fieldObj.getFieldAlias()).build());
}
st.add("groups", outFieldList);
if (CollectionUtils.isNotEmpty(xOrders)) {
st.add("orders", xOrders);
return st.render() + " LIMIT 0, 10000000";
}
return st.render();
}
@Override
@ -611,7 +640,7 @@ public class MysqlQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -676,7 +676,7 @@ public class OracleQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -614,7 +614,7 @@ public class PgQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -621,7 +621,7 @@ public class RedshiftQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -623,7 +623,7 @@ public class SqlserverQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -913,6 +913,9 @@ public class ChartViewService {
ChartDrillRequest head = drillRequestList.get(0);
Map<String, String> dimValMap = new HashMap<>();
head.getDimensionList().forEach(item -> dimValMap.put(item.getId(), item.getValue()));
boolean isAntVScatterNumberXAxis = CollectionUtils.isNotEmpty(xAxis) && StringUtils.equals(xAxis.get(0).getGroupType(), "q") && StringUtils.equalsIgnoreCase(view.getRender(), "antv");
for (int i = 0; i < drillRequestList.size(); i++) {
ChartDrillRequest request = drillRequestList.get(i);
ChartViewFieldDTO chartViewFieldDTO = drill.get(i);
@ -924,14 +927,23 @@ public class ChartViewService {
dimValMap.put(requestDimension.getId(), requestDimension.getValue());
if (!checkDrillExist(xAxis, extStack, requestDimension.getId(), view)) {
chartFieldMap.put(chartViewFieldDTO.getId(), chartViewFieldDTO);
xAxis.add(chartViewFieldDTO);
if (isAntVScatterNumberXAxis) {
extStack.add(chartViewFieldDTO);
} else {
xAxis.add(chartViewFieldDTO);
}
}
if (i == drillRequestList.size() - 1) {
ChartViewFieldDTO nextDrillField = drill.get(i + 1);
if (!checkDrillExist(xAxis, extStack, nextDrillField.getId(), view)) {
// get drill list first element's sort,then assign to nextDrillField
nextDrillField.setSort(getDrillSort(xAxis, drill.get(0)));
xAxis.add(nextDrillField);
if (isAntVScatterNumberXAxis) {
extStack.add(nextDrillField);
} else {
xAxis.add(nextDrillField);
}
}
}
}
@ -1250,8 +1262,15 @@ public class ChartViewService {
// 同比/环比计算通过对比类型和数据设置计算出对应指标的结果然后替换结果data数组中的对应元素
// 如果因维度变化如时间字段缺失时间字段的展示格式变化导致无法计算结果的则结果data数组中的对应元素全置为null
// 根据不同图表类型获得需要替换的指标index array
for (int i = 0; i < yAxis.size(); i++) {
ChartViewFieldDTO chartViewFieldDTO = yAxis.get(i);
List<ChartViewFieldDTO> tempYAxis = new ArrayList<>();
if (CollectionUtils.isNotEmpty(xAxis) && StringUtils.equals(xAxis.get(0).getGroupType(), "q") && StringUtils.equalsIgnoreCase(view.getRender(), "antv")) {
//针对散点图scatter处理
tempYAxis.add(xAxis.get(0));
}
tempYAxis.addAll(yAxis);
for (int i = 0; i < tempYAxis.size(); i++) {
ChartViewFieldDTO chartViewFieldDTO = tempYAxis.get(i);
ChartFieldCompareDTO compareCalc = chartViewFieldDTO.getCompareCalc();
if (ObjectUtils.isEmpty(compareCalc)) {
continue;
@ -1649,6 +1668,20 @@ public class ChartViewService {
}
private boolean checkDrillExist(List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> extStack, String fieldId, ChartViewWithBLOBs view) {
if (CollectionUtils.isNotEmpty(xAxis)) {
//针对判断 antv 散点图
if (StringUtils.equals(xAxis.get(0).getGroupType(), "q") && StringUtils.equalsIgnoreCase(view.getRender(), "antv")) {
if (CollectionUtils.isNotEmpty(extStack)) {
for (ChartViewFieldDTO x : extStack) {
if (StringUtils.equalsIgnoreCase(x.getId(), fieldId)) {
return true;
}
}
}
}
}
if (CollectionUtils.isNotEmpty(xAxis)) {
for (ChartViewFieldDTO x : xAxis) {
if (StringUtils.equalsIgnoreCase(x.getId(), fieldId)) {
@ -2122,7 +2155,7 @@ public class ChartViewService {
JSONObject jsonObject = JSONObject.parseObject(senior);
List<ChartSeniorAssistDTO> list = new ArrayList<>();
JSONObject threshold = jsonObject.getJSONObject("threshold");
if (ObjectUtils.isEmpty(threshold) || StringUtils.isBlank(threshold.toJSONString())){
if (ObjectUtils.isEmpty(threshold) || StringUtils.isBlank(threshold.toJSONString())) {
return list;
}
JSONArray tableThreshold = threshold.getJSONArray("tableThreshold");
@ -2154,7 +2187,7 @@ public class ChartViewService {
return list;
}
private boolean solveThresholdCondition(ChartSeniorAssistDTO fieldDTO, String tableId){
private boolean solveThresholdCondition(ChartSeniorAssistDTO fieldDTO, String tableId) {
String fieldId = fieldDTO.getFieldId();
String summary = fieldDTO.getSummary();
if (StringUtils.isEmpty(fieldId) || StringUtils.isEmpty(summary)) {
@ -2170,7 +2203,7 @@ public class ChartViewService {
return true;
}
private List<ChartSeniorAssistDTO> getConditionFields(ChartSeniorThresholdDTO condition){
private List<ChartSeniorAssistDTO> getConditionFields(ChartSeniorThresholdDTO condition) {
List<ChartSeniorAssistDTO> list = new ArrayList<>();
if (StringUtils.equalsIgnoreCase(condition.getField(), "0")) {
return list;

View File

@ -313,7 +313,7 @@ public class ChartDataBuild {
String[] row = data.get(i1);
StringBuilder a = new StringBuilder();
if (isDrill) {
if (isDrill && !xIsNumber) {
a.append(row[extGroupList.size() + xAxis.size() - 1]);
} else {
for (int i = extGroupList.size(); i < extGroupList.size() + xAxis.size(); i++) {
@ -329,7 +329,12 @@ public class ChartDataBuild {
AxisChartDataAntVDTO axisChartDataDTO = new AxisChartDataAntVDTO();
if (xIsNumber) {
axisChartDataDTO.setX(new BigDecimal(a.toString()));
Object v = a.toString();
try {
v = new BigDecimal(a.toString());
} catch (Exception ignore) {
}
axisChartDataDTO.setX(v);
} else {
axisChartDataDTO.setX(a.toString());
}
@ -340,11 +345,20 @@ public class ChartDataBuild {
List<ChartDimensionDTO> dimensionList = new ArrayList<>();
List<ChartQuotaDTO> quotaList = new ArrayList<>();
for (int j = 0; j < xAxis.size(); j++) {
ChartDimensionDTO chartDimensionDTO = new ChartDimensionDTO();
chartDimensionDTO.setId(xAxis.get(j).getId());
chartDimensionDTO.setValue(row[j]);
dimensionList.add(chartDimensionDTO);
if (xIsNumber && CollectionUtils.isNotEmpty(extGroupList)) {
for (int j = 0; j < extGroupList.size(); j++) {
ChartDimensionDTO chartDimensionDTO = new ChartDimensionDTO();
chartDimensionDTO.setId(extGroupList.get(j).getId());
chartDimensionDTO.setValue(row[j]);
dimensionList.add(chartDimensionDTO);
}
} else {
for (int j = 0; j < xAxis.size(); j++) {
ChartDimensionDTO chartDimensionDTO = new ChartDimensionDTO();
chartDimensionDTO.setId(xAxis.get(j).getId());
chartDimensionDTO.setValue(row[j]);
dimensionList.add(chartDimensionDTO);
}
}
axisChartDataDTO.setDimensionList(dimensionList);
@ -360,7 +374,11 @@ public class ChartDataBuild {
}
if (CollectionUtils.isNotEmpty(extGroup) && xIsNumber) { //有分组时其实就是第一个
axisChartDataDTO.setCategory(row[0]);
if (isDrill) {
axisChartDataDTO.setCategory(row[extGroupList.size() - 1]);
} else {
axisChartDataDTO.setCategory(row[0]);
}
} else {
axisChartDataDTO.setCategory(yAxis.get(j).getName());
}
@ -983,7 +1001,7 @@ public class ChartDataBuild {
}
}
if (xIsNumber && CollectionUtils.isNotEmpty(extStack)) {
fields.add(extStack.get(0));
fields.addAll(extStack);
}
if (xIsNumber) {
@ -1051,30 +1069,18 @@ public class ChartDataBuild {
// 表格
public static Map<String, Object> transTableNormal(Map<String, List<ChartViewFieldDTO>> fieldMap, ChartViewWithBLOBs view, List<String[]> data, Map<String, ColumnPermissionItem> desensitizationList) {
String[] keys = new String[]{"labelAxis", "tooltipAxis"};
List<ChartViewFieldDTO> fields = new ArrayList<>();
List<ChartViewFieldDTO> yfields = new ArrayList<>();
if (CollectionUtils.isNotEmpty(fieldMap.get("xAxis"))) fields.addAll(fieldMap.get("xAxis"));
if (CollectionUtils.isNotEmpty(fieldMap.get("tooltipAxis"))) {
fieldMap.get("tooltipAxis").forEach(field -> {
Integer deType = field.getDeType();
if (deType == 2 || deType == 3) {
yfields.add(field);
} else {
fields.add(field);
}
});
}
if (CollectionUtils.isNotEmpty(fieldMap.get("labelAxis"))) {
fieldMap.get("labelAxis").forEach(field -> {
Integer deType = field.getDeType();
if (deType == 2 || deType == 3) {
yfields.add(field);
} else {
fields.add(field);
}
});
for (Map.Entry<String, List<ChartViewFieldDTO>> entry : fieldMap.entrySet()) {
if (StringUtils.equalsAny(entry.getKey(), keys)) {
fields.addAll(entry.getValue());
}
}
if (CollectionUtils.isNotEmpty(fieldMap.get("yAxis"))) fields.addAll(fieldMap.get("yAxis"));
if (CollectionUtils.isNotEmpty(yfields)) fields.addAll(yfields);
return transTableNormal(fields, view, data, desensitizationList);

View File

@ -60,16 +60,15 @@ public class StaticResourceService {
}
private boolean isImage(MultipartFile file) {
BufferedImage image = null;
try (InputStream input = file.getInputStream()) {
image = ImageIO.read(input);
ImageIO.read(input);
} catch (IOException e) {
LogUtil.error(e.getMessage(), e);
return false;
}
Pattern pattern = Pattern.compile("\\.(png|jpg|jpeg|gif)$");
Pattern pattern = Pattern.compile("\\.(png|jpg|jpeg|gif|svg)$");
Matcher matcher = pattern.matcher(file.getOriginalFilename().toLowerCase());
if (image == null || image.getWidth() <= 0 || image.getHeight() <= 0 || !matcher.find()) {
if (!matcher.find()) {
return false;
}

View File

@ -26,8 +26,17 @@
},
"dependencies": {
"@antv/g2plot": "^2.4.9",
"@antv/l7": "^2.15.0",
"@antv/s2": "^1.49.1",
"@antv/l7": "2.15.0",
"@antv/l7-component": "2.15.0",
"@antv/l7-core": "2.15.0",
"@antv/l7-layers": "2.15.0",
"@antv/l7-maps": "2.15.0",
"@antv/l7-renderer": "2.15.0",
"@antv/l7-scene": "2.15.0",
"@antv/l7-source": "2.15.0",
"@antv/l7-utils": "2.15.0",
"@antv/s2": "1.49.1",
"@antv/util": "^2.0.17",
"@riophae/vue-treeselect": "0.4.0",
"@tinymce/tinymce-vue": "^3.2.8",
"axios": "^0.21.3",
@ -63,6 +72,7 @@
"svgo": "1.2.2",
"tinymce": "^5.8.2",
"umy-ui": "^1.1.6",
"vant": "^2.13.2",
"vue": "2.6.10",
"vue-clipboard2": "0.3.1",
"vue-codemirror": "^4.0.6",

View File

@ -33,6 +33,7 @@
const user = getQueryVariable('user')
const terminal = getQueryVariable('terminal')
const attachParams = getQueryVariable('attachParams')
const fromLink = getQueryVariable('fromLink')
const baseUrl = window.location.pathname.replace('link.html', '')
let url = baseUrl + "#/delink?link=" + encodeURIComponent(link)
if (terminal) {
@ -44,6 +45,9 @@
if (attachParams) {
url += '&attachParams=' + encodeURIComponent(attachParams)
}
if (fromLink) {
url += '&fromLink=' + fromLink
}
window.location.href = url
</script>

View File

@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/>
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
</head>
<body>
<div id="app-mobile"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -134,6 +134,16 @@
@change="showGridChange"
/>
</el-dropdown-item>
<el-dropdown-item>
<span class="icon iconfont icon-adaptor icon16" />
<span class="text14 margin-left8">{{ $t('panel.auto_size_adaptor') }}</span>
<el-switch
v-model="autoSizeAdaptorSwitch"
:class="[{['grid-active']: autoSizeAdaptorSwitch},'margin-left8']"
size="mini"
@change="showSizeAdaptorSwitchChange"
/>
</el-dropdown-item>
<el-dropdown-item @click.native="openOuterParamsSet">
<span class="icon iconfont icon-icon-quicksetting icon16" />
<span class="text14 margin-left8">{{ $t('panel.params_setting') }}</span>
@ -192,7 +202,7 @@
@click="batchOption"
><span
class="icon-font-margin"
>{{ batchOptStatus?$t('panel.cancel_batch_opt'):$t('panel.batch_opt') }}</span></span>
>{{ batchOptStatus ? $t('panel.cancel_batch_opt') : $t('panel.batch_opt') }}</span></span>
<span style="float: right;margin-right: 24px">
<el-button
size="mini"
@ -264,6 +274,7 @@ import { getPanelAllLinkageInfo, saveLinkage } from '@/api/panel/linkage'
import bus from '@/utils/bus'
import { queryPanelJumpInfo } from '@/api/panel/linkJump'
import { inOtherPlatform } from '@/utils/index'
export default {
name: 'Toolbar',
props: {
@ -274,6 +285,7 @@ export default {
return {
showPageLine: false,
showGridSwitch: false,
autoSizeAdaptorSwitch: true,
mobileLayoutInitStatus: false,
isShowPreview: false,
needToChange: [
@ -330,13 +342,16 @@ export default {
eventBus.$on('checkAndSave', this.checkAndSave)
eventBus.$on('clearCanvas', this.clearCanvas)
bus.$on('onSubjectChange', this.editPanelInit)
bus.$on('editSave', this.mobileLayoutSave)
this.scale = this.canvasStyleData.scale
this.mobileLayoutInitStatus = this.mobileLayoutStatus
this.showGridSwitch = this.canvasStyleData.aidedDesign.showGrid
this.autoSizeAdaptorSwitch = this.canvasStyleData.autoSizeAdaptor || true
this.showPageLine = this.canvasStyleData.pdfPageLine?.showPageLine
this.autoCache()
},
beforeDestroy() {
bus.$off('editSave', this.mobileLayoutSave)
eventBus.$off('preview', this.preview)
eventBus.$off('checkAndSave', this.checkAndSave)
eventBus.$off('clearCanvas', this.clearCanvas)
@ -623,6 +638,11 @@ export default {
this.$store.commit('canvasChange')
this.canvasStyleData.aidedDesign.showGrid = !this.canvasStyleData.aidedDesign.showGrid
},
showSizeAdaptorSwitchChange() {
this.$store.commit('canvasChange')
this.canvasStyleData.autoSizeAdaptor = !this.canvasStyleData.autoSizeAdaptor
eventBus.$emit('componentSizeAdaptorChange')
},
showPageLineChange() {
this.$store.commit('canvasChange')
this.canvasStyleData.pdfPageLine.showPageLine = !this.canvasStyleData.pdfPageLine.showPageLine
@ -636,13 +656,14 @@ export default {
openMobileLayout(switchVal) {
if (switchVal) {
this.$store.commit('openMobileLayout')
bus.$emit('mobile-status-change', 'openMobileLayout', this.componentData)
} else {
this.mobileLayoutSave()
}
},
editSave() {
if (this.mobileLayoutStatus) {
this.mobileLayoutSave()
bus.$emit('mobile-status-change', 'editSave')
} else {
this.saveLinkage()
}
@ -651,6 +672,9 @@ export default {
this.$store.commit('setComponentData', JSON.parse(this.componentDataCache))
this.$store.commit('setMobileLayoutStatus', false)
this.$store.commit('openMobileLayout')
if (this.mobileLayoutStatus) {
bus.$emit('mobile-status-change', 'reset', JSON.parse(this.componentDataCache))
}
},
editCancel() {
if (this.mobileLayoutStatus) {

View File

@ -12,7 +12,7 @@
>
<el-button-group size="mini">
<el-button
v-if="!isNewBlank"
v-if="fromLink"
size="mini"
type="button"
@click="back2Last"
@ -89,8 +89,8 @@ export default {
isPublicLink() {
return this.$router.currentRoute.path === '/delink'
},
isNewBlank() {
return window.history.length === 1
fromLink() {
return this.$route.query.fromLink === 'true'
},
containerClass() {
return this.isPublicLink ? 'trans-pc' : 'bar-main'

View File

@ -40,6 +40,7 @@
:style="getComponentStyleDefault(config.style)"
style="overflow: hidden"
:out-style="config.style"
:terminal="terminal"
:is-relation="isRelation"
:element="config"
:in-screen="inScreen"

View File

@ -150,13 +150,13 @@
</template>
<script>
import { mapState } from 'vuex'
import {mapState} from 'vuex'
import Shape from './Shape'
import DeDrag from '@/components/deDrag'
// eslint-disable-next-line no-unused-vars
import { getComponentRotatedStyle, getStyle } from '@/components/canvas/utils/style'
import { _$, imgUrlTrans } from '@/components/canvas/utils/utils'
import {getComponentRotatedStyle, getStyle} from '@/components/canvas/utils/style'
import {_$, imgUrlTrans} from '@/components/canvas/utils/utils'
import ContextMenu from './ContextMenu'
import MarkLine from './MarkLine'
import Area from './Area'
@ -164,13 +164,13 @@ import eventBus from '@/components/canvas/utils/eventBus'
import Grid from './Grid'
import PageLineEditor from './PageLineEditor'
import PGrid from './PGrid'
import { changeStyleWithScale } from '@/components/canvas/utils/translate'
import {changeStyleWithScale} from '@/components/canvas/utils/translate'
import UserViewDialog from '@/components/canvas/customComponent/UserViewDialog'
import DeOutWidget from '@/components/dataease/DeOutWidget'
import DragShadow from '@/components/deDrag/Shadow'
import bus from '@/utils/bus'
import LinkJumpSet from '@/views/panel/linkJumpSet'
import { buildFilterMap, buildViewKeyMap, formatCondition, valueValid, viewIdMatch } from '@/utils/conditionUtil'
import {buildFilterMap, buildViewKeyMap, formatCondition, valueValid, viewIdMatch} from '@/utils/conditionUtil'
//
import _ from 'lodash'
import _jq from 'jquery'
@ -190,11 +190,11 @@ let itemMaxX = 0
function debounce(func, time) {
if (!isOverlay) {
(function(t) {
(function (t) {
isOverlay = true
setTimeout(function() {
setTimeout(function () {
t()
setTimeout(function() {
setTimeout(function () {
isOverlay = false
if (lastTask !== undefined) {
debounce(lastTask, time)
@ -319,10 +319,10 @@ function init() {
resetPositionBox.call(this)
initPosition(this)
let i = 0
const timeid = setInterval(function() {
const timeid = setInterval(function () {
if (i >= vm.yourList.length) {
clearInterval(timeid)
vm.$nextTick(function() {
vm.$nextTick(function () {
vm.moveAnimate = true
})
} else {
@ -339,7 +339,7 @@ function resizePlayer(item, newSize) {
removeItemFromPositionBox.call(vm, item)
const belowItems = findBelowItems.call(this, item)
_.forEach(belowItems, function(upItem) {
_.forEach(belowItems, function (upItem) {
const canGoUpRows = canItemGoUp.call(vm, upItem)
if (canGoUpRows > 0) {
moveItemUp.call(vm, upItem, canGoUpRows)
@ -426,7 +426,7 @@ function movePlayer(item, position) {
removeItemFromPositionBox.call(vm, item)
const belowItems = findBelowItems.call(this, item)
_.forEach(belowItems, function(upItem) {
_.forEach(belowItems, function (upItem) {
const canGoUpRows = canItemGoUp.call(vm, upItem)
if (canGoUpRows > 0) {
moveItemUp.call(vm, upItem, canGoUpRows)
@ -452,7 +452,7 @@ function removeItem(index) {
removeItemFromPositionBox.call(vm, item)
const belowItems = findBelowItems.call(this, item)
_.forEach(belowItems, function(upItem) {
_.forEach(belowItems, function (upItem) {
const canGoUpRows = canItemGoUp.call(vm, upItem)
if (canGoUpRows > 0) {
moveItemUp.call(vm, upItem, canGoUpRows)
@ -544,7 +544,7 @@ function findClosetCoords(item, tCoord) {
y: collisionsItem[0].coord.el.y
})
setTimeout(function() {
setTimeout(function () {
isOverlay = false
}, 200)
}
@ -592,7 +592,7 @@ function changeItemCoord(item) {
el: item
}
const index = _.findIndex(vm.coordinates, function(o) {
const index = _.findIndex(vm.coordinates, function (o) {
return o.el._dragId === item._dragId
})
if (index !== -1) {
@ -609,7 +609,7 @@ function emptyTargetCell(item) {
const vm = this
const belowItems = findBelowItems.call(vm, item)
_.forEach(belowItems, function(downItem, index) {
_.forEach(belowItems, function (downItem, index) {
if (downItem._dragId === item._dragId) return
const moveSize = item.y + item.sizey - downItem.y
if (moveSize > 0) {
@ -649,7 +649,7 @@ function moveItemDown(item, size) {
const vm = this
removeItemFromPositionBox.call(vm, item)
const belowItems = findBelowItems.call(vm, item)
_.forEach(belowItems, function(downItem, index) {
_.forEach(belowItems, function (downItem, index) {
if (downItem._dragId === item._dragId) return
const moveSize = calcDiff.call(vm, item, downItem, size)
if (moveSize > 0) {
@ -722,7 +722,7 @@ function moveItemUp(item, size) {
changeItemCoord.call(this, item)
_.forEach(belowItems, function(upItem, index) {
_.forEach(belowItems, function (upItem, index) {
const moveSize = canItemGoUp.call(vm, upItem)
if (moveSize > 0) {
moveItemUp.call(vm, upItem, moveSize)
@ -806,19 +806,19 @@ export default {
dragStart: {
required: false,
type: Function,
default: function() {
default: function () {
}
},
dragging: {
required: false,
type: Function,
default: function() {
default: function () {
}
},
dragEnd: {
required: false,
type: Function,
default: function() {
default: function () {
}
},
resizable: {
@ -829,19 +829,19 @@ export default {
resizeStart: {
required: false,
type: Function,
default: function() {
default: function () {
}
},
resizing: {
required: false,
type: Function,
default: function() {
default: function () {
}
},
resizeEnd: {
required: false,
type: Function,
default: function() {
default: function () {
}
},
matrixCount: {
@ -1004,6 +1004,7 @@ export default {
return this.curCanvasScaleMap[this.canvasId]
},
...mapState([
'canvasStyleData',
'curComponent',
'editor',
'linkageSettingStatus',
@ -1116,6 +1117,7 @@ export default {
this.$store.commit('getEditor')
const _this = this
eventBus.$on('hideArea', this.hideArea)
eventBus.$on('componentSizeAdaptorChange', this.changeScale)
eventBus.$on('startMoveIn', this.startMoveIn)
bus.$on('onRemoveLastItem', this.removeLastItem)
bus.$on('trigger-search-button', this.triggerSearchButton)
@ -1132,6 +1134,7 @@ export default {
beforeDestroy() {
eventBus.$off('hideArea', this.hideArea)
eventBus.$off('startMoveIn', this.startMoveIn)
eventBus.$off('componentSizeAdaptorChange', this.changeScale)
bus.$off('onRemoveLastItem', this.removeLastItem)
bus.$off('trigger-search-button', this.triggerSearchButton)
bus.$off('refresh-button-info', this.refreshButtonInfo)
@ -1287,7 +1290,7 @@ export default {
}
return -1
},
pluginEditHandler({ e, id }) {
pluginEditHandler({e, id}) {
let index = -1
for (let i = 0; i < this.componentData.length; i++) {
const item = this.componentData[i]
@ -1397,12 +1400,12 @@ export default {
getSelectArea() {
const result = []
//
const { x, y } = this.start
const {x, y} = this.start
//
this.componentData.forEach(component => {
if (component.isLock) return
const { left, top, width, height } = component.style
const {left, top, width, height} = component.style
if (x <= left && y <= top && (left + width <= x + this.width) && (top + height <= y + this.height)) {
result.push(component)
}
@ -1458,7 +1461,7 @@ export default {
getTextareaHeight(element, text) {
// eslint-disable-next-line prefer-const
let { lineHeight, fontSize, height } = element.style
let {lineHeight, fontSize, height} = element.style
if (lineHeight === '') {
lineHeight = 1.5
}
@ -1523,8 +1526,8 @@ export default {
})
if (this.canvasId === 'canvas-main') {
this.$store.commit('setPreviewCanvasScale', {
scaleWidth: this.scalePointWidth,
scaleHeight: this.scalePointHeight
scaleWidth: this.canvasStyleData.autoSizeAdaptor ? this.scalePointWidth : 1,
scaleHeight: this.canvasStyleData.autoSizeAdaptor ? this.scalePointHeight : 1
})
}
}
@ -1549,7 +1552,7 @@ export default {
}
},
getRefLineParams(params) {
const { vLine, hLine } = params
const {vLine, hLine} = params
this.vLine = vLine
this.hLine = hLine
},
@ -1702,8 +1705,8 @@ export default {
newX = newX > 0 ? newX : 1
newY = newY > 0 ? newY : 1
if (item.sizex !== nowX || item.sizey !== nowY) {
debounce((function(newX, oldX, newY, oldY) {
return function() {
debounce((function (newX, oldX, newY, oldY) {
return function () {
if (newX !== oldX || oldY !== newY) {
movePlayer.call(vm, resizeItem, {
x: newX,
@ -1739,8 +1742,8 @@ export default {
return
}
if (newX !== oldX || oldY !== newY) {
debounce((function(newX, oldX, newY, oldY) {
return function() {
debounce((function (newX, oldX, newY, oldY) {
return function () {
if (newX !== oldX || oldY !== newY) {
movePlayer.call(vm, moveItem, {
x: newX,
@ -1778,7 +1781,7 @@ export default {
// 使copy
const finalList = []
const _this = this
_.forEach(this.componentData, function(item, index) {
_.forEach(this.componentData, function (item, index) {
if (_.isEmpty(item)) return
if (_this.canvasId === item.canvasId) {
delete item['_dragId']
@ -1820,7 +1823,7 @@ export default {
addItemBox(item) {
this.yourList.push(item)
this.$nextTick(function() {
this.$nextTick(function () {
addItem.call(this, item, this.yourList.length - 1)
})
},
@ -1851,7 +1854,7 @@ export default {
//
resizeParentBoundsRef() {
const _this = this
_this.componentData.forEach(function(data, index) {
_this.componentData.forEach(function (data, index) {
_this.$refs.deDragRef && _this.$refs.deDragRef[index] && _this.$refs.deDragRef[index].checkParentSize()
})
},

View File

@ -153,6 +153,7 @@
v-if="chart && showMapLayerController"
:chart="chart"
:series-id-map="seriesIdMap"
:show-edit-position="showEditPosition"
/>
</div>

View File

@ -13,6 +13,7 @@
<script>
import { mapState } from 'vuex'
import bus from '@/utils/bus'
export default {
props: {
@ -29,7 +30,8 @@ export default {
computed: {
...mapState([
'pcComponentData',
'pcComponentGap'
'pcComponentGap',
'mobileLayoutStatus'
])
},
mounted() {
@ -49,6 +51,7 @@ export default {
this.element.y = 200
this.element.auxiliaryMatrix = true
this.$store.commit('addComponent', { component: this.element })
bus.$emit('mobile-status-change', 'addComponent', { component: this.element })
} else {
this.deleteComponent()
}
@ -58,6 +61,9 @@ export default {
this.$emit('amRemoveItem')
this.$store.commit('deleteComponentWithId', this.element.id)
this.$store.commit('setCurComponent', { component: null, index: null })
if (this.mobileLayoutStatus) {
window.top.postMessage({ type: 'deleteComponentWithId', value: this.element.id }, '*')
}
},
updateMobileSelected(id, mobileSelected) {
this.pcComponentData.forEach(item => {

View File

@ -145,32 +145,31 @@
</template>
<script>
import {getStyle} from '@/components/canvas/utils/style'
import {mapState} from 'vuex'
import { getStyle } from '@/components/canvas/utils/style'
import { mapState } from 'vuex'
import ComponentWrapper from './ComponentWrapper'
import {changeStyleWithScale} from '@/components/canvas/utils/translate'
import {uuid} from 'vue-uuid'
import {deepCopy, imgUrlTrans} from '@/components/canvas/utils/utils'
import { changeStyleWithScale } from '@/components/canvas/utils/translate'
import { uuid } from 'vue-uuid'
import { deepCopy, imgUrlTrans } from '@/components/canvas/utils/utils'
import eventBus from '@/components/canvas/utils/eventBus'
import elementResizeDetectorMaker from 'element-resize-detector'
import CanvasOptBar from '@/components/canvas/components/editor/CanvasOptBar'
import bus from '@/utils/bus'
import {buildFilterMap, buildViewKeyMap, formatCondition, valueValid, viewIdMatch} from '@/utils/conditionUtil'
import {hasDataPermission} from '@/utils/permission'
import {activeWatermark} from '@/components/canvas/tools/watermark'
import {proxyUserLoginInfo, userLoginInfo} from '@/api/systemInfo/userLogin'
import { buildFilterMap, buildViewKeyMap, formatCondition, valueValid, viewIdMatch } from '@/utils/conditionUtil'
import { hasDataPermission } from '@/utils/permission'
import { activeWatermark } from '@/components/canvas/tools/watermark'
import { proxyUserLoginInfo, userLoginInfo } from '@/api/systemInfo/userLogin'
import html2canvas from 'html2canvasde'
import {queryAll} from '@/api/panel/pdfTemplate'
import { queryAll } from '@/api/panel/pdfTemplate'
import PDFPreExport from '@/views/panel/export/PDFPreExport'
import {listenGlobalKeyDownPreview} from '@/components/canvas/utils/shortcutKey'
import { listenGlobalKeyDownPreview } from '@/components/canvas/utils/shortcutKey'
import UserViewDialog from '@/components/canvas/customComponent/UserViewDialog'
import {hexColorToRGBA} from "@/views/chart/chart/util";
import {isMobile} from '@/utils/index'
import { hexColorToRGBA } from '@/views/chart/chart/util'
import { isMobile } from '@/utils/index'
const erd = elementResizeDetectorMaker()
export default {
components: {UserViewDialog, ComponentWrapper, CanvasOptBar, PDFPreExport},
components: { UserViewDialog, ComponentWrapper, CanvasOptBar, PDFPreExport },
model: {
prop: 'show',
event: 'change'
@ -207,14 +206,14 @@ export default {
componentData: {
type: Array,
required: false,
default: function () {
default: function() {
return []
}
},
canvasStyleData: {
type: Object,
required: false,
default: function () {
default: function() {
return {}
}
},
@ -261,7 +260,9 @@ export default {
],
needToChangeWidth: [
'left',
'width',
'width'
],
needToChangeInnerWidth: [
'fontSize',
'activeFontSize',
'borderWidth',
@ -371,6 +372,7 @@ export default {
return this.componentDataShow || []
},
...mapState([
'previewCanvasScale',
'isClickComponent'
]),
@ -463,7 +465,7 @@ export default {
return this.$refs['viewWrapperChild']
},
getAllWrapperChildRefs() {
let allChildRefs = []
const allChildRefs = []
const currentChildRefs = this.getWrapperChildRefs()
if (currentChildRefs && currentChildRefs.length > 0) {
allChildRefs.push.apply(allChildRefs, currentChildRefs)
@ -649,7 +651,7 @@ export default {
},
clearAllLinkage() {
this.$store.commit('clearPanelLinkageInfo')
bus.$emit('clear_panel_linkage', {viewId: 'all'})
bus.$emit('clear_panel_linkage', { viewId: 'all' })
},
changeStyleWithScale,
getStyle,
@ -665,8 +667,8 @@ export default {
}
if (this.isMainCanvas()) {
this.$store.commit('setPreviewCanvasScale', {
scaleWidth: (this.scaleWidth / 100),
scaleHeight: (this.scaleHeight / 100)
scaleWidth: this.canvasStyleData.autoSizeAdaptor ? (this.scaleWidth / 100) : 1,
scaleHeight: this.canvasStyleData.autoSizeAdaptor ? (this.scaleHeight / 100) : 1
})
}
this.handleScaleChange()
@ -682,6 +684,10 @@ export default {
format(value, scale) {
return value * scale / 100
},
formatPoint(value, pointScale) {
return value * pointScale
},
handleScaleChange() {
if (this.componentData) {
const componentData = deepCopy(this.componentData)
@ -691,10 +697,13 @@ export default {
component.style[key] = this.format(component.style[key], this.scaleHeight)
}
if (this.needToChangeWidth.includes(key)) {
component.style[key] = this.format(component.style[key], this.scaleWidth)
}
if (this.needToChangeInnerWidth.includes(key)) {
if ((key === 'fontSize' || key === 'activeFontSize') && (this.terminal === 'mobile' || ['custom', 'v-text'].includes(component.type))) {
// do nothing ( v-text )
} else {
component.style[key] = this.format(component.style[key], this.scaleWidth)
component.style[key] = this.formatPoint(component.style[key], this.previewCanvasScale.scalePointWidth)
}
}
})
@ -714,7 +723,7 @@ export default {
},
deselectCurComponent(e) {
if (!this.isClickComponent) {
this.$store.commit('setCurComponent', {component: null, index: null})
this.$store.commit('setCurComponent', { component: null, index: null })
if (this.$refs?.['canvas-opt-bar']) {
this.$refs['canvas-opt-bar'].setWidgetStatus()
}

View File

@ -1038,7 +1038,7 @@ export default {
if (this.publicLinkStatus) {
// ID
if (jumpInfo.publicJumpId) {
const url = '/link/' + jumpInfo.publicJumpId
const url = '/link/' + jumpInfo.publicJumpId + '?fromLink=true'
const currentUrl = window.location.href
localStorage.setItem('beforeJumpUrl', currentUrl)
this.windowsJump(url, jumpInfo.jumpType)

View File

@ -50,10 +50,32 @@ const unlockMap = {
let isCtrlOrCommandDown = false
// 检查当前页面是否有弹框
const checkDialog = () => {
let haveDialog = false
document.querySelectorAll('.el-dialog__wrapper').forEach(element => {
if (window.getComputedStyle(element).getPropertyValue('display') !== 'none') {
haveDialog = true
}
})
document.querySelectorAll('.el-popover').forEach(element => {
if (window.getComputedStyle(element).getPropertyValue('display') !== 'none') {
haveDialog = true
}
})
// 富文本单框
if (document.querySelector('.tox-dialog-wrap')) {
haveDialog = true
}
return haveDialog
}
// Monitor key operations globally and execute corresponding commands
export function listenGlobalKeyDown() {
window.onkeydown = (e) => {
if (!store.state.isInEditor) return
if (!store.state.isInEditor || checkDialog()) return
const { keyCode } = e
if (keyCode === ctrlKey || keyCode === commandKey) {
isCtrlOrCommandDown = true

View File

@ -86,6 +86,7 @@ export function panelInit(componentData, componentStyle) {
export function panelDataPrepare(componentData, componentStyle, callback) {
// style初始化
componentStyle.autoSizeAdaptor = (componentStyle.autoSizeAdaptor === undefined ? true : componentStyle.autoSizeAdaptor)
componentStyle.refreshTime = (componentStyle.refreshTime || 5)
componentStyle.refreshViewLoading = (componentStyle.refreshViewLoading || false)
componentStyle.refreshUnit = (componentStyle.refreshUnit || 'minute')
@ -350,7 +351,7 @@ export function insertTreeNode(nodeInfo, tree) {
if (!nodeInfo) {
return
}
if (nodeInfo.pid === 0 || nodeInfo.pid === '0') {
if (nodeInfo.pid === 0 || nodeInfo.pid === '0' || nodeInfo.pid === 'panel_list') {
tree.push(nodeInfo)
return
}

View File

@ -43,6 +43,7 @@
ref="deOutWidget"
:canvas-id="canvasId"
class="component-custom"
:terminal="terminal"
:out-style="element.style"
:is-relation="isRelation"
:element="element"
@ -101,6 +102,10 @@ export default {
type: Number,
required: false,
default: 0
},
terminal: {
type: String,
default: 'pc'
}
},
data() {

View File

@ -1,34 +1,67 @@
<template>
<el-date-picker
v-if="element.options!== null && element.options.attrs!==null && show"
ref="dateRef"
v-model="values"
:popper-class="'coustom-date-picker' + ' ' + extPoperClass"
:type="componentType"
:range-separator="$t(element.options.attrs.rangeSeparator)"
:start-placeholder="$t(element.options.attrs.startPlaceholder)"
:end-placeholder="$t(element.options.attrs.endPlaceholder)"
:placeholder="$t(element.options.attrs.placeholder)"
:append-to-body="inScreen"
value-format="timestamp"
:format="labelFormat"
:size="size"
:editable="false"
:picker-options="pickerOptions"
:default-time="defaultRangeTime"
@change="dateChange"
@focus="toFocus"
@blur="onBlur"
/>
<div class="date-picker-vant">
<el-date-picker
v-if="element.options!== null && element.options.attrs!==null && show"
ref="dateRef"
v-model="values"
:popper-class="'coustom-date-picker' + ' ' + extPoperClass"
:type="componentType"
:range-separator="$t(element.options.attrs.rangeSeparator)"
:start-placeholder="$t(element.options.attrs.startPlaceholder)"
:end-placeholder="$t(element.options.attrs.endPlaceholder)"
:placeholder="$t(element.options.attrs.placeholder)"
:append-to-body="inScreen"
value-format="timestamp"
:format="labelFormat"
:size="size"
:editable="false"
:picker-options="pickerOptions"
:default-time="defaultRangeTime"
@change="dateChange"
@focus="toFocus"
@blur="onBlur"
/>
<div v-if="isMobileStatus" class="vant-mobile" :class="isRange && 'wl50'" @click="showPopup"/>
<div v-if="isMobileStatus && isRange" class="vant-mobile" :class="['datetimerange', 'datetime', 'daterange'].includes(componentType) && 'wr50'" @click="showPopupRight"/>
<van-popup get-container="body" v-if="isMobileStatus" v-model="showDate" position="bottom" style="height: auto">
<van-datetime-picker
v-if="showdDatetimePicker"
@confirm="confirm"
@cancel="cancel"
v-model="currentDate"
:type="componentTypeVant"
title="选择时间"
:min-date="minDate"
:max-date="maxDate"
/>
<van-picker
v-else
title="选择时间"
:default-index="defaultIndex"
show-toolbar
:columns="columns"
@confirm="onConfirm"
@cancel="onCancel"
/>
</van-popup>
</div>
</template>
<script>
import { ApplicationContext } from '@/utils/ApplicationContext'
import { timeSection } from '@/utils'
import bus from '@/utils/bus'
import customInput from '@/components/widget/deWidget/customInput'
import customInput from '@/components/widget/deWidget/customInput'
import { dateMap, years, seconds } from '@/components/widget/deWidget/serviceNameFn'
import { mapState } from 'vuex'
import vanPopup from 'vant/lib/popup'
import vanDatetimePicker from 'vant/lib/datetime-picker'
import vanPicker from 'vant/lib/picker'
import 'vant/lib/popup/style'
import 'vant/lib/datetime-picker/style'
import 'vant/lib/picker/style'
export default {
components: { vanPopup, vanDatetimePicker, vanPicker },
mixins: [customInput],
props: {
canvasId: {
@ -52,19 +85,60 @@ export default {
isRelation: {
type: Boolean,
default: false
},
terminal: {
type: String,
default: 'pc'
}
},
data() {
return {
showDate: false,
minDate: new Date(1980, 0, 1),
maxDate: new Date(2025, 10, 1),
currentDate: new Date(),
operator: 'between',
defaultIndex: 2,
columns: years,
values: null,
onFocus: false,
show: true,
selectSecondInput: false,
selectSecond: false,
outTimer: null,
innerTimer: null
}
},
computed: {
isMobileStatus() {
return this.mobileStatus || this.terminal === 'mobile'
},
isRange() {
if (!this.isMobileStatus) return false
return ['datetimerange', 'daterange'].includes(this.componentType)
},
showdDatetimePicker() {
if (!this.isMobileStatus) return false
if (this.showSecond && this.selectSecond) return false
return this.componentTypeVant !== 'year'
},
showSecond() {
if (!this.isMobileStatus) return false
return this.labelFormat?.endsWith('ss')
},
componentTypeVant() {
if (!this.isMobileStatus) return ''
if (this.showSecond) {
return 'datetime'
}
if (this.labelFormat?.endsWith('mm')) {
return 'datetime'
}
if (this.labelFormat?.endsWith('HH')) {
return 'datehour'
}
return dateMap[this.componentType]
},
extPoperClass() {
if (this.labelFormat && this.labelFormat.includes('HH') && !this.labelFormat.includes('HH:mm')) {
return 'de-no-minite'
@ -130,7 +204,8 @@ export default {
return null
},
...mapState([
'canvasStyleData'
'canvasStyleData',
'mobileStatus'
])
},
@ -186,6 +261,86 @@ export default {
bus.$off('reset-default-value', this.resetDefaultValue)
},
methods: {
showPopupRight() {
const [_, end] = this.values || []
!!end && (this.currentDate = new Date(end))
this.selectSecondInput = true
this.showDate = true
},
cancel() {
this.showDate = false
},
confirm() {
this.setArrValue()
if (this.showSecond) {
this.columns = seconds
this.selectSecond = true
}
if (this.selectSecond || this.componentTypeVant === 'year') {
return
}
this.showDate = false
this.mobileDateChange()
},
onCancel() {
this.showDate = false
if (this.showSecond) {
this.selectSecond = false
}
},
setArrValue(val) {
if (!this.isRange) {
if (this.selectSecond) {
this.values = this.values + val * 1000
return
}
this.values = val ? +new Date(val) : +new Date(this.currentDate)
return
}
const [start, end] = this.values || []
if (this.selectSecond) {
if (this.selectSecondInput) {
this.values = [start, +new Date(this.currentDate) + val * 1000]
} else {
this.values = [+new Date(this.currentDate) + val * 1000, end]
}
return
}
if (this.selectSecondInput) {
this.values = [start, +new Date(this.currentDate)]
} else {
this.values = [+new Date(this.currentDate), end]
}
},
onConfirm(val) {
this.showDate = false
this.setArrValue(val)
if (this.showSecond) {
this.columns = years
this.selectSecond = false
}
this.mobileDateChange()
},
mobileDateChange() {
if (this.isRange) {
const [start, end] = this.values || []
if (!start || !end) return
}
this.dateChange(this.values)
},
showPopup() {
if (this.isRange) {
const [start] = this.values || []
!!start && (this.currentDate = new Date(start))
} else {
this.currentDate = new Date(this.values)
if (this.componentTypeVant === 'year') {
this.defaultIndex = years.findIndex(ele => `${this.currentDate.getFullYear()}` === ele)
}
}
this.selectSecondInput = false
this.showDate = true
},
loadInit() {
this.clearTime()
if (this.refreshHandler()) {
@ -340,6 +495,28 @@ export default {
</script>
<style lang="scss">
.date-picker-vant {
position: relative;
width: 100%;
.el-date-editor {
width: 100% !important;
}
.vant-mobile {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
&.wl50 {
width: 50%;
}
&.wr50 {
left: auto;
right: 0;
width: 50%;
}
}
}
.coustom-date-picker {
right: 0px;
border: 1px solid var(--BrDateColor, #dfe4ed) !important;

View File

@ -79,6 +79,18 @@ function handlerInputStyle(node, style) {
})
}
const dateMap = {
year: 'year',
month: 'year-month',
date: 'date',
datetime: 'datetime',
datetimerange: 'datetime',
daterange: 'date'
}
const years = Array(60).fill(1).map((_, index) => `${index + 1980}`)
const seconds = Array(60).fill(1).map((_, index) => index)
export {
attrsMap,
styleAttrs,
@ -87,5 +99,8 @@ export {
textSelectGridWidget,
textSelectTreeWidget,
textSelectWidget,
handlerInputStyle
handlerInputStyle,
dateMap,
years,
seconds
}

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1698901715032" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4099" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M960.605 932.345v-240.231c0.045-7.2-2.723-14.445-8.213-19.98-11.115-11.047-29.002-11.047-40.071 0-5.535 5.535-8.303 12.757-8.303 19.98v171.923l-351.99-352.035 351.99-352.013v171.855c0 7.245 2.767 14.49 8.303 20.002 11.070 11.070 28.957 11.070 40.071 0 5.49-5.511 8.257-12.78 8.213-20.002v-240.187c0.045-7.223-2.723-14.468-8.213-20.003-5.58-5.511-12.803-8.279-20.025-8.302h-240.233c-7.222 0-14.467 2.79-19.98 8.302-11.115 11.049-11.115 28.957 0 40.050 5.511 5.535 12.735 8.302 19.98 8.279h171.9l-352.013 352.013-352.012-352.035h171.855c7.268 0.022 14.49-2.745 20.025-8.279 11.070-11.047 11.070-29.002 0-40.050-5.49-5.511-12.758-8.279-20.025-8.303h-240.187c-7.268 0-14.513 2.79-20.025 8.303-5.513 5.558-8.279 12.803-8.279 20.048v240.165c0 7.245 2.79 14.512 8.279 20.002 11.070 11.070 28.98 11.070 40.028 0 5.513-5.511 8.279-12.713 8.279-20.002v-171.855l352.058 352.012-352.035 352.035v-171.922c0-7.2-2.745-14.445-8.279-19.98-11.070-11.047-29.002-11.047-40.028 0-5.558 5.535-8.279 12.757-8.279 19.98v240.231c0 7.223 2.79 14.468 8.279 20.048 5.535 5.468 12.757 8.279 20.025 8.279h240.188c7.268 0 14.49-2.745 20.025-8.279 11.070-11.047 11.070-29.002 0-40.050-5.535-5.535-12.78-8.257-20.025-8.257h-171.877l352.012-352.035 352.013 352.035h-171.9c-7.222 0-14.467 2.768-19.98 8.257-11.115 11.049-11.115 29.002 0 40.050 5.511 5.468 12.735 8.279 19.98 8.279h240.255c7.2 0 14.445-2.813 20.025-8.279 5.467-5.602 8.19-12.825 8.19-20.048z" p-id="4100" fill="#646A73"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -2064,7 +2064,7 @@ export default {
panel_cache_use_tips: 'It was checked that the last dashboard could not be saved normally. Do you want to use the panel that was not saved last time?',
template_name_tips: 'Panel\'s name should not be null',
panel_background_item: 'Customize panel background',
panel_background_image_tips: 'Currently.Jpeg,.Jpg,.Png,.Gif files are supported, and the size should not exceed 15m',
panel_background_image_tips: 'Currently Jpeg,Jpg,Png,Gif,Svg files are supported, and the size should not exceed 15m',
reUpload: 'reUpload',
create_by: 'Create By',
create_time: 'Create Time',
@ -2313,6 +2313,7 @@ export default {
suspension: 'suspension',
new_element_distribution: 'Element Distribution',
aided_grid: 'Aided Grid',
auto_size_adaptor: 'Component Adaptor',
aided_grid_open: 'Open',
aided_grid_close: 'Close',
export_pdf_page: 'Pagination Line',

View File

@ -2058,7 +2058,7 @@ export default {
panel_cache_use_tips: '檢查到上次有儀表板未能正常保存,是否使用上次未保存的儀表板?',
template_name_tips: '儀表板名稱必填',
panel_background_item: '自定義儀表板背景',
panel_background_image_tips: '當前支持.jpeg,.jpg,.png,.gif文件,大小不要超過15M',
panel_background_image_tips: '當前支持jpeg,jpg,png,gif,svg文件,大小15M',
reUpload: '重新上傳',
create_by: '創建人',
create_time: '創建時間',
@ -2307,6 +2307,7 @@ export default {
suspension: '懸浮',
new_element_distribution: '元素移入分佈方式',
aided_grid: '輔助設計網格',
auto_size_adaptor: '組件自適應',
aided_grid_open: '打開',
aided_grid_close: '關閉',
export_pdf_page: '分頁線',

View File

@ -2058,7 +2058,7 @@ export default {
panel_cache_use_tips: '检查到上次有仪表板未能正常保存,是否使用上次未保存的仪表板?',
template_name_tips: '仪表板名称必填',
panel_background_item: '自定义仪表板背景',
panel_background_image_tips: '当前支持.jpeg,.jpg,.png,.gif文件,大小不要超过15M',
panel_background_image_tips: '当前支持jpeg,jpg,png,gif,svg文件,大小15M',
reUpload: '重新上传',
create_by: '创建人',
create_time: '创建时间',
@ -2307,6 +2307,7 @@ export default {
suspension: '悬浮',
new_element_distribution: '元素移入分布方式',
aided_grid: '辅助设计网格',
auto_size_adaptor: '组件自适应',
aided_grid_open: '打开',
aided_grid_close: '关闭',
export_pdf_page: '分页线',

View File

@ -0,0 +1,9 @@
<template>
<router-view />
</template>
<script>
export default {
name: 'AppMobile'
}
</script>

View File

@ -0,0 +1,155 @@
import Vue from 'vue'
import Cookies from 'js-cookie'
import '@/styles/index.scss' // global css
import ElementUI from 'element-ui'
import Vuetify from 'vuetify'
import Fit2CloudUI from 'fit2cloud-ui'
import i18n from '../lang' // internationalization
import App from './App'
import store from '../store'
import router from '../router/mobile.js'
import message from '../utils/message'
import '@/icons' // icon
import '@/permission' // permission control
import api from '@/api/index.js'
import filter from '@/filter/filter'
import directives from '../directive'
import VueClipboard from 'vue-clipboard2'
import widgets from '@/components/widget'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import '../utils/dialog'
import DeComplexInput from '@/components/business/conditionTable/DeComplexInput'
import DeComplexSelect from '@/components/business/conditionTable/DeComplexSelect'
import DeViewSelect from '@/components/deViewSelect'
import RemarkEditor from '@/views/chart/components/componentStyle/dialog/RemarkEditor'
import TitleRemark from '@/views/chart/view/TitleRemark'
import '@/components/canvas/customComponent' // 注册自定义组件
import deBtn from '@/components/deCustomCm/DeBtn.vue'
import '@/utils/DateUtil'
import draggable from 'vuedraggable'
import deWebsocket from '@/websocket'
import { GaodeMap } from '@antv/l7-maps'
import * as echarts from 'echarts'
import UmyUi from 'umy-ui'
// 全屏插件
import fullscreen from 'vue-fullscreen'
import VueFriendlyIframe from 'vue-friendly-iframe'
import vueToPdf from 'vue-to-pdf'
import VueVideoPlayer from 'vue-video-player'
import 'video.js/dist/video-js.css'
import '@antv/s2/dist/style.min.css'
// 控制标签宽高成比例的指令
import proportion from 'vue-proportion-directive'
import xss from 'xss'
// 定义全局XSS解决方法
Object.defineProperty(Vue.prototype, '$xss', {
value: xss
})
Vue.config.productionTip = false
Vue.use(VueClipboard)
Vue.use(widgets)
Vue.component('Draggable', draggable)
Vue.prototype.$api = api
Vue.prototype.$echarts = echarts
Vue.prototype.$gaodeMap = GaodeMap
Vue.use(UmyUi)
Vue.use(fullscreen)
Vue.use(VueFriendlyIframe)
Vue.use(Vuetify)
// import TEditor from '@/components/Tinymce/index.vue'
// Vue.component('TEditor', TEditor)
/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
* you can execute: mockXHR()
*
* Currently MockJs will be used in the production environment,
* please remove it before going online ! ! !
*/
if (process.env.NODE_ENV === 'production') {
// const { mockXHR } = require('.../mock')
// mockXHR()
}
// set ElementUI lang to EN
// Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui按如下方式声明
ElementUI.Dialog.props.closeOnClickModal.default = false
ElementUI.Dialog.props.closeOnPressEscape.default = false
Vue.use(ElementUI, {
size: Cookies.get('size') || 'medium', // set element-ui default size
i18n: (key, value) => i18n.t(key, value)
})
Vue.use(Fit2CloudUI, {
i18n: (key, value) => i18n.t(key, value)
})
// Vue.use(VueAxios, axios)
Vue.use(filter)
Vue.use(directives)
Vue.use(message)
Vue.component('Treeselect', Treeselect)
Vue.component('DeComplexInput', DeComplexInput)
Vue.component('DeComplexSelect', DeComplexSelect)
Vue.component('DeViewSelect', DeViewSelect)
Vue.component('RemarkEditor', RemarkEditor)
Vue.component('TitleRemark', TitleRemark)
Vue.component('DeBtn', deBtn)
Vue.config.productionTip = false
Vue.use(vueToPdf)
Vue.use(VueVideoPlayer)
Vue.use(proportion)
Vue.prototype.hasDataPermission = function(pTarget, pSource) {
if (this.$store.state.user.user.isAdmin || pSource === 'ignore') {
return true
}
if (pSource && pTarget) {
return pSource.indexOf(pTarget) > -1
}
return false
}
Vue.prototype.checkPermission = function(pers) {
const permissions = store.getters.permissions
const hasPermission = pers.every(needP => {
const result = permissions.includes(needP)
return result
})
return hasPermission
}
Vue.use(deWebsocket)
Vue.prototype.$currentHttpRequestList = new Map()
Vue.prototype.$cancelRequest = function(cancelkey) {
if (cancelkey) {
if (cancelkey.indexOf('/**') > -1) {
Vue.prototype.$currentHttpRequestList.forEach((item, key) => {
key.indexOf(cancelkey.split('/**')[0]) > -1 && item('Operation canceled by the user.')
})
} else {
Vue.prototype.$currentHttpRequestList.get(cancelkey) && Vue.prototype.$currentHttpRequestList.get(cancelkey)('Operation canceled by the user.')
}
}
}
new Vue({
router,
store,
i18n,
render: h => h(App)
}).$mount('#app-mobile')

View File

@ -0,0 +1,19 @@
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export const constantRoutes = [
{
path: '/',
component: () => import('@/views/mobile/index.vue'),
}
]
const createRouter = () => new Router({
mode: 'hash',
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
const router = createRouter()
export default router

View File

@ -92,6 +92,8 @@ const data = {
componentGap: 5,
// 移动端布局状态
mobileLayoutStatus: false,
// 是否是mobile
mobileStatus: false,
// 公共链接状态(当前是否是公共链接打开)
publicLinkStatus: false,
pcTabMatrixCount: {
@ -574,6 +576,9 @@ const data = {
setMobileLayoutStatus(state, status) {
state.mobileLayoutStatus = status
},
setMobileStatus(state, status) {
state.mobileStatus = status
},
setPublicLinkStatus(state, status) {
state.publicLinkStatus = status
},

View File

@ -54,6 +54,18 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe63e;</span>
<div class="name">adaptor</div>
<div class="code-name">&amp;#xe63e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe886;</span>
<div class="name">颜色</div>
<div class="code-name">&amp;#xe886;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe644;</span>
<div class="name">command</div>
@ -810,9 +822,9 @@
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1669699377636') format('woff2'),
url('iconfont.woff?t=1669699377636') format('woff'),
url('iconfont.ttf?t=1669699377636') format('truetype');
src: url('iconfont.woff2?t=1698903637839') format('woff2'),
url('iconfont.woff?t=1698903637839') format('woff'),
url('iconfont.ttf?t=1698903637839') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@ -838,6 +850,24 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-adaptor"></span>
<div class="name">
adaptor
</div>
<div class="code-name">.icon-adaptor
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-yanse"></span>
<div class="name">
颜色
</div>
<div class="code-name">.icon-yanse
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-command"></span>
<div class="name">
@ -1972,6 +2002,22 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-adaptor"></use>
</svg>
<div class="name">adaptor</div>
<div class="code-name">#icon-adaptor</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-yanse"></use>
</svg>
<div class="name">颜色</div>
<div class="code-name">#icon-yanse</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-command"></use>

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2459092 */
src: url('iconfont.woff2?t=1669699377636') format('woff2'),
url('iconfont.woff?t=1669699377636') format('woff'),
url('iconfont.ttf?t=1669699377636') format('truetype');
src: url('iconfont.woff2?t=1698903637839') format('woff2'),
url('iconfont.woff?t=1698903637839') format('woff'),
url('iconfont.ttf?t=1698903637839') format('truetype');
}
.iconfont {
@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-adaptor:before {
content: "\e63e";
}
.icon-yanse:before {
content: "\e886";
}
.icon-command:before {
content: "\e644";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,20 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "34289857",
"name": "adaptor",
"font_class": "adaptor",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "9626971",
"name": "颜色",
"font_class": "yanse",
"unicode": "e886",
"unicode_decimal": 59526
},
{
"icon_id": "1567487",
"name": "command",

View File

@ -110,7 +110,7 @@
<el-col style="width: 130px!important;">
<el-upload
action=""
accept=".jpeg,.jpg,.png,.gif"
accept=".jpeg,.jpg,.png,.gif,.svg"
class="avatar-uploader"
list-type="picture-card"
:class="{disabled:uploadDisabled}"

View File

@ -158,8 +158,13 @@ export function getLabel(chart) {
// label value formatter
if (chart.type && chart.type !== 'waterfall') {
label.formatter = function(param) {
let yAxis, extStack, xaxisExt
let xAxis, yAxis, extStack, xaxisExt
let res = param.value
try {
xAxis = JSON.parse(chart.xaxis)
} catch (e) {
xAxis = JSON.parse(JSON.stringify(chart.xaxis))
}
try {
yAxis = JSON.parse(chart.yaxis)
} catch (e) {
@ -244,38 +249,46 @@ export function getLabel(chart) {
} else {
for (let i = 0; i < yAxis.length; i++) {
const f = yAxis[i]
if (f.name === param.category) {
let formatterCfg = formatterItem
if (f.formatterCfg) {
formatterCfg = f.formatterCfg
}
// 饼图和环形图格式优化
if (equalsAny(chart.type, 'pie', 'pie-donut')) {
// 这边默认值取指标是为了兼容存量的视图
const labelContent = l.labelContent ?? ['quota']
const contentItems = []
if (labelContent.includes('dimension')) {
contentItems.push(param.field)
}
if (labelContent.includes('quota')) {
contentItems.push(valueFormatter(param.value, formatterCfg))
}
if (labelContent.includes('proportion')) {
const percentage = `${(Math.round(param.percent * 10000) / 100).toFixed(l.reserveDecimalCount)}%`
if (labelContent.length === 3) {
contentItems.push(`(${percentage})`)
} else {
contentItems.push(percentage)
}
}
res = contentItems.join(' ')
} else if (equalsAny(chart.type, 'pie-rose', 'pie-donut-rose')) {
const quotaValue = valueFormatter(param.value, formatterCfg)
res = [param.field, quotaValue].join(' ')
} else {
let formatterCfg = formatterItem
if (f.formatterCfg) {
formatterCfg = f.formatterCfg
}
if (chart.type === 'scatter' && xAxis && xAxis.length > 0 && xAxis[0].groupType === 'q') {
// 针对横轴为指标的散点图
if (f.name === param.group) {
res = valueFormatter(param.value, formatterCfg)
}
break
} else {
if (f.name === param.category) {
// 饼图和环形图格式优化
if (equalsAny(chart.type, 'pie', 'pie-donut')) {
// 这边默认值取指标是为了兼容存量的视图
const labelContent = l.labelContent ?? ['quota']
const contentItems = []
if (labelContent.includes('dimension')) {
contentItems.push(param.field)
}
if (labelContent.includes('quota')) {
contentItems.push(valueFormatter(param.value, formatterCfg))
}
if (labelContent.includes('proportion')) {
const percentage = `${(Math.round(param.percent * 10000) / 100).toFixed(l.reserveDecimalCount)}%`
if (labelContent.length === 3) {
contentItems.push(`(${percentage})`)
} else {
contentItems.push(percentage)
}
}
res = contentItems.join(' ')
} else if (equalsAny(chart.type, 'pie-rose', 'pie-donut-rose')) {
const quotaValue = valueFormatter(param.value, formatterCfg)
res = [param.field, quotaValue].join(' ')
} else {
res = valueFormatter(param.value, formatterCfg)
}
break
}
}
}
}

View File

@ -6,6 +6,7 @@
width="150"
:append-to-body="false"
trigger="click"
:popper-class="showEditPosition === 'bar-main-preview' ? 'map-layer-poper' : ''"
>
<i
slot="reference"
@ -51,6 +52,10 @@ export default {
id: ''
}
}
},
showEditPosition: {
type: String,
required: true
}
},
data() {
@ -98,9 +103,15 @@ export default {
}
}
</script>
<style lang="scss">
.map-layer-poper {
top: 3px !important;
right: 80px !important;
left: auto !important;
}
</style>
<style scoped lang="scss">
.de-ul li {
margin: 5px 2px;
cursor: pointer;

View File

@ -286,8 +286,11 @@
min-width="200px"
:prop="field.fieldName"
:label="field.remarks"
resizable
/>
resizable>
<template slot-scope="scope">
<span>{{ at(scope.row, field.fieldName)[0] }}</span>
</template>
</el-table-column>
</el-table>
</div>
<el-table
@ -303,7 +306,11 @@
:prop="field.fieldName"
:label="field.remarks"
resizable
/>
>
<template slot-scope="scope">
<span>{{ at(scope.row, field.fieldName)[0] }}</span>
</template>
</el-table-column>
</el-table>
</div>
<div
@ -623,6 +630,7 @@ import { pySort } from './util'
import _ from 'lodash'
import GridTable from '@/components/gridTable/index.vue'
import { updateCacheTree } from '@/components/canvas/utils/utils'
import { at } from 'lodash'
export default {
name: 'AddSQL',
@ -742,7 +750,8 @@ export default {
}
]
}
]
],
at
}
},
computed: {

View File

@ -77,7 +77,7 @@ export default {
})
},
setPanelInfo() {
loadResource(this.resourceId,this.user).then(res => {
loadResource(this.resourceId, this.user).then(res => {
this.show = false
let loadingCount = 0
const watermarkInfo = {

View File

@ -0,0 +1,142 @@
<template>
<el-row
id="canvasInfoMobile"
class="this_mobile_canvas_main"
:style="mobileCanvasStyle"
>
<canvas-opt-bar/>
<de-canvas
ref="canvasMainRef"
:canvas-style-data="canvasStyleData"
:component-data="mainCanvasComponentData"
:canvas-id="canvasId"
:canvas-pid="'0'"
:mobile-layout-status="true"
/>
</el-row>
</template>
<script>
import DeCanvas from '@/components/canvas/DeCanvas'
import CanvasOptBar from '@/components/canvas/components/editor/CanvasOptBar'
import {
imgUrlTrans,
getNowCanvasComponentData,
} from "@/components/canvas/utils/utils";
import { mapState } from "vuex";
import { hexColorToRGBA } from "@/views/chart/chart/util";
export default {
components: { DeCanvas, CanvasOptBar },
data() {
return {
canvasId: "canvas-main",
previewVisible: false,
};
},
computed: {
...mapState(["canvasStyleData", "mobileLayoutStatus", 'componentData']),
mainCanvasComponentData() {
return getNowCanvasComponentData(this.canvasId);
},
mobileCanvasStyle() {
let style;
if (this.canvasStyleData.openCommonStyle) {
const styleInfo =
this.canvasStyleData.panel.mobileSetting &&
this.canvasStyleData.panel.mobileSetting.customSetting
? this.canvasStyleData.panel.mobileSetting
: this.canvasStyleData.panel;
if (
styleInfo.backgroundType === "image" &&
typeof styleInfo.imageUrl === "string"
) {
style = {
background: `url(${imgUrlTrans(styleInfo.imageUrl)}) no-repeat`,
};
} else if (styleInfo.backgroundType === "color") {
const colorRGBA = hexColorToRGBA(
styleInfo.color,
styleInfo.alpha === undefined ? 100 : styleInfo.alpha,
);
style = {
background: colorRGBA,
};
} else {
style = {
background: "#f7f8fa",
};
}
}
return style;
},
},
mounted() {
this.$store.commit('setMobileLayoutStatus', true)
this.$store.commit('setMobileStatus', true)
window.addEventListener('message', (event) => {
if (event.data.type === 'addComponent') {
this.$store.commit('addComponent', event.data.value)
}
if (event.data.type === 'setCanvasStyle') {
this.$store.commit('setCanvasStyle', event.data.value)
}
if (event.data.type === 'editSave') {
window.top.postMessage({ type: 'setComponentData', value: this.componentData }, '*')
}
if (event.data.type === 'reset') {
this.$store.commit('setComponentData', event.data.value)
this.$store.commit('openMobileLayout')
}
if (event.data.type === 'openMobileLayout') {
this.$store.commit('setComponentData', event.data.value)
this.$store.commit('openMobileLayout')
}
})
},
methods: {
cancel() {
this.show = false
},
confirm() {
this.show = false
},
showPopup() {
this.show = true
}
}
}
</script>
<style lang="less" scoped>
.this_mobile_canvas_main {
overflow-x: hidden;
overflow-y: auto;
height: 100vh;
background-size: 100% 100% !important;
}
.mobile-container {
-webkit-tap-highlight-color: transparent;
color: #323233;
font-size: 16px;
font-family:
"Open Sans",
-apple-system,
BlinkMacSystemFont,
"Helvetica Neue",
Helvetica,
Segoe UI,
Arial,
Roboto,
"PingFang SC",
"miui",
"Hiragino Sans GB",
"Microsoft Yahei",
sans-serif;
-webkit-font-smoothing: antialiased;
height: 570px;
box-sizing: border-box;
width: 360px;
min-width: 360px;
overflow: hidden;
background: #fafafa;
}
</style>

View File

@ -47,7 +47,7 @@ import { mapState } from 'vuex'
import ComponentWaitItem from '@/views/panel/edit/ComponentWaitItem'
import MobileBackgroundSelector from '@/views/panel/subjectSetting/panelStyle/MobileBackgroundSelector'
import { imgUrlTrans } from '@/components/canvas/utils/utils'
import {hexColorToRGBA} from "@/views/chart/chart/util";
import { hexColorToRGBA } from '@/views/chart/chart/util'
export default {
name: 'ComponentWait',

View File

@ -188,7 +188,7 @@
class="mobile_canvas_main"
>
<el-col
:span="8"
:span="10"
class="this_mobile_canvas_cell"
>
<div
@ -200,23 +200,8 @@
<el-row class="this_mobile_canvas_inner_top">
{{ panelInfo.name }}
</el-row>
<el-row class="this_mobile_canvas_main_outer">
<el-row
id="canvasInfoMobile"
class="this_mobile_canvas_main"
:style="mobileCanvasStyle"
>
<canvas-opt-bar v-if="!previewVisible&&mobileLayoutStatus"/>
<de-canvas
v-if="!previewVisible&&mobileLayoutStatus"
ref="canvasMainRef"
:canvas-style-data="canvasStyleData"
:component-data="mainCanvasComponentData"
:canvas-id="canvasId"
:canvas-pid="'0'"
:mobile-layout-status="true"
/>
</el-row>
<el-row v-loading="mobileLoading" class="this_mobile_canvas_main_outer">
<iframe src="./mobile.html" @load="handleLoad" frameborder="0" width="360" height="570"></iframe>
</el-row>
<el-row class="this_mobile_canvas_inner_bottom">
<el-col :span="12">
@ -249,7 +234,7 @@
</div>
</el-col>
<el-col
:span="16"
:span="14"
class="this_mobile_canvas_cell this_mobile_canvas_wait_cell"
>
<component-wait/>
@ -593,6 +578,7 @@ export default {
autoMoveOffSet: 15,
mobileEditorShow: true,
hasStar: false,
mobileLoading: true,
drawerSize: '300px',
visible: false,
show: false,
@ -652,7 +638,7 @@ export default {
{ label: '适应新主题', value: true },
{ label: '保持源样式', value: false }
],
multiplexingStyleAdaptSelf : true
multiplexingStyleAdaptSelf: true
}
},
@ -776,7 +762,7 @@ export default {
curCanvasScaleSelf() {
return this.curCanvasScaleMap[this.canvasId]
},
selectComponentCount(){
selectComponentCount() {
return Object.keys(this.curMultiplexingComponents).length
},
...mapState([
@ -786,6 +772,7 @@ export default {
'canvasStyleData',
'curComponentIndex',
'componentData',
'pcComponentData',
'linkageSettingStatus',
'dragComponentInfo',
'componentGap',
@ -817,7 +804,8 @@ export default {
this.recordStyleChange(this.$store.state.styleChangeTimes)
}
},
mobileLayoutStatus() {
mobileLayoutStatus(val) {
this.mobileLoading = val
this.restore()
},
previewVisible(val) {
@ -849,6 +837,21 @@ export default {
listenGlobalKeyDown()
},
mounted() {
bus.$on('mobile-status-change', this.mobileStatusChange)
window.addEventListener('message', (event) => {
if (event.data.type === 'deleteComponentWithId') {
console.log('event1', event.data)
this.$store.commit('deleteComponentWithId', event.data.value)
this.deleteComponentWithId(event.data.value)
}
if (event.data.type === 'setComponentData') {
console.log('setComponentData', event.data)
this.$store.commit('setComponentData', event.data.value)
setTimeout(() => {
bus.$emit('editSave')
}, 1000)
}
})
this.initWatermark()
this.initEvents()
const _this = this
@ -864,6 +867,7 @@ export default {
this.multiplexingStyleAdaptSelf = this.multiplexingStyleAdapt
},
beforeDestroy() {
bus.$off('mobile-status-change', this.mobileStatusChange)
bus.$off('component-on-drag', this.componentOnDrag)
bus.$off('component-dialog-style', this.componentDialogStyle)
bus.$off('previewFullScreenClose', this.previewFullScreenClose)
@ -875,6 +879,40 @@ export default {
elx && elx.remove()
},
methods: {
handleLoad() {
this.mobileLoading = false
this.mobileStatusChange('openMobileLayout', this.componentData)
},
deleteComponentWithId(id) {
for (let index = 0; index < this.pcComponentData.length; index++) {
const element = this.pcComponentData[index]
if (element.id && element.id === id) {
element.mobileSelected = false
if (element.type === 'de-tabs') {
this.deleteComponentWithId(element.id)
}
break
}
}
},
mobileStatusChange(type, value) {
console.log('mobileLayoutStatustype', type, this.mobileLayoutStatus)
if (!this.mobileLayoutStatus) return
const iframe = document.querySelector('iframe')
console.log('iframe', iframe)
if (iframe) {
iframe.contentWindow.postMessage(
{
type,
value
},
'*'
)
}
// if (['setCanvasStyle', 'addComponent'].includes(type)) {
// }
},
initWatermark() {
if (this.panelInfo.watermarkInfo) {
this.$nextTick(() => {
@ -1557,14 +1595,14 @@ export default {
.mobile_canvas_main {
width: 80%;
height: 90%;
margin-left: 10%;
margin-left: 7%;
margin-top: 3%;
}
.this_mobile_canvas {
border-radius: 30px;
min-width: 300px;
max-width: 350px;
min-width: 370px;
max-width: 370px;
min-height: 600px;
max-height: 700px;
overflow: hidden;

View File

@ -75,6 +75,7 @@ export const CANVAS_STYLE = {
showPageLine: false,
proportion: null
},
autoSizeAdaptor: true, // 组件内容大小自适应(自适应时会根据画布缩放比例对内容进行缩放,关闭则显示内部文本实际大小)
refreshViewEnable: false, // 开启视图刷新(默认关闭)
refreshViewLoading: true, // 仪表板视图loading提示
refreshUnit: 'minute', // 仪表板刷新时间带外 默认 分钟

View File

@ -50,7 +50,7 @@
>
<el-upload
action=""
accept=".jpeg,.jpg,.png,.gif"
accept=".jpeg,.jpg,.png,.gif,.svg"
class="avatar-uploader"
list-type="picture-card"
:http-request="upload"

View File

@ -51,7 +51,7 @@
>
<el-upload
action=""
accept=".jpeg,.jpg,.png,.gif"
accept=".jpeg,.jpg,.png,.gif,.svg"
class="avatar-uploader"
list-type="picture-card"
:http-request="upload"
@ -106,6 +106,7 @@ import { mapState } from 'vuex'
import { deepCopy, imgUrlTrans } from '@/components/canvas/utils/utils'
import { COLOR_PANEL } from '@/views/chart/chart/chart'
import { uploadFileResult } from '@/api/staticResource/staticResource'
import bus from '@/utils/bus'
export default {
name: 'MobileBackgroundSelector',
@ -141,6 +142,7 @@ export default {
const canvasStyleData = deepCopy(this.canvasStyleData)
canvasStyleData.panel.mobileSetting = this.mobileSetting
this.$store.commit('setCanvasStyle', canvasStyleData)
bus.$emit('mobile-status-change', 'setCanvasStyle', canvasStyleData)
this.$store.commit('recordSnapshot', 'commitStyle')
},
onChangeType() {

View File

@ -41,6 +41,11 @@ module.exports = {
entry: 'src/main.js',
template: 'public/index.html',
filename: 'index.html'
},
mobile: {
entry: 'src/mobile/main.js',
template: 'public/mobile.html',
filename: 'mobile.html'
}
},
configureWebpack: {

View File

@ -725,7 +725,7 @@ public class DmQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -747,7 +747,7 @@ public class KingbaseQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -577,7 +577,7 @@ public class KylinQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -592,7 +592,7 @@ public class MaxcomputeQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -592,7 +592,7 @@ public class MongobiQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {

View File

@ -582,7 +582,7 @@ public class PrestoQueryProvider extends QueryProvider {
//然后是数值格式的情况还需要传extGroup
if (xIsNumber && CollectionUtils.isNotEmpty(extGroup)) {
xAxisList.add(extGroup.get(0));
xAxisList.addAll(extGroup);
}
if (CollectionUtils.isNotEmpty(xAxisList)) {