Compare commits

...

30 Commits

Author SHA1 Message Date
yigekaiguan 44928ebc64 为chartFactory某些私有属性添加'_'前缀 2021-09-24 15:38:15 +08:00
yigekaiguan 92139f707f 使用chartFactory.themeStyleSheet()函数重写图表设置面板CSS样式表 2021-09-24 15:19:15 +08:00
yigekaiguan bc29ede09a 添加chartFactory.themeStyleSheet()函数,用于为构建图表之外主题相关的样式表提供支持 2021-09-24 11:19:05 +08:00
yigekaiguan 15b33e855f chartFactory.getGradualColor重命名为gradualColor 2021-09-24 09:57:29 +08:00
datagear 63b41132b8 使用chart.themeStyleSheet函数重构图表设置面板CSS样式 2021-09-23 23:12:02 +08:00
yigekaiguan 71e4dd8674 chartFactory.js移除已无用的parseJSONSilently、trimJSONString、toJSONString函数 2021-09-23 20:07:40 +08:00
yigekaiguan 62797ab649 图表JS对象新增themeStyleName、themeStyleSheet函数,用于为定义图表主题相关的CSS样式表提供支持 2021-09-23 19:53:36 +08:00
datagear 001f49acb6 完善表格图表美化滚动条功能 2021-09-22 23:28:54 +08:00
datagear 4ad1838f8e 看板后台生成的css放在最开头,确保页面生成的、用户自定义的css有更高优先级 2021-09-22 23:14:18 +08:00
yigekaiguan 8e5d2e22ce 看板内图表元素的内置CSS样式改为通过样式类而非内联style的方式,避免用户自定义图表样式类不起作用的问题 2021-09-22 21:34:06 +08:00
yigekaiguan 327fe29bee 完善下拉框图表功能 2021-09-22 14:56:07 +08:00
datagear 20a9e15f8e 添加下拉框图表基本功能 2021-09-21 21:14:28 +08:00
yigekaiguan d334d9197b 修复当登录超时后点击查询页面的查询按钮无响应的BUG 2021-09-18 15:18:05 +08:00
yigekaiguan 637cd54cc7 修复当登录超时后点击查询页面的查询按钮无响应的BUG 2021-09-18 11:25:03 +08:00
yigekaiguan 35e2f0d08b SpringBoot由2.4.6升级至2.4.10,解决bin发布包必须添加config/placeholder文件夹的问题 2021-09-17 10:08:07 +08:00
yigekaiguan 93a36b1070 Merge branch 'dev-2.9.0' of https://gitee.com/datagear/datagear.git into dev-2.9.0 2021-09-16 10:27:50 +08:00
yigekaiguan ad452ee10b 完善README 2021-09-16 10:26:50 +08:00
datagear a8fb05bb53 管理员账号不允许删除 2021-09-15 21:07:07 +08:00
yigekaiguan 93a5bc2340 删除用户操作改为必须选择数据迁移目标用户后才能删除 2021-09-15 17:34:07 +08:00
yigekaiguan cc1b9b6520 标签卡图表插件版本号升级至2.9.0 2021-09-15 10:18:04 +08:00
yigekaiguan 71f4ceb811 修改清理临时目录时间间隔配置项,调试模式时每10分钟清理一次 2021-09-15 09:57:24 +08:00
yigekaiguan 4690efeb3f 修复静态内容类的数据集(CSV、JSON等)修改后必须刷新看板页面才能更新数据的BUG 2021-09-14 19:07:59 +08:00
yigekaiguan 62fe947e43 改进表格图表滚动条样式,使其与图表主题匹配(仅支持webkit内核浏览器) 2021-09-13 16:24:13 +08:00
datagear 3934c8ae46 补充版本开发计划 2021-09-12 20:59:13 +08:00
datagear 997895cb49 改进数据集预览功能,当参数、属性、数据格式变化时也必须重新执行预览 2021-09-12 20:52:20 +08:00
datagear f3b83c068a 标签卡图表添加flex配置项,用于丰富标签卡布局设置功能 2021-09-12 12:06:29 +08:00
datagear 1ccc40f7f4 更新版本开发计划 2021-09-11 23:40:57 +08:00
datagear 521df3639e ECharts版本由5.1.2升级至5.2.0 2021-09-11 16:12:30 +08:00
datagear 7e66f016be 数据集预览即使执行出错也返回解析后的内容,便于排查拼写错误 2021-09-11 13:41:53 +08:00
datagear 8a4b77f1f1 v2.9.0版本标识 2021-09-08 19:14:26 +08:00
88 changed files with 2433 additions and 92640 deletions

View File

@ -10,14 +10,14 @@ DataGear是一款开源免费的数据可视化分析平台可自由制作任
## 系统特点
- 支持接入多种数据源
<br>支持接入任意提供JDBC驱动的数据库包括MySQL、Oracle、PostgreSQL、SQL Server等关系数据库以及Elasticsearch、ClickHouse、Hive等大数据引擎
- 动态接入多种数据源
<br>支持动态接入任意提供JDBC驱动的数据库包括MySQL、Oracle、PostgreSQL、SQL Server等关系数据库以及Elasticsearch、ClickHouse、Hive等大数据引擎
- 支持多种格式的数据集
<br>支持创建SQL、CSV、Excel、HTTP接口、JSON数据集可将数据集定义为动态参数化数据集可添加文本框、下拉框、日期框、时间框等类型的数据集参数为构建动态可交互图表提供支持
- 丰富强大的图表功能
<br>图表可聚合多个不同格式的数据集,轻松构建同比、环比数据图表,内置折线图、柱状图、饼图、地图、雷达图、漏斗图等开箱即用的图表,并且支持自定义图表配置项,支持编写和上传自定义图表插件
<br>图表可聚合多个不同格式的数据集,轻松构建同比、环比数据图表,内置折线图、柱状图、饼图、地图、雷达图、漏斗图、散点图、K线图、桑基图50+开箱即用的图表,并且支持自定义图表配置项,支持编写和上传自定义图表插件
- 可自由编辑的数据可视化页面
<br>可视化页面采用原生的HTML网页作为模板可自由编辑页面内容支持导入任意HTML网页为元素添加扩展属性即可绑定和配置图表页面内置丰富的API可构建图表联动、数据钻取、异步加载、交互表单等个性化的数据可视化页面

View File

@ -5,14 +5,16 @@
地图热力图
路径图
下拉框
数据集预览即使执行错误也返回解析后的内容,便于用户检查错误;
修复登录超时后打开页面内对话框未处理超时的BUG
改进表格图表滚动条样式,使其与图表主题匹配;
改进表格轮播性能,解决轮播卡顿问题;
修复静态内容类的数据集CSV、JSON等修改后必须刷新看板页面才能更新数据的BUG
移除看板展示后台缓存,将看板展示页改为无状态方式
修复CSV数据集属性设置日期格式yyyyMMdd无效的BUG因为值直接被解析成了数值跳过了格式
升级ECharts至5.2.0版本;
ok 修复当登录超时后点击查询页面的查询按钮无响应的BUG
ok 删除用户操作改为必须选择数据迁移目标用户后才能删除;
ok 修复静态内容类的数据集CSV、JSON等修改后必须刷新看板页面才能更新数据的BUG
ok 改进表格图表滚动条样式使其与图表主题匹配仅支持webkit内核浏览器
ok 改进数据集预览功能,当参数、属性、数据格式变化时也必须重新执行预览;
ok 修复CSV数据集属性设置日期格式yyyyMMdd无效的BUG之前版本已修复
ok 标签卡图表添加flex配置项用于丰富标签卡布局设置功能
ok 升级ECharts至5.2.0版本;
ok 数据集预览即使执行出错也返回解析后的内容,便于排查拼写错误;
待定:
@ -32,6 +34,7 @@
待研究:
提供服务API使图表、看板可以方便整合至第三方前端代码中
看板多端支持;
数据集支持更多数据库比如MongoDB
多维分析图表类型;
数据填报;

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.datagear</groupId>
<artifactId>datagear</artifactId>
<version>2.8.0</version>
<version>2.9.0</version>
</parent>
<artifactId>datagear-analysis</artifactId>

View File

@ -8,9 +8,7 @@
package org.datagear.analysis;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 看板
@ -18,7 +16,7 @@ import java.util.Map;
* @author datagear@163.com
*
*/
public class Dashboard extends AbstractIdentifiable implements Serializable
public class Dashboard extends DashboardQueryHandler implements Identifiable, Serializable
{
private static final long serialVersionUID = 1L;
@ -27,6 +25,8 @@ public class Dashboard extends AbstractIdentifiable implements Serializable
public static final String PROPERTY_WIDGET = "widget";
public static final String PROPERTY_CHARTS = "charts";
private String id;
private transient RenderContext renderContext;
private DashboardWidget widget;
@ -40,11 +40,23 @@ public class Dashboard extends AbstractIdentifiable implements Serializable
public Dashboard(String id, RenderContext renderContext, DashboardWidget widget)
{
super(id);
super();
this.id = id;
this.renderContext = renderContext;
this.widget = widget;
}
@Override
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public RenderContext getRenderContext()
{
return renderContext;
@ -88,77 +100,61 @@ public class Dashboard extends AbstractIdentifiable implements Serializable
/**
* 获取指定ID的{@linkplain Chart}
*
* @param id
* @param chartId
* @return 返回{@code null}表示没有找到
*/
public Chart getChart(String id)
public Chart getChart(String chartId)
{
if (this.charts == null)
return null;
for (Chart chart : this.charts)
{
if (chart.getId().equals(id))
if (chart.getId().equals(chartId))
return chart;
}
return null;
}
/**
* 获取{@linkplain DashboardResult}
*
* @param query
* @return
* @throws DataSetException
*/
public DashboardResult getResult(DashboardQuery query) throws DataSetException
@Override
protected ChartDefinition getChartDefinition(String chartId)
{
Map<String, ChartQuery> chartQueries = query.getChartQueries();
boolean suppressChartError = query.isSuppressChartError();
return getChart(chartId);
}
Map<String, ChartResult> chartResults = new HashMap<String, ChartResult>(chartQueries.size());
Map<String, ChartResultError> chartResultErrors = new HashMap<String, ChartResultError>();
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
for (Map.Entry<String, ChartQuery> entry : chartQueries.entrySet())
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dashboard other = (Dashboard) obj;
if (id == null)
{
String chartId = entry.getKey();
ChartQuery chartQuery = entry.getValue();
Chart chart = getChart(chartId);
if (chart == null)
throw new IllegalArgumentException("Chart '" + chartId + "' not found");
if (chartQuery.getResultDataFormat() == null && query.getResultDataFormat() != null)
{
chartQuery = chartQuery.copy();
chartQuery.setResultDataFormat(query.getResultDataFormat());
}
ChartResult chartResult = null;
if (suppressChartError)
{
try
{
chartResult = chart.getResult(chartQuery);
chartResults.put(chartId, chartResult);
}
catch (Throwable t)
{
chartResultErrors.put(chartId, new ChartResultError(t));
}
}
else
{
chartResult = chart.getResult(chartQuery);
chartResults.put(chartId, chartResult);
}
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
return true;
}
DashboardResult dashboardResult = new DashboardResult(chartResults);
dashboardResult.setChartResultErrors(chartResultErrors);
return dashboardResult;
@Override
public String toString()
{
return getClass().getSimpleName() + " [id=" + id + "]";
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
package org.datagear.analysis;
import java.util.HashMap;
import java.util.Map;
/**
* {@linkplain DashboardQuery}处理器
*
* @author datagear@163.com
*
*/
public abstract class DashboardQueryHandler
{
public DashboardQueryHandler()
{
super();
}
/**
* 获取{@linkplain DashboardResult}
*
* @param query
* @return
* @throws DataSetException
*/
public DashboardResult getResult(DashboardQuery query) throws DataSetException
{
Map<String, ChartQuery> chartQueries = query.getChartQueries();
boolean suppressChartError = query.isSuppressChartError();
Map<String, ChartResult> chartResults = new HashMap<String, ChartResult>(chartQueries.size());
Map<String, ChartResultError> chartResultErrors = new HashMap<String, ChartResultError>();
for (Map.Entry<String, ChartQuery> entry : chartQueries.entrySet())
{
String chartId = entry.getKey();
ChartQuery chartQuery = entry.getValue();
ChartDefinition chart = getChartDefinition(chartId);
if (chart == null)
throw new IllegalArgumentException("Chart '" + chartId + "' not found");
if (chartQuery.getResultDataFormat() == null && query.getResultDataFormat() != null)
{
chartQuery = chartQuery.copy();
chartQuery.setResultDataFormat(query.getResultDataFormat());
}
ChartResult chartResult = null;
if (suppressChartError)
{
try
{
chartResult = chart.getResult(chartQuery);
chartResults.put(chartId, chartResult);
}
catch (Throwable t)
{
chartResultErrors.put(chartId, new ChartResultError(t));
}
}
else
{
chartResult = chart.getResult(chartQuery);
chartResults.put(chartId, chartResult);
}
}
DashboardResult dashboardResult = new DashboardResult(chartResults);
dashboardResult.setChartResultErrors(chartResultErrors);
return dashboardResult;
}
/**
* 获取指定图表ID对应的{@linkplain ChartDefinition}
*
* @param chartId
* {@linkplain Chart#getId()}
* @return 允许返回{@code null}
*/
protected abstract ChartDefinition getChartDefinition(String chartId);
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
package org.datagear.analysis;
import java.util.Map;
/**
* 简单{@linkplain DashboardQueryHandler}
*
* @author datagear@163.com
*
*/
public class SimpleDashboardQueryHandler extends DashboardQueryHandler
{
private Map<String, ? extends ChartDefinition> chartDefinitions;
public SimpleDashboardQueryHandler()
{
super();
}
public SimpleDashboardQueryHandler(Map<String, ? extends ChartDefinition> chartDefinitions)
{
super();
this.chartDefinitions = chartDefinitions;
}
public Map<String, ? extends ChartDefinition> getChartDefinitions()
{
return chartDefinitions;
}
public void setChartDefinitions(Map<String, ? extends ChartDefinition> chartDefinitions)
{
this.chartDefinitions = chartDefinitions;
}
@Override
protected ChartDefinition getChartDefinition(String chartId)
{
return (this.chartDefinitions == null ? null : this.chartDefinitions.get(chartId));
}
}

View File

@ -119,7 +119,7 @@ public abstract class AbstractCsvDataSet extends AbstractResolvableDataSet imple
}
catch (Throwable t)
{
throw new DataSetSourceParseException(t);
throw new DataSetSourceParseException(t, reader.getResolvedTemplate());
}
finally
{

View File

@ -124,7 +124,7 @@ public abstract class AbstractJsonDataSet extends AbstractResolvableDataSet impl
}
catch (Throwable t)
{
throw new DataSetSourceParseException(t);
throw new DataSetSourceParseException(t, reader.getResolvedTemplate());
}
finally
{

View File

@ -120,4 +120,21 @@ public class ChartWidget extends ChartDefinition implements Serializable
{
return IDUtil.uuid();
}
/**
* 获取由{@linkplain ChartWidget#render(RenderContext)}渲染的{@linkplain Chart}所关联的{@linkplain ChartWidget#getId()}
*
* @param chart
* @return 可能返回{@code null}
*/
public static String getChartWidget(Chart chart)
{
if (chart == null)
return null;
@SuppressWarnings("unchecked")
Map<String, Object> chartWidgetInfo = (Map<String, Object>) chart.getAttribute(ATTR_CHART_WIDGET);
return (chartWidgetInfo == null ? null : (String) chartWidgetInfo.get(ChartWidget.PROPERTY_ID));
}
}

View File

@ -19,6 +19,8 @@ public class DataSetSourceParseException extends DataSetException
{
private static final long serialVersionUID = 1L;
private String source = null;
public DataSetSourceParseException()
{
super();
@ -38,4 +40,20 @@ public class DataSetSourceParseException extends DataSetException
{
super(message, cause);
}
public DataSetSourceParseException(Throwable cause, String source)
{
super(cause);
this.source = source;
}
public String getSource()
{
return source;
}
public void setSource(String source)
{
this.source = source;
}
}

View File

@ -335,11 +335,15 @@ public class HttpDataSet extends AbstractResolvableDataSet
protected TemplateResolvedDataSetResult resolveResult(DataSetQuery query, List<DataSetProperty> properties,
boolean resolveProperties) throws DataSetException
{
String uri = null;
String headerContent = null;
String requestContent = null;
try
{
String uri = resolveTemplateUri(query);
String headerContent = resolveTemplateHeaderContent(query);
String requestContent = resolveTemplateRequestContent(query);
uri = resolveTemplateUri(query);
headerContent = resolveTemplateHeaderContent(query);
requestContent = resolveTemplateRequestContent(query);
ClassicHttpRequest request = createHttpRequest(uri);
@ -353,13 +357,8 @@ public class HttpDataSet extends AbstractResolvableDataSet
ResolvedDataSetResult result = this.httpClient.execute(request, responseHandler);
String templateResult = "URI:" + System.lineSeparator() + uri //
+ System.lineSeparator() + "-----------------------------------------" + System.lineSeparator() //
+ "Request headers:" + System.lineSeparator() + headerContent //
+ System.lineSeparator() + "-----------------------------------------" + System.lineSeparator() //
+ "Request content:" + System.lineSeparator() + requestContent;
return new TemplateResolvedDataSetResult(result.getResult(), result.getProperties(), templateResult);
return new TemplateResolvedDataSetResult(result.getResult(), result.getProperties(),
buildResolvedTemplate(uri, headerContent, requestContent));
}
catch (DataSetException e)
{
@ -367,10 +366,44 @@ public class HttpDataSet extends AbstractResolvableDataSet
}
catch (Throwable t)
{
throw new DataSetSourceParseException(t);
throw new DataSetSourceParseException(t, buildResolvedTemplate(uri, headerContent, requestContent));
}
}
protected String buildResolvedTemplate(String uri, String headerContent, String requestContent)
{
StringBuilder sb = new StringBuilder();
if (!StringUtil.isEmpty(uri))
{
if (sb.length() > 0)
sb.append(
System.lineSeparator() + "-----------------------------------------" + System.lineSeparator());
sb.append("URI:" + System.lineSeparator() + uri);
}
if (!StringUtil.isEmpty(headerContent))
{
if (sb.length() > 0)
sb.append(
System.lineSeparator() + "-----------------------------------------" + System.lineSeparator());
sb.append("Request headers:" + System.lineSeparator() + headerContent);
}
if (!StringUtil.isEmpty(requestContent))
{
if (sb.length() > 0)
sb.append(
System.lineSeparator() + "-----------------------------------------" + System.lineSeparator());
sb.append("Request content:" + System.lineSeparator() + requestContent);
}
return sb.toString();
}
protected void setHttpHeaders(ClassicHttpRequest request, String headerContent) throws Throwable
{
if (StringUtil.isEmpty(headerContent))

View File

@ -877,6 +877,13 @@ public abstract class HtmlTplDashboardWidgetRenderer extends TextParserSupport
List<String> excludes = StringUtil.splitWithTrim(importExclude, ",");
// 后台生成的样式应该放在最开头确保页面生成的用户自定义的css有更高优先级
if (!excludes.contains(this.themeImportName))
{
writeNewLine(out);
writeDashboardThemeStyle(renderContext, renderAttr, out, dashboard);
}
if (this.htmlTplDashboardImport != null)
{
List<ImportItem> importItems = this.htmlTplDashboardImport.getImportItems();
@ -901,12 +908,6 @@ public abstract class HtmlTplDashboardWidgetRenderer extends TextParserSupport
}
}
}
if (!excludes.contains(this.themeImportName))
{
writeNewLine(out);
writeDashboardThemeStyle(renderContext, renderAttr, out, dashboard);
}
}
/**
@ -1029,7 +1030,6 @@ public abstract class HtmlTplDashboardWidgetRenderer extends TextParserSupport
writeNewLine(out);
out.write("</style>");
writeNewLine(out);
return true;
}

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.datagear</groupId>
<artifactId>datagear</artifactId>
<version>2.8.0</version>
<version>2.9.0</version>
</parent>
<artifactId>datagear-connection</artifactId>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.datagear</groupId>
<artifactId>datagear</artifactId>
<version>2.8.0</version>
<version>2.9.0</version>
</parent>
<artifactId>datagear-dataexchange</artifactId>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.datagear</groupId>
<artifactId>datagear</artifactId>
<version>2.8.0</version>
<version>2.9.0</version>
</parent>
<artifactId>datagear-management</artifactId>

View File

@ -7,6 +7,7 @@
package org.datagear.management.domain;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Set;
@ -221,4 +222,44 @@ public class User extends AbstractStringIdEntity implements CloneableEntity
{
return ADMIN_USER_ID.equals(userId);
}
/**
* 是否包含管理员账号
*
* @param userIds
* @return
*/
public static boolean containsAdminUser(String[] userIds)
{
if (userIds == null)
return false;
for (String userId : userIds)
{
if (ADMIN_USER_ID.equals(userId))
return true;
}
return false;
}
/**
* 是否包含管理员账号
*
* @param userIds
* @return
*/
public static boolean containsAdminUser(Collection<String> userIds)
{
if (userIds == null)
return false;
for (String userId : userIds)
{
if (ADMIN_USER_ID.equals(userId))
return true;
}
return false;
}
}

View File

@ -16,18 +16,50 @@ package org.datagear.management.service;
public interface CreateUserEntityService
{
/**
* 更新创建用户ID
* 更新创建用户
*
* @param oldUserId
* 待更新的旧用户ID
* @param newUserId
* 要更新到的新用户ID
* @return
*/
int updateCreateUserId(String oldUserId, String newUserId);
/**
* 更新创建用户
*
* @param oldUserIds
* 待更新的旧用户ID
* @param newUserId
* 要更新到的新用户ID
* @return
*/
int updateCreateUserId(String[] oldUserIds, String newUserId);
/**
* 删除指定用户ID的所有实体
*
* TODO 有些业务的删除操作并不是仅删除数据库记录那么简单后续再考虑实现此接口
* <p>
* 注意
* </p>
* <p>
* 这个接口的目的是为删除用户时同时删除其创建的数据提供支持但它并不能很好地实现原因如下
* </p>
* <ul>
* <li>有些业务的删除操作并不是仅删除数据库记录也可能有相关的外部资源导致其无法直接通过SQL实现</li>
* <li>待删除的数据有可能被外键引用而导致删除SQL出错或者从业务角度来考虑它们不应被删除</li>
* </ul>
* <p>
* 所以这里先注释此接口
* </p>
* <p>
* 对于删除用户操作应采用如下方式
* </p>
* <ol>
* <li>使用{@linkplain #updateCreateUserId(String, String)}先将待删除用户的数据迁移另一个用户</li>
* <li>删除用户信息</li>
* </ol>
*
* @param userIds
* @return

View File

@ -17,11 +17,4 @@ import org.datagear.management.domain.Schema;
*/
public interface SchemaService extends DataPermissionEntityService<String, Schema>, CreateUserEntityService
{
/**
* 删除指定用户ID的{@linkplain Schema}
*
* @param userIds
* @return
*/
int deleteByUserId(String... userIds);
}

View File

@ -7,6 +7,8 @@
package org.datagear.management.service;
import java.util.List;
import org.datagear.management.domain.User;
/**
@ -33,6 +35,16 @@ public interface UserService extends EntityService<String, User>
*/
User getByIdNoPassword(String id);
/**
* 根据ID获取用户其密码已被清除
*
* @param ids
* @param discardNull
* 对于未找到的元素是否丢弃而不是返回{@code null}元素
* @return
*/
List<User> getByIdsNoPassword(String[] ids, boolean discardNull);
/**
* 更新但是忽略{@linkplain User#getRoles()}
*
@ -50,4 +62,32 @@ public interface UserService extends EntityService<String, User>
* @return
*/
boolean updatePasswordById(String id, String newPassword, boolean encrypt);
/**
* 删除用户
* <p>
* 注意此接口仅删除用户本身信息另参考{@linkplain #deleteByIds(String[], String)}
* </p>
*/
@Override
boolean deleteById(String id);
/**
* 删除用户
* <p>
* 注意此接口仅删除用户本身信息另参考{@linkplain #deleteByIds(String[], String)}
* </p>
*/
@Override
boolean[] deleteByIds(String[] ids);
/**
* 删除用户同时将其创建的业务数据都迁移至目标用户
*
* @param ids
* 待删除的用户ID
* @param migrateToId
* 业务数据要迁移到的用户ID
*/
void deleteByIds(String[] ids, String migrateToId);
}

View File

@ -288,9 +288,9 @@ public abstract class AbstractMybatisDataPermissionEntityService<ID, T extends D
}
@Override
protected int updateCreateUserId(String oldUserId, String newUserId)
protected int updateCreateUserId(String[] oldUserIds, String newUserId)
{
int count = super.updateCreateUserId(oldUserId, newUserId);
int count = super.updateCreateUserId(oldUserIds, newUserId);
if (count > 0)
permissionCacheInvalidate();

View File

@ -263,10 +263,7 @@ public abstract class AbstractMybatisEntityService<ID, T extends Entity<ID>> ext
}
/**
* 更新创建用户ID
* <p>
* 此方法调用底层的{@code updateCreateUserId} SQL
* </p>
* 更新创建用户
* <p>
* 此方法主要为子类实现{@linkplain CreateUserEntityService#updateCreateUserId(String, String)}提供支持
* </p>
@ -274,11 +271,31 @@ public abstract class AbstractMybatisEntityService<ID, T extends Entity<ID>> ext
* @param oldUserId
* @param newUserId
* @return
* @see #updateCreateUserId(String[], String)
*/
protected int updateCreateUserId(String oldUserId, String newUserId)
{
String[] oldUserIds = new String[] { oldUserId };
return updateCreateUserId(oldUserIds, newUserId);
}
/**
* 更新创建用户
* <p>
* 此方法调用底层的{@code updateCreateUserId} SQL
* </p>
* <p>
* 此方法主要为子类实现{@linkplain CreateUserEntityService#updateCreateUserId(String[], String)}提供支持
* </p>
*
* @param oldUserIds
* @param newUserId
* @return
*/
protected int updateCreateUserId(String[] oldUserIds, String newUserId)
{
Map<String, Object> params = buildParamMap();
params.put("oldUserId", oldUserId);
params.put("oldUserIds", oldUserIds);
params.put("newUserId", newUserId);
int count = updateMybatis("updateCreateUserId", params);
@ -293,7 +310,8 @@ public abstract class AbstractMybatisEntityService<ID, T extends Entity<ID>> ext
* 如果{@linkplain CreateUserEntity#getCreateUser()}不为空
* 则使用{@linkplain UserService#getByIdNoPassword(String)}对其进行更新
*
* @param entity 允许为{@code null}
* @param entity
* 允许为{@code null}
* @param service
*/
protected void inflateCreateUserEntity(CreateUserEntity<?> entity, UserService service)

View File

@ -93,6 +93,12 @@ public class AnalysisProjectServiceImpl extends AbstractMybatisDataPermissionEnt
return super.updateCreateUserId(oldUserId, newUserId);
}
@Override
public int updateCreateUserId(String[] oldUserIds, String newUserId)
{
return super.updateCreateUserId(oldUserIds, newUserId);
}
@Override
protected AnalysisProject postProcessGet(AnalysisProject obj)
{

View File

@ -225,6 +225,12 @@ public class DataSetEntityServiceImpl extends AbstractMybatisDataPermissionEntit
return super.updateCreateUserId(oldUserId, newUserId);
}
@Override
public int updateCreateUserId(String[] oldUserIds, String newUserId)
{
return super.updateCreateUserId(oldUserIds, newUserId);
}
@Override
public PagingData<DataSetEntity> pagingQuery(User user, PagingQuery pagingQuery, String dataFilter,
String analysisProjectId)

View File

@ -77,6 +77,12 @@ public class DataSetResDirectoryServiceImpl extends
return super.updateCreateUserId(oldUserId, newUserId);
}
@Override
public int updateCreateUserId(String[] oldUserIds, String newUserId)
{
return super.updateCreateUserId(oldUserIds, newUserId);
}
@Override
protected DataSetResDirectory postProcessGet(DataSetResDirectory obj)
{

View File

@ -199,6 +199,12 @@ public class HtmlChartWidgetEntityServiceImpl
return super.updateCreateUserId(oldUserId, newUserId);
}
@Override
public int updateCreateUserId(String[] oldUserIds, String newUserId)
{
return super.updateCreateUserId(oldUserIds, newUserId);
}
@Override
public PagingData<HtmlChartWidgetEntity> pagingQuery(User user, PagingQuery pagingQuery, String dataFilter,
String analysisProjectId)

View File

@ -132,6 +132,12 @@ public class HtmlTplDashboardWidgetEntityServiceImpl
return super.updateCreateUserId(oldUserId, newUserId);
}
@Override
public int updateCreateUserId(String[] oldUserIds, String newUserId)
{
return super.updateCreateUserId(oldUserIds, newUserId);
}
@Override
public PagingData<HtmlTplDashboardWidgetEntity> pagingQuery(User user, PagingQuery pagingQuery, String dataFilter,
String analysisProjectId)

View File

@ -7,8 +7,6 @@
package org.datagear.management.service.impl;
import java.util.Map;
import org.apache.ibatis.session.SqlSessionFactory;
import org.datagear.connection.DriverEntityManager;
import org.datagear.management.domain.Schema;
@ -127,17 +125,9 @@ public class SchemaServiceImpl extends AbstractMybatisDataPermissionEntityServic
}
@Override
public int deleteByUserId(String... userIds)
public int updateCreateUserId(String[] oldUserIds, String newUserId)
{
Map<String, Object> params = buildParamMap();
params.put("userIds", userIds);
int count = updateMybatis("deleteByUserId", params);
if (count > 0)
cacheInvalidate();
return count;
return super.updateCreateUserId(oldUserIds, newUserId);
}
@Override

View File

@ -8,6 +8,7 @@
package org.datagear.management.service.impl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -17,6 +18,7 @@ import org.apache.ibatis.session.SqlSessionFactory;
import org.datagear.management.domain.Role;
import org.datagear.management.domain.User;
import org.datagear.management.service.AuthorizationListener;
import org.datagear.management.service.CreateUserEntityService;
import org.datagear.management.service.RoleService;
import org.datagear.management.service.UserService;
import org.datagear.management.util.dialect.MbSqlDialect;
@ -41,6 +43,8 @@ public class UserServiceImpl extends AbstractMybatisEntityService<String, User>
private AuthorizationListener authorizationListener = null;
private List<CreateUserEntityService> createUserEntityServices = null;
public UserServiceImpl()
{
super();
@ -92,6 +96,16 @@ public class UserServiceImpl extends AbstractMybatisEntityService<String, User>
this.authorizationListener = authorizationListener;
}
public List<CreateUserEntityService> getCreateUserEntityServices()
{
return createUserEntityServices;
}
public void setCreateUserEntityServices(List<CreateUserEntityService> createUserEntityServices)
{
this.createUserEntityServices = createUserEntityServices;
}
@Override
public User getByName(String name)
{
@ -117,6 +131,24 @@ public class UserServiceImpl extends AbstractMybatisEntityService<String, User>
return user;
}
@Override
public List<User> getByIdsNoPassword(String[] ids, boolean discardNull)
{
List<User> users = new ArrayList<User>();
for (String id : ids)
{
User user = getByIdNoPassword(id);
if (user == null && discardNull)
continue;
users.add(user);
}
return users;
}
@Override
public boolean updatePasswordById(String id, String newPassword, boolean encrypt)
{
@ -141,6 +173,18 @@ public class UserServiceImpl extends AbstractMybatisEntityService<String, User>
return update(user, params);
}
@Override
public void deleteByIds(String[] ids, String migrateToId)
{
if (this.createUserEntityServices != null)
{
for (CreateUserEntityService service : this.createUserEntityServices)
service.updateCreateUserId(ids, migrateToId);
}
this.deleteByIds(ids);
}
@Override
protected void add(User entity, Map<String, Object> params)
{

View File

@ -848,3 +848,9 @@ CREATE TABLE DATAGEAR_SCHEMA_GUARD
SG_CREATE_TIME TIMESTAMP,
PRIMARY KEY (SG_ID)
);
-----------------------------------------
--version[2.9.0], DO NOT EDIT THIS LINE!
-----------------------------------------

View File

@ -26,7 +26,10 @@
UPDATE DATAGEAR_ANALYSIS_PROJECT SET
AP_CREATE_USER_ID = #{newUserId}
WHERE
AP_CREATE_USER_ID = #{oldUserId}
AP_CREATE_USER_ID IN
<foreach item="item" index="index" collection="oldUserIds" open="(" separator="," close=")">
#{item}
</foreach>
</update>
<delete id="deleteById">

View File

@ -142,7 +142,10 @@
UPDATE DATAGEAR_DATA_SET SET
DS_CREATE_USER_ID = #{newUserId}
WHERE
DS_CREATE_USER_ID = #{oldUserId}
DS_CREATE_USER_ID IN
<foreach item="item" index="index" collection="oldUserIds" open="(" separator="," close=")">
#{item}
</foreach>
</update>
<update id="updateSqlDataSetEntity">

View File

@ -26,7 +26,10 @@
UPDATE DATAGEAR_DSR_DIRECTORY SET
DD_CREATE_USER_ID = #{newUserId}
WHERE
DD_CREATE_USER_ID = #{oldUserId}
DD_CREATE_USER_ID IN
<foreach item="item" index="index" collection="oldUserIds" open="(" separator="," close=")">
#{item}
</foreach>
</update>
<delete id="deleteById">

View File

@ -44,7 +44,10 @@
UPDATE DATAGEAR_HTML_CHART_WIDGET SET
HCW_CREATE_USER_ID = #{newUserId}
WHERE
HCW_CREATE_USER_ID = #{oldUserId}
HCW_CREATE_USER_ID IN
<foreach item="item" index="index" collection="oldUserIds" open="(" separator="," close=")">
#{item}
</foreach>
</update>
<delete id="deleteById">

View File

@ -41,7 +41,10 @@
UPDATE DATAGEAR_HTML_DASHBOARD SET
HD_CREATE_USER_ID = #{newUserId}
WHERE
HD_CREATE_USER_ID = #{oldUserId}
HD_CREATE_USER_ID IN
<foreach item="item" index="index" collection="oldUserIds" open="(" separator="," close=")">
#{item}
</foreach>
</update>
<delete id="deleteById">

View File

@ -31,7 +31,10 @@
UPDATE DATAGEAR_SCHEMA SET
SCHEMA_CREATE_USER_ID = #{newUserId}
WHERE
SCHEMA_CREATE_USER_ID = #{oldUserId}
SCHEMA_CREATE_USER_ID IN
<foreach item="item" index="index" collection="oldUserIds" open="(" separator="," close=")">
#{item}
</foreach>
</update>
<delete id="deleteById">
@ -40,15 +43,6 @@
SCHEMA_ID = #{id}
</delete>
<delete id="deleteByUserId">
DELETE FROM DATAGEAR_SCHEMA
WHERE
SCHEMA_CREATE_USER_ID IN
<foreach item="item" index="index" collection="userIds" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
<select id="getById" resultType="org.datagear.management.domain.Schema">
SELECT
T.*

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.datagear</groupId>
<artifactId>datagear</artifactId>
<version>2.8.0</version>
<version>2.9.0</version>
</parent>
<artifactId>datagear-meta</artifactId>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.datagear</groupId>
<artifactId>datagear</artifactId>
<version>2.8.0</version>
<version>2.9.0</version>
</parent>
<artifactId>datagear-persistence</artifactId>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>org.datagear</groupId>
<artifactId>datagear</artifactId>
<version>2.8.0</version>
<version>2.9.0</version>
</parent>
<artifactId>datagear-util</artifactId>

View File

@ -21,7 +21,7 @@ public final class Global
}
/** 当前版本号 */
public static final String VERSION = "2.8.0";
public static final String VERSION = "2.9.0";
/** 中文产品名称 */
public static final String PRODUCT_NAME_ZH = "数据齿轮";

View File

@ -22,6 +22,10 @@
#默认角色:匿名用户
#defaultRole.anonymous=ROLE_DATA_ADMIN
#清理临时目录
#执行清理时间间隔
cleanTempDirectory.interval=0 0 1 * * ?
#日志级别
#ERROR, WARN, INFO, DEBUG, TRACE
logging.level.org.datagear=INFO

View File

@ -1,5 +0,0 @@
不要删除这个placeholder文件夹不然程序将无法启动
SpringBoot升级至2.4.6版本后,
有一个BUG会导致程序启动失败详见https://github.com/spring-projects/spring-boot/issues/26627
所以临时添加这个占位文件夹,确保程序可以正常启动。

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.datagear</groupId>
<artifactId>datagear</artifactId>
<version>2.8.0</version>
<version>2.9.0</version>
</parent>
<artifactId>datagear-web</artifactId>

View File

@ -54,6 +54,7 @@ import org.datagear.management.service.AnalysisProjectAuthorizationListener;
import org.datagear.management.service.AnalysisProjectService;
import org.datagear.management.service.AuthorizationListener;
import org.datagear.management.service.AuthorizationService;
import org.datagear.management.service.CreateUserEntityService;
import org.datagear.management.service.DataPermissionEntityService;
import org.datagear.management.service.DataSetEntityService;
import org.datagear.management.service.DataSetResDirectoryService;
@ -628,7 +629,7 @@ public class CoreConfig implements ApplicationListener<ContextRefreshedEvent>
// JS
importItems.add(ImportItem.valueOfJavaScript("jquery", libPrefix + "/jquery-1.12.4/jquery-1.12.4.min.js"));
importItems.add(ImportItem.valueOfJavaScript("echarts", libPrefix + "/echarts-5.1.2/echarts.js"));
importItems.add(ImportItem.valueOfJavaScript("echarts", libPrefix + "/echarts-5.2.0/echarts.min.js"));
importItems.add(ImportItem.valueOfJavaScript("wordcloud",
libPrefix + "/echarts-wordcloud-2.0.0/echarts-wordcloud.min.js"));
importItems.add(ImportItem.valueOfJavaScript("liquidfill",
@ -769,6 +770,7 @@ public class CoreConfig implements ApplicationListener<ContextRefreshedEvent>
initAnalysisProjectAuthorizationListenerAwares(context);
initServiceCaches(context);
initDevotedDataExchangeServices(context);
initUserServiceCreateUserEntityServices(context);
}
@SuppressWarnings("rawtypes")
@ -838,4 +840,29 @@ public class CoreConfig implements ApplicationListener<ContextRefreshedEvent>
devotedDataExchangeServices.add(this.batchDataExchangeService());
this.dataExchangeService().setDevotedDataExchangeServices(devotedDataExchangeServices);
}
protected void initUserServiceCreateUserEntityServices(ApplicationContext context)
{
List<CreateUserEntityService> serviceList = getCreateUserEntityServices(context);
UserService userService = this.userService();
if (userService instanceof UserServiceImpl)
((UserServiceImpl) userService).setCreateUserEntityServices(serviceList);
}
/**
* 获取所有{@linkplain CreateUserEntityService}实例
*
* @param context
* @return
*/
public static List<CreateUserEntityService> getCreateUserEntityServices(ApplicationContext context)
{
Map<String, CreateUserEntityService> serviceMap = context.getBeansOfType(CreateUserEntityService.class);
List<CreateUserEntityService> serviceList = new ArrayList<CreateUserEntityService>(serviceMap.size());
serviceList.addAll(serviceMap.values());
return serviceList;
}
}

View File

@ -21,8 +21,11 @@ import org.datagear.web.security.AuthUser;
import org.datagear.web.security.AuthenticationSuccessHandlerImpl;
import org.datagear.web.security.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
@ -38,7 +41,7 @@ import org.springframework.security.web.firewall.StrictHttpFirewall;
* @author datagear@163.com
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter
public class SecurityConfig extends WebSecurityConfigurerAdapter implements ApplicationListener<ContextRefreshedEvent>
{
/**
* 授权角色(登录用户 系统管理员) 数据管理员
@ -121,16 +124,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
this.coreConfig = coreConfig;
}
protected AuthenticationSuccessHandler getAuthenticationSuccessHandler()
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler()
{
AuthenticationSuccessHandlerImpl bean = new AuthenticationSuccessHandlerImpl();
List<CreateUserEntityService> createUserEntityServices = Arrays.asList(this.coreConfig.schemaService(),
this.coreConfig.dataSetEntityService(), this.coreConfig.htmlChartWidgetEntityService(),
this.coreConfig.htmlTplDashboardWidgetEntityService(), this.coreConfig.analysisProjectService());
bean.setCreateUserEntityServices(createUserEntityServices);
return bean;
}
@ -299,7 +297,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
.antMatchers("/**").access(disableAnonymous ? AUTH_USER_ADMIN : AUTH_ANONYMOUS_USER_ADMIN)
.and().formLogin().loginPage("/login").loginProcessingUrl("/login/doLogin").usernameParameter("name")
.passwordParameter("password").successHandler(getAuthenticationSuccessHandler())
.passwordParameter("password").successHandler(authenticationSuccessHandler())
.and().logout().logoutUrl("/logout").invalidateHttpSession(true).logoutSuccessUrl("/")
@ -351,4 +349,22 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
firewall.setAllowSemicolon(true);
return firewall;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event)
{
ApplicationContext context = event.getApplicationContext();
inflateAuthenticationSuccessHandler(context);
}
protected void inflateAuthenticationSuccessHandler(ApplicationContext context)
{
List<CreateUserEntityService> serviceList = CoreConfig.getCreateUserEntityServices(context);
AuthenticationSuccessHandler ash = authenticationSuccessHandler();
if (ash instanceof AuthenticationSuccessHandlerImpl)
((AuthenticationSuccessHandlerImpl) ash).setCreateUserEntityServices(serviceList);
}
}

View File

@ -12,6 +12,7 @@ import java.io.Serializable;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -30,10 +31,12 @@ import org.datagear.analysis.DashboardTheme;
import org.datagear.analysis.DashboardThemeSource;
import org.datagear.analysis.DataSetQuery;
import org.datagear.analysis.RenderContext;
import org.datagear.analysis.SimpleDashboardQueryHandler;
import org.datagear.analysis.support.ChartWidget;
import org.datagear.analysis.support.DataSetParamValueConverter;
import org.datagear.analysis.support.DefaultRenderContext;
import org.datagear.analysis.support.SimpleDashboardThemeSource;
import org.datagear.analysis.support.html.HtmlTplDashboard;
import org.datagear.analysis.support.html.HtmlChartWidget;
import org.datagear.analysis.support.html.HtmlTplDashboardRenderAttr;
import org.datagear.analysis.support.html.HtmlTplDashboardRenderAttr.WebContext;
import org.datagear.analysis.support.html.HtmlTplDashboardWidgetRenderer;
@ -167,34 +170,64 @@ public abstract class AbstractDataAnalysisController extends AbstractController
* 获取看板结果
*
* @param request
* @param response
* @param model
* @param webContext
* @param form
* @param renderer
* @return
* @throws Exception
*/
protected DashboardResult getDashboardResult(HttpServletRequest request, HttpServletResponse response,
org.springframework.ui.Model model, WebContext webContext, DashboardQueryForm form) throws Exception
protected DashboardResult getDashboardResult(HttpServletRequest request, DashboardQueryForm form,
HtmlTplDashboardWidgetRenderer renderer)
{
String dashboardId = form.getDashboardId();
DashboardQuery dashboardQuery = form.getDashboardQuery();
if (StringUtil.isEmpty(dashboardId))
if (StringUtil.isEmpty(form.getDashboardId()))
throw new IllegalInputException();
SessionHtmlTplDashboardManager dashboardManager = getSessionHtmlTplDashboardManagerNotNull(request);
HtmlTplDashboard dashboard = dashboardManager.get(dashboardId);
if (dashboard == null)
throw new RecordNotFoundException();
SessionDashboardInfoManager dashboardInfoManager = getSessionDashboardInfoManagerNotNull(request);
DashboardInfo dashboardInfo = dashboardInfoManager.get(form.getDashboardId());
DashboardQuery queriesConverted = convertDashboardQuery(dashboard, dashboardQuery);
if (dashboardInfo == null)
throw new IllegalInputException();
return dashboard.getResult(queriesConverted);
DashboardQuery dashboardQuery = form.getDashboardQuery();
Map<String, HtmlChartWidget> chartWidgets = getChartWidgets(form.getDashboardQuery(), dashboardInfo, renderer);
DashboardQuery queriesConverted = convertDashboardQuery(dashboardQuery, chartWidgets);
SimpleDashboardQueryHandler dqh = new SimpleDashboardQueryHandler(chartWidgets);
return dqh.getResult(queriesConverted);
}
protected DashboardQuery convertDashboardQuery(Dashboard dashboard, DashboardQuery query)
/**
* 获取图表ID-图表部件映射表
*
* @param query
* @param dashboardInfo
* @param renderer
* @return
*/
protected Map<String, HtmlChartWidget> getChartWidgets(DashboardQuery query, DashboardInfo dashboardInfo,
HtmlTplDashboardWidgetRenderer renderer)
{
Map<String, ChartQuery> chartQueries = query.getChartQueries();
Map<String, HtmlChartWidget> chartWidgets = new HashMap<String, HtmlChartWidget>(chartQueries.size());
for (String chartId : chartQueries.keySet())
{
String chartWidgetId = dashboardInfo.getChartWidgetId(chartId);
if (chartWidgetId == null)
throw new IllegalInputException("Chart '" + chartId + "' not found");
HtmlChartWidget chartWidget = renderer.getHtmlChartWidget(chartWidgetId);
chartWidgets.put(chartId, chartWidget);
}
return chartWidgets;
}
protected DashboardQuery convertDashboardQuery(DashboardQuery query,
Map<String, ? extends ChartWidget> chartWidgets)
{
if (query == null)
return new DashboardQuery();
@ -206,12 +239,12 @@ public abstract class AbstractDataAnalysisController extends AbstractController
{
String chartId = entry.getKey();
ChartQuery chartQuery = entry.getValue();
Chart chart = dashboard.getChart(chartId);
ChartWidget chartWidget = chartWidgets.get(chartId);
if (chart == null)
if (chartWidget == null)
throw new IllegalInputException("Chart '" + chartId + "' not found");
ChartDataSet[] chartDataSets = chart.getChartDataSets();
ChartDataSet[] chartDataSets = chartWidget.getChartDataSets();
List<DataSetQuery> dataSetQueries = chartQuery.getDataSetQueries();
ChartQuery chartQueryRe = null;
@ -245,25 +278,6 @@ public abstract class AbstractDataAnalysisController extends AbstractController
return queryRe;
}
protected SessionHtmlTplDashboardManager getSessionHtmlTplDashboardManagerNotNull(HttpServletRequest request)
{
HttpSession session = request.getSession();
SessionHtmlTplDashboardManager dashboardManager = (SessionHtmlTplDashboardManager) session
.getAttribute(SessionHtmlTplDashboardManager.class.getName());
synchronized (session)
{
if (dashboardManager == null)
{
dashboardManager = new SessionHtmlTplDashboardManager();
session.setAttribute(SessionHtmlTplDashboardManager.class.getName(), dashboardManager);
}
}
return dashboardManager;
}
protected void addHeartBeatValue(HttpServletRequest request, WebContext webContext)
{
String heartbeatURL = "/dashboard" + DashboardController.HEARTBEAT_TAIL_URL;
@ -288,34 +302,25 @@ public abstract class AbstractDataAnalysisController extends AbstractController
return WebUtils.addJsessionidParam(url, sessionId);
}
protected static class SessionHtmlTplDashboardManager implements Serializable
protected SessionDashboardInfoManager getSessionDashboardInfoManagerNotNull(HttpServletRequest request)
{
private static final long serialVersionUID = 1L;
HttpSession session = request.getSession();
private transient Map<String, HtmlTplDashboard> htmlTplDashboards;
SessionDashboardInfoManager dashboardManager = (SessionDashboardInfoManager) session
.getAttribute(SessionDashboardInfoManager.class.getName());
public SessionHtmlTplDashboardManager()
synchronized (session)
{
super();
if (dashboardManager == null)
{
dashboardManager = new SessionDashboardInfoManager();
session.setAttribute(SessionDashboardInfoManager.class.getName(), dashboardManager);
}
}
public synchronized HtmlTplDashboard get(String htmlTplDashboardId)
{
if (this.htmlTplDashboards == null)
return null;
return this.htmlTplDashboards.get(htmlTplDashboardId);
}
public synchronized void put(HtmlTplDashboard dashboard)
{
if (this.htmlTplDashboards == null)
this.htmlTplDashboards = new HashMap<>();
this.htmlTplDashboards.put(dashboard.getId(), dashboard);
}
return dashboardManager;
}
/**
* 看板查询表单
*
@ -353,4 +358,96 @@ public abstract class AbstractDataAnalysisController extends AbstractController
this.dashboardQuery = dashboardQuery;
}
}
protected static class SessionDashboardInfoManager implements Serializable
{
private static final long serialVersionUID = 1L;
private Map<String, DashboardInfo> dashboardInfos = null;
public SessionDashboardInfoManager()
{
super();
}
public synchronized DashboardInfo get(String dashboardId)
{
if (this.dashboardInfos == null)
return null;
return this.dashboardInfos.get(dashboardId);
}
public synchronized void put(DashboardInfo dashboardInfo)
{
if (this.dashboardInfos == null)
this.dashboardInfos = new HashMap<>();
this.dashboardInfos.put(dashboardInfo.getDashboardId(), dashboardInfo);
}
}
protected static class DashboardInfo implements Serializable
{
private static final long serialVersionUID = 1L;
/**看板ID*/
private final String dashboardId;
/**看板部件ID*/
private final String dashboardWidgetId;
/** 图表ID-图表部件ID映射表 */
private final Map<String, String> chartIdToChartWidgetIds = new HashMap<String, String>();
public DashboardInfo(String dashboardId, String dashboardWidgetId)
{
super();
this.dashboardId = dashboardId;
this.dashboardWidgetId = dashboardWidgetId;
}
public DashboardInfo(Dashboard dashboard)
{
this.dashboardId = dashboard.getId();
this.dashboardWidgetId = dashboard.getWidget().getId();
if (dashboard.hasChart())
{
List<Chart> charts = dashboard.getCharts();
for (Chart chart : charts)
this.chartIdToChartWidgetIds.put(chart.getId(), ChartWidget.getChartWidget(chart));
}
}
public String getDashboardId()
{
return dashboardId;
}
public String getDashboardWidgetId()
{
return dashboardWidgetId;
}
public synchronized Map<String, String> getChartIdToChartWidgetIds()
{
return Collections.unmodifiableMap(chartIdToChartWidgetIds);
}
public synchronized String getChartWidgetId(String chartId)
{
return this.chartIdToChartWidgetIds.get(chartId);
}
public synchronized void putChartWidgetId(String chartId, String chartWidgetId)
{
this.chartIdToChartWidgetIds.put(chartId, chartWidgetId);
}
public synchronized void putChartWidgetIds(Map<String, String> chartIdToChartWidgetIds)
{
this.chartIdToChartWidgetIds.putAll(chartIdToChartWidgetIds);
}
}
}

View File

@ -481,8 +481,8 @@ public class ChartController extends AbstractChartPluginAwareController implemen
public ErrorMessageDashboardResult showData(HttpServletRequest request, HttpServletResponse response,
org.springframework.ui.Model model, @RequestBody DashboardQueryForm form) throws Exception
{
WebContext webContext = createWebContext(request);
DashboardResult dashboardResult = getDashboardResult(request, response, model, webContext, form);
DashboardResult dashboardResult = getDashboardResult(request, form,
this.chartShowHtmlTplDashboardWidgetHtmlRenderer);
return new ErrorMessageDashboardResult(dashboardResult, true);
}
@ -526,8 +526,8 @@ public class ChartController extends AbstractChartPluginAwareController implemen
HtmlTplDashboard dashboard = dashboardWidget.render(renderContext);
SessionHtmlTplDashboardManager dashboardManager = getSessionHtmlTplDashboardManagerNotNull(request);
dashboardManager.put(dashboard);
SessionDashboardInfoManager dashboardInfoManager = getSessionDashboardInfoManagerNotNull(request);
dashboardInfoManager.put(new DashboardInfo(dashboard));
}
protected WebContext createWebContext(HttpServletRequest request)

View File

@ -446,7 +446,7 @@ public class ControllerAdvice extends AbstractController
DataSetSourceParseException exception)
{
setOperationMessageForThrowable(request, buildMessageCode(DataSetSourceParseException.class), exception, false,
exception.getMessage());
exception.getMessage(), exception.getSource());
return getErrorView(request, response);
}
@ -457,7 +457,7 @@ public class ControllerAdvice extends AbstractController
HttpServletResponse response, SqlDataSetSqlExecutionException exception)
{
setOperationMessageForThrowable(request, buildMessageCode(SqlDataSetSqlExecutionException.class), exception,
false, exception.getMessage());
false, exception.getMessage(), exception.getSql());
return getErrorView(request, response);
}

View File

@ -28,7 +28,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.datagear.analysis.Chart;
import org.datagear.analysis.DashboardResult;
import org.datagear.analysis.RenderContext;
import org.datagear.analysis.TemplateDashboardWidgetResManager;
@ -1037,8 +1036,8 @@ public class DashboardController extends AbstractDataAnalysisController implemen
HtmlTplDashboard dashboard = dashboardWidget.render(renderContext, template);
SessionHtmlTplDashboardManager dashboardManager = getSessionHtmlTplDashboardManagerNotNull(request);
dashboardManager.put(dashboard);
SessionDashboardInfoManager dashboardInfoManager = getSessionDashboardInfoManagerNotNull(request);
dashboardInfoManager.put(new DashboardInfo(dashboard));
}
finally
{
@ -1061,8 +1060,8 @@ public class DashboardController extends AbstractDataAnalysisController implemen
public ErrorMessageDashboardResult showData(HttpServletRequest request, HttpServletResponse response,
org.springframework.ui.Model model, @RequestBody DashboardQueryForm form) throws Exception
{
WebContext webContext = createWebContext(request);
DashboardResult dashboardResult = getDashboardResult(request, response, model, webContext, form);
DashboardResult dashboardResult = getDashboardResult(request, form,
this.htmlTplDashboardWidgetEntityService.getHtmlTplDashboardWidgetRenderer());
return new ErrorMessageDashboardResult(dashboardResult, true);
}
@ -1082,13 +1081,19 @@ public class DashboardController extends AbstractDataAnalysisController implemen
@RequestParam(LOAD_CHART_PARAM_DASHBOARD_ID) String dashboardId,
@RequestParam(LOAD_CHART_PARAM_CHART_WIDGET_ID) String[] chartWidgetIds) throws Throwable
{
SessionHtmlTplDashboardManager dashboardManager = getSessionHtmlTplDashboardManagerNotNull(request);
HtmlTplDashboard dashboard = dashboardManager.get(dashboardId);
User user = WebUtils.getUser(request, response);
if (dashboard == null)
SessionDashboardInfoManager dashboardInfoManager = getSessionDashboardInfoManagerNotNull(request);
DashboardInfo dashboardInfo = dashboardInfoManager.get(dashboardId);
if (dashboardInfo == null)
throw new RecordNotFoundException();
HtmlTplDashboardWidgetEntity dashboardWidget = (HtmlTplDashboardWidgetEntity) dashboard.getWidget();
HtmlTplDashboardWidgetEntity dashboardWidget = this.htmlTplDashboardWidgetEntityService
.getHtmlTplDashboardWidget(user, dashboardInfo.getDashboardWidgetId());
if (dashboardWidget == null)
throw new RecordNotFoundException();
// 确保看板创建用户对看板模板内定义的图表有权限
ChartWidgetSourceContext.set(new ChartWidgetSourceContext(dashboardWidget.getCreateUser()));
@ -1099,9 +1104,7 @@ public class DashboardController extends AbstractDataAnalysisController implemen
try
{
for (int i = 0; i < chartWidgetIds.length; i++)
{
chartWidgets[i] = dashboardWidgetRenderer.getHtmlChartWidget(chartWidgetIds[i]);
}
// 不缓存
response.setContentType(CONTENT_TYPE_JSON);
@ -1109,14 +1112,11 @@ public class DashboardController extends AbstractDataAnalysisController implemen
HtmlChart[] charts = this.htmlChartWidgetJsonWriter.write(out, chartWidgets);
synchronized (dashboard)
{
List<Chart> dashboardCharts = dashboard.getCharts();
List<Chart> newCharts = (dashboardCharts == null || dashboardCharts.isEmpty() ? new ArrayList<>()
: new ArrayList<>(dashboardCharts));
newCharts.addAll(Arrays.asList(charts));
dashboard.setCharts(newCharts);
}
Map<String, String> chartIdToChartWidgetIds = new HashMap<String, String>();
for (int i = 0; i < chartWidgetIds.length; i++)
chartIdToChartWidgetIds.put(charts[i].getId(), chartWidgetIds[i]);
dashboardInfo.putChartWidgetIds(chartIdToChartWidgetIds);
}
finally
{

View File

@ -9,6 +9,7 @@ package org.datagear.web.controller;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
@ -219,15 +220,43 @@ public class UserController extends AbstractController
return "/user/user_form";
}
@RequestMapping(value = "/delete", produces = CONTENT_TYPE_JSON)
@ResponseBody
public ResponseEntity<OperationMessage> delete(HttpServletRequest request, HttpServletResponse response,
@RequestBody String[] ids)
@RequestMapping("/delete")
public String delete(HttpServletRequest request, HttpServletResponse response, org.springframework.ui.Model model,
@RequestParam("id") String[] ids)
{
this.userService.deleteByIds(ids);
if (isEmpty(ids))
throw new IllegalInputException();
this.schemaService.deleteByUserId(ids);
// TODO 应该删除所有其他用户创建的数据
List<User> users = this.userService.getByIdsNoPassword(ids, true);
model.addAttribute("deleteUsers", toWriteJsonTemplateModel(users));
model.addAttribute(KEY_TITLE_MESSAGE_KEY, "user.deleteUser");
model.addAttribute(KEY_FORM_ACTION, "deleteDo");
return "/user/user_delete";
}
@RequestMapping(value = "/deleteDo", produces = CONTENT_TYPE_JSON)
@ResponseBody
public ResponseEntity<OperationMessage> deleteDo(HttpServletRequest request, HttpServletResponse response,
@RequestBody DeleteUserForm form)
{
if (isEmpty(form.getIds()) || isEmpty(form.getMigrateToId()))
throw new IllegalInputException();
if (Arrays.asList(form.getIds()).contains(form.getMigrateToId()))
throw new IllegalInputException();
if (User.containsAdminUser(form.getIds()))
return buildOperationMessageFailResponseEntity(request, HttpStatus.BAD_REQUEST,
buildMessageCode("deleteAdminUserDenied"));
User user = this.userService.getById(form.getMigrateToId());
if (user == null)
throw new IllegalInputException();
this.userService.deleteByIds(form.getIds(), form.getMigrateToId());
return buildOperationMessageDeleteSuccessResponseEntity(request);
}
@ -368,4 +397,40 @@ public class UserController extends AbstractController
this.confirmPassword = confirmPassword;
}
}
public static class DeleteUserForm implements Serializable
{
private static final long serialVersionUID = 1L;
/** 要删除的用户ID */
private String[] ids;
/** 数据迁移的目标用户ID */
private String migrateToId;
public DeleteUserForm()
{
super();
}
public String[] getIds()
{
return ids;
}
public void setIds(String[] ids)
{
this.ids = ids;
}
public String getMigrateToId()
{
return migrateToId;
}
public void setMigrateToId(String migrateToId)
{
this.migrateToId = migrateToId;
}
}
}

View File

@ -50,7 +50,7 @@ public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHa
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException
{
mergeAnonymousUserEntities(request, response, authentication);
migrateAnonymousUserData(request, response, authentication);
String redirectPath = WebUtils.getContextPath(request);
@ -68,7 +68,7 @@ public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHa
* @param response
* @param loginUser
*/
protected void mergeAnonymousUserEntities(HttpServletRequest request, HttpServletResponse response,
protected void migrateAnonymousUserData(HttpServletRequest request, HttpServletResponse response,
Authentication authentication)
{
User user = WebUtils.getUser(authentication);

View File

@ -4,6 +4,10 @@
#当系统作为war包部署至Servlet容器时将加载这里配置项
#-----------------------------------------
#清理临时目录
#执行清理时间间隔
cleanTempDirectory.interval=0 0 1 * * ?
#日志级别
#ERROR, WARN, INFO, DEBUG, TRACE
logging.level.org.datagear=INFO

View File

@ -59,8 +59,8 @@ defaultRole.anonymous=ROLE_DATA_ADMIN
#清理临时目录
#可删除的过期文件分钟数
cleanTempDirectory.expiredMinutes=1440
#执行清理间隔
cleanTempDirectory.interval=0 0 1 * * ?
#执行清理时间间隔
cleanTempDirectory.interval=0 0/10 * * * ?
#数据库
datasource.driverClassName=org.apache.derby.jdbc.EmbeddedDriver

View File

@ -515,3 +515,9 @@ DataGear版本更新日志
改进:看板编辑页面插入图表对话框改为悬浮面板,便于多次插入图表操作;
改进:登录页、注册页、重置密码页添加右上角系统菜单;
改进程序发布包配置文件中添加DataGearWorkspace配置项模板
-----------------------------------------
--v2.9.0
-----------------------------------------

View File

@ -377,6 +377,7 @@ user.viewUser=查看用户
user.manageUser=管理用户
user.selectUser=选择用户
user.personalSet=个人设置
user.deleteUser=删除用户
user.id=ID
user.name=用户名
user.password=密码
@ -387,9 +388,12 @@ user.createTime=创建日期
user.roles=角色
user.confirmPassword=确认密码
user.validation.confirmPasswordError=与[密码]项不一致
user.validation.migrateToUserIdIllegal=不能选择待删除的用户
user.confirmDelete=确定删除选中的用户吗?用户创建的数据源也会被删除
user.deleteAdminUserDenied=管理员账号不允许删除
user.userNameExists=用户[{0}]已存在
user.migrateDataToUser=数据迁移至
user.migrateDataToUser.desc=将待删除用户的所有数据迁移至此用户
#about
about.about=关于

View File

@ -377,6 +377,7 @@ user.viewUser=View user
user.manageUser=Manage user
user.selectUser=Select user
user.personalSet=Personal set
user.deleteUser=Delete user
user.id=ID
user.name=User name
user.password=Password
@ -387,9 +388,12 @@ user.createTime=Create time
user.roles=Roles
user.confirmPassword=Confirm password
user.validation.confirmPasswordError=Must be the same with [Password]
user.validation.migrateToUserIdIllegal=Must select user out of deleting list
user.confirmDelete=Confirm delete selected user? All data related will be deleted also
user.deleteAdminUserDenied=Administrator user can not be deleted
user.userNameExists=User [{0}] already exists
user.migrateDataToUser=Migrate data to
user.migrateDataToUser.desc=Migrate their data to this user
#about
about.about=About

View File

@ -109,22 +109,57 @@
.dg-chart-label{
position: relative;
}
.dg-chart-label .dg-chart-label-wrapper{
}
.dg-chart-label .dg-chart-label-wrapper .dg-chart-label-item .label-name{
.dg-chart-label .dg-chart-label-item .label-name{
text-align: center;
}
.dg-chart-label .dg-chart-label-wrapper .dg-chart-label-item .label-value{
.dg-chart-label .dg-chart-label-item .label-value{
text-align: center;
font-size: 1.5em;
font-weight: bold;
}
.dg-chart-label .dg-chart-label-wrapper.dg-chart-label-inline,
.dg-chart-label .dg-chart-label-wrapper.dg-chart-label-inline .dg-chart-label-item,
.dg-chart-label .dg-chart-label-wrapper.dg-chart-label-inline .dg-chart-label-item .label-name,
.dg-chart-label .dg-chart-label-wrapper.dg-chart-label-inline .dg-chart-label-item .label-value{
.dg-chart-label.dg-chart-label-inline .dg-chart-label-item,
.dg-chart-label.dg-chart-label-inline .dg-chart-label-item .label-name,
.dg-chart-label.dg-chart-label-inline .dg-chart-label-item .label-value{
display: inline-block;
}
.dg-chart-label.dg-chart-label-flex{
display: flex;
flex-wrap: wrap;
align-items: center;
}
.dg-chart-label.dg-chart-label-flex.dg-chart-label-flex-around{
justify-content: space-around;
}
.dg-chart-label.dg-chart-label-flex.dg-chart-label-flex-start{
justify-content: flex-start;
}
.dg-chart-label.dg-chart-label-flex.dg-chart-label-flex-end{
justify-content: flex-end;
}
.dg-chart-label.dg-chart-label-flex.dg-chart-label-flex-center{
justify-content: center;
}
.dg-chart-label.dg-chart-label-flex.dg-chart-label-flex-between{
justify-content: space-between;
}
/*下拉框图表*/
.dg-chart-select{}
.dg-chart-select.dg-chart-select-fill{
position: relative;
}
.dg-chart-select.dg-chart-select-fill .dg-chart-select-select{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
/*数据集参数值表单*/
.dg-dspv-form{}

View File

@ -1415,6 +1415,9 @@ table.dataTable tbody tr td select{
.page-form-user .selectUserRoleBtn{
vertical-align: top;
}
.page-form-user-delete .delete-users{
display: inline-block;
}
/*驱动信息管理表单页*/
.page-form-driverEntity{
@ -2610,6 +2613,7 @@ table.dataTable tbody tr td select{
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
resize: none;
}
.page-form-dataSet .workspace .workspace-operation-wrapper .preview-result-table-wrapper .result-data-max-count{
float: left;
@ -2625,6 +2629,23 @@ table.dataTable tbody tr td select{
width: 100%;
font-size: 0.8em;
}
.page-form-dataSet .workspace .workspace-operation-wrapper .preview-result-table-wrapper .preview-error-info{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: none;
}
.page-form-dataSet .workspace .workspace-operation-wrapper .preview-result-table-wrapper .preview-error-info textarea{
width: 100%;
height: 100%;
margin: 0 0;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
resize: none;
}
.page-form-dataSet .workspace .workspace-operation-wrapper .input-in-table{
width: 90%!important;
}

View File

@ -1,3 +0,0 @@
注意:
项目使用的是有改动的echarts.js参考第5883行而非echarts.min.js因为官网发布版对与关系地图支持有BUG。

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -193,13 +193,19 @@
chartFactory.CHART_EVENT_CHART_TYPE_HTML = "html";
/**内置名字标识片段*/
chartFactory.BUILT_IN_NAME_PART = "datagear";
chartFactory._BUILT_IN_NAME_PART = "datagear";
/**内置名字标识片段*/
chartFactory.BUILT_IN_NAME_UNDERSCORE_PREFIX = "_" + chartFactory.BUILT_IN_NAME_PART;
chartFactory._BUILT_IN_NAME_UNDERSCORE_PREFIX = "_" + chartFactory._BUILT_IN_NAME_PART;
/**数据对象的原始信息属性名*/
chartFactory.DATA_ORIGINAL_INFO_PROP_NAME = chartFactory.BUILT_IN_NAME_UNDERSCORE_PREFIX + "OriginalInfo";
chartFactory._DATA_ORIGINAL_INFO_PROP_NAME = chartFactory._BUILT_IN_NAME_UNDERSCORE_PREFIX + "OriginalInfo";
/**图表主题的CSS信息属性名*/
chartFactory._KEY_THEME_STYLE_SHEET_INFO = chartFactory._BUILT_IN_NAME_UNDERSCORE_PREFIX + "StyleSheetInfo";
/** 关键字注册得ECharts主题名 */
chartFactory._KEY_REGISTERED_ECHARTS_THEME_NAME = chartFactory._BUILT_IN_NAME_UNDERSCORE_PREFIX + "RegisteredEchartsThemeName";
/**
* 图表使用的渲染上下文属性名
@ -315,10 +321,10 @@
if(theme.color && theme.actualBackgroundColor)
{
if(!theme.legendColor)
theme.legendColor = chartFactory.getGradualColor(theme, 0.8);
theme.legendColor = chartFactory.gradualColor(theme, 0.8);
if(!theme.borderColor)
theme.borderColor = chartFactory.getGradualColor(theme, 0.3);
theme.borderColor = chartFactory.gradualColor(theme, 0.3);
if(!theme.tooltipTheme)
{
@ -326,9 +332,9 @@
{
name: "tooltipTheme",
color: theme.actualBackgroundColor,
backgroundColor: chartFactory.getGradualColor(theme, 0.7),
actualBackgroundColor: chartFactory.getGradualColor(theme, 0.7),
borderColor: chartFactory.getGradualColor(theme, 0.9),
backgroundColor: chartFactory.gradualColor(theme, 0.7),
actualBackgroundColor: chartFactory.gradualColor(theme, 0.7),
borderColor: chartFactory.gradualColor(theme, 0.9),
borderWidth: 1,
gradient: theme.gradient
};
@ -342,9 +348,9 @@
{
name: "highlightTheme",
color: theme.actualBackgroundColor,
backgroundColor: chartFactory.getGradualColor(theme, 0.8),
actualBackgroundColor: chartFactory.getGradualColor(theme, 0.8),
borderColor: chartFactory.getGradualColor(theme, 1),
backgroundColor: chartFactory.gradualColor(theme, 0.8),
actualBackgroundColor: chartFactory.gradualColor(theme, 0.8),
borderColor: chartFactory.gradualColor(theme, 1),
borderWidth: 1,
gradient: theme.gradient
};
@ -387,21 +393,6 @@
delete chart.resultDataFormat;
};
/**
* 获取/设置图表的内置扩展属性值
* chart.extValue()是允许用户级使用的此函数应用于内置设置/获取操作可避免属性名冲突
*
* @param chart 图表对象
* @param name 扩展属性名
* @param value 可选要设置的扩展属性值不设置则执行获取操作
*/
chartFactory.extValueBuiltin = function(chart, name, value)
{
name = chartFactory.BUILT_IN_NAME_UNDERSCORE_PREFIX+"_" + name;
return chart.extValue(name, value);
};
//----------------------------------------
// chartBase start
//----------------------------------------
@ -951,8 +942,10 @@
if(chartFactory.renderedChart($element) != null)
throw new Error("Chart element '#"+this.elementId+"' has been rendered");
this._createChartEleThemeCssIfNon();
$element.addClass(this.themeStyleName());
$element.data(chartFactory._KEY_ELEMENT_RENDERED_CHART, this);
chartFactory.setThemeStyle($element, this.theme());
this.statusRendering(true);
@ -968,6 +961,35 @@
}
};
chartBase._createChartEleThemeCssIfNon = function()
{
var thisChart = this;
this.themeStyleSheet(chartFactory.builtinPropName("ChartEle"), function()
{
var theme = thisChart.theme();
var css=
{
name: "",
value:
{
"color": theme.color,
"background-color": theme.backgroundColor,
"border-color": theme.borderColor
}
};
if(theme.borderWidth)
{
css.value["border-width"] = theme.borderWidth;
css.value["border-style"] = "solid";
}
return css;
});
};
/**
* 调用底层图表渲染器的render函数执行渲染
*/
@ -1095,6 +1117,8 @@
var $element = this.elementJquery();
this.statusDestroyed(true);
$element.removeClass(this.themeStyleName());
$element.data(chartFactory._KEY_ELEMENT_RENDERED_CHART, null);
var renderer = this.renderer();
@ -2391,7 +2415,7 @@
*/
chartBase._isEchartsInstance = function(obj)
{
return (obj && obj.constructor && obj.constructor.name && /ECharts/i.test(obj.constructor.name));
return (obj && obj.setOption && obj.isDisposed && obj.dispose && obj.off);
};
/**
@ -2404,21 +2428,16 @@
//从ChartTheme构建ECharts主题
if(!themeName)
{
var chartTheme = this.theme();
var theme = this.theme();
themeName = theme[chartFactory._KEY_REGISTERED_ECHARTS_THEME_NAME];
if(!chartTheme._registeredEchartsThemeName)
if(!themeName)
{
var seq = (chartFactory._REGISTERED_ECHARTS_THEME_NAME_SEQ != null ?
chartFactory._REGISTERED_ECHARTS_THEME_NAME_SEQ : 0);
chartFactory._REGISTERED_ECHARTS_THEME_NAME_SEQ = seq + 1;
themeName = (theme[chartFactory._KEY_REGISTERED_ECHARTS_THEME_NAME] = chartFactory.nextElementId());
chartTheme._registeredEchartsThemeName = chartFactory.BUILT_IN_NAME_UNDERSCORE_PREFIX + "EChartsThemeByChartTheme" + seq;
var echartsTheme = chartFactory.buildEchartsTheme(chartTheme);
echarts.registerTheme(chartTheme._registeredEchartsThemeName, echartsTheme);
var echartsTheme = chartFactory.buildEchartsTheme(theme);
echarts.registerTheme(themeName, echartsTheme);
}
themeName = chartTheme._registeredEchartsThemeName;
}
return themeName;
@ -2784,7 +2803,7 @@
resultDataIndex = undefined;
}
var pname = chartFactory.DATA_ORIGINAL_INFO_PROP_NAME;
var pname = chartFactory._DATA_ORIGINAL_INFO_PROP_NAME;
var isArray = $.isArray(data);
@ -2968,7 +2987,7 @@
}
theme = (theme == null ? this.theme() : theme);
return chartFactory.getGradualColor(theme, factor);
return chartFactory.gradualColor(theme, factor);
};
/**
@ -2998,6 +3017,50 @@
}
};
/**
* 获取图表主题对应的CSS类名
* 图表在渲染前会自动为图表元素添加这个CSS类
*
* @returns CSS类名
*/
chartBase.themeStyleName = function()
{
var theme = this.theme();
var pn = chartFactory.builtinPropName("ChartEleStyleName");
var sn = theme[pn];
if(!sn)
sn = (theme[pn] = chartFactory.nextElementId());
return sn;
};
/**
* 获取/设置与此图表主题和指定名称关联的CSS样式表
* 设置的CSS样式都会添加chartBase.themeStyleName()函数返回的类名选择器前缀因此只会影响使用了相同主题的图表
* 同一图表主题和名称的CSS样式表通常仅需创建一次因此此函数的建议使用方式如下
* chart.themeStyleSheet("...", function(){ return ...; });
*
* @param name 名称
* @param css 可选参考chartFactory.themeStyleSheet()的css参数
* @param force 可选参考chartFactory.themeStyleSheet()的force参数
*
* @returns 样式表<style>元素的ID没有设置过则返回undefined
*/
chartBase.themeStyleSheet = function(name, css, force)
{
var theme = this.theme();
if(arguments.length == 1)
return chartFactory.themeStyleSheet(theme, name);
else
{
var cssNamePrefix = "." + this.themeStyleName();
return chartFactory.themeStyleSheet(theme, name, css, cssNamePrefix, force);
}
};
//-------------
// < 已弃用函数 start
//-------------
@ -3199,6 +3262,128 @@
// chartBase end
//----------------------------------------
/**
* 获取/设置与指定主题和名称关联的CSS样式表
* 同一主题和名称的CSS样式表通常仅需创建一次因此此函数的建议使用方式如下
* chartFactory.themeStyleSheet({ ... }, "...", function(){ return ...; }, "...");
*
* @param theme 主题对象格式为{ ... }
* @param name 名称
* @param css 可选要设置的CSS格式为
* function(){ return CSS样式表对象[ CSS样式表对象, ... ] }
* 或者
* CSS样式表对象
* 或者
* [ CSS样式表对象, ... ]
* 其中CSS样式表对象格式为
* {
* //CSS选择器例如" .success"、".success"、" .error"、[ ".success", " .error" ]
* name: "..."["...", ...],
* //CSS属性对象、CSS属性字符串例如
* //{ 'color': 'red', 'background-color': 'blue' }、
* //"color:red;background-color:blue;"
* value: { CSS属性名 : CSS属性值, ... }"..."
* }
* @param cssNamePrefix 可选当指定了css时设置统一得CSS选择器前缀
* @param force 可选当指定了css时是否强制执行设置true 强制设置false 只有name对应的样式表不存在时才设置默认值为false
*
* @returns 样式表<style>元素的ID没有设置过则返回undefined
*/
chartFactory.themeStyleSheet = function(theme, name, css, cssNamePrefix, force)
{
//(theme, name, css, true)、(theme, name, css, false)
if(force === undefined && (cssNamePrefix === true || cssNamePrefix === false))
{
force = cssNamePrefix;
cssNamePrefix = undefined;
}
var infoMap = theme[chartFactory._KEY_THEME_STYLE_SHEET_INFO];
if(infoMap == null)
infoMap = (theme[chartFactory._KEY_THEME_STYLE_SHEET_INFO] = {});
var styleId = infoMap[name];
if(css === undefined)
return styleId;
if(styleId && (force != true))
return styleId;
var cssText = "";
if($.isFunction(css))
css = css();
if(!$.isArray(css))
css = [ css ];
for(var i=0; i<css.length; i++)
{
var cssName = css[i].name;
var cssValue = css[i].value;
if(cssName == null)
continue;
if(!$.isArray(cssName))
cssName = [ cssName ];
for(var j=0; j<cssName.length; j++)
{
cssText += (cssNamePrefix ? cssNamePrefix + cssName[j] : cssName[j]);
if(j < (cssName.length - 1))
cssText += ",\n";
}
cssText += "{\n";
if(cssValue)
{
if(typeof(cssValue) == "string")
cssText += cssValue;
else
{
for(var p in cssValue)
cssText += p + ":" + cssValue[p]+";\n";
}
}
cssText += "}\n";
}
if(!styleId)
styleId = (infoMap[name] = chartFactory.nextElementId());
chartFactory.styleSheetText(styleId, cssText);
return styleId;
};
/**
* 获取内置属性名添加内置前缀
* 内置属性名以'_'开头
*/
chartFactory.builtinPropName = function(name)
{
return chartFactory._BUILT_IN_NAME_UNDERSCORE_PREFIX + name;
};
/**
* 获取/设置图表的内置扩展属性值
* chart.extValue()是允许用户级使用的此函数应用于内置设置/获取操作可避免属性名冲突
*
* @param chart 图表对象
* @param name 扩展属性名
* @param value 可选要设置的扩展属性值不设置则执行获取操作
*/
chartFactory.extValueBuiltin = function(chart, name, value)
{
name = chartFactory.builtinPropName(name);
return chart.extValue(name, value);
};
/**
* 获取/设置渲染上下文的属性值
*
@ -3271,7 +3456,7 @@
};
/** HTML元素上已渲染的图表对象KEY */
chartFactory._KEY_ELEMENT_RENDERED_CHART = chartFactory.BUILT_IN_NAME_UNDERSCORE_PREFIX + "_renderedChart";
chartFactory._KEY_ELEMENT_RENDERED_CHART = chartFactory._BUILT_IN_NAME_UNDERSCORE_PREFIX + "RenderedChart";
/**
* 获取当前在指定HTML元素上渲染的图表对象返回null表示元素上并未渲染图表
@ -3287,7 +3472,7 @@
};
/** 生成元素ID用的前缀 */
chartFactory._ELEMENT_ID_PREFIX = chartFactory.BUILT_IN_NAME_PART + new Number(new Date().getTime()).toString(16);
chartFactory._ELEMENT_ID_PREFIX = chartFactory._BUILT_IN_NAME_PART + new Number(new Date().getTime()).toString(16);
/**
* 执行JS代码
@ -3311,96 +3496,6 @@
return (re || defaultValue);
};
/**
* 解析JSON
* 如果参数不合法将返回空对象{}
*/
chartFactory.parseJSONSilently = function(str)
{
if(!str)
return {};
try
{
if(typeof($) != "undefined" && $.parseJSON)
return $.parseJSON(str);
else
return JSON.parse(str);
}
catch(e)
{
chartFactory.logException(e);
}
return {};
};
/**
* 将不符合JSON规范的字符串定义规范化属性名添加双引号或将属性名单引号替换为双引号
*/
chartFactory.trimJSONString = function(str)
{
if(!str)
return str;
//替换单引号为双引号
var str1 = "";
for(var i=0; i<str.length;i++)
{
var c = str.charAt(i);
if(c == '\\')
{
str1 += c;
i = i+1;
str1 += str.charAt(i);
}
else if(c == '\'')
str1 += '"';
else
str1 += c;
}
str = str1;
//属性名匹配表达式
var reg = /([{,]\s*)([^\:\s]*)(\s*:)/g;
return str.replace(reg, function(token, prefix, name, suffix)
{
var len = name.length;
if(len > 1 && name.charAt(0) == '"' && name.charAt(len-1) == '"')
return token;
else if(len > 1 && name.charAt(0) == '\'' && name.charAt(len-1) == '\'')
{
name = '"' + name.substring(1, len-1) + '"';
return prefix + name + suffix;
}
else
return prefix + '"' + name + '"' + suffix;
});
};
/**
* 将对象转换为JSON字符串
*/
chartFactory.toJSONString = function(obj)
{
return JSON.stringify(obj);
};
/**
* 为元素设置主题样式
*
* @param element HTML元素Jquery对象
* @param theme 主题对象
*/
chartFactory.setThemeStyle = function(element, theme)
{
return this.setStyles(element, theme);
};
/**
* 为元素设置样式集
*
@ -3457,21 +3552,24 @@
return (element.attr("style") || "");
};
chartFactory._KEY_GRADUAL_COLORS = chartFactory._BUILT_IN_NAME_UNDERSCORE_PREFIX + "GradualColors";
/**
* 获取主题从背景色actualBackgroundColor到前景色color之间的渐变因子对应的颜色
* 这个颜色是实际背景色actualBackgroundColor与前景色color之间的某个颜色
*
* @param theme
* @param factor 可选渐变因子0-1之间的小数
* @returns 上述factor对应的颜色当未设置factor时将返回一个包含所有渐变颜色的数组
* @param theme 主题对象格式为{ color: "...", actualBackgroundColor: "..." }
* @param factor 可选渐变因子0-1之间的小数其中0表示最接近实际背景色的颜色1表示最接近前景色的颜色
* @returns factor匹配的颜色字符串格式类似"#FFFFFF"如果未设置factor将返回一个包含所有渐变颜色的数组
*/
chartFactory.getGradualColor = function(theme, factor)
chartFactory.gradualColor = function(theme, factor)
{
var gcs = theme._gradualColors;
var gcs = theme[chartFactory._KEY_GRADUAL_COLORS];
if(!gcs || gcs.length == 0)
{
gcs = this.evalGradualColors(theme.actualBackgroundColor, theme.color, (theme.gradient || 10));
theme._gradualColors = gcs;
theme[chartFactory._KEY_GRADUAL_COLORS] = gcs;
}
if(factor == null)
@ -3600,55 +3698,55 @@
};
/**
* 创建CSS样式表
*
* @param id 样式表元素ID
* @param cssText 样式文本
* @param position 可选插入位置"first""last""beforeFirstScript"第一个<script>节点之前DOM插入其前面默认值为"last"
* 设置指定ID的样式表css文本
* 如果样式表不存在将会自动创建且会插入<head>中的靠前位置确保其css效果优先级低于用户定义的css
*
* @param styleId 样式表元素ID
* @param cssText css文本内容
*/
chartFactory.createStyleSheet = function(id, cssText, position)
chartFactory.styleSheetText = function(styleId, cssText)
{
if(!position)
position = "last";
var $style = $("#" + styleId);
var head = (document.head || document.getElementsByTagName("head")[0]);
var style = document.createElement("style");
var beforeNode = null;
if(position === "last")
if($style.length > 0)
{
}
else if(position === "first")
{
beforeNode = head.firstChild;
}
else if(position === "beforeFirstScript")
{
var childNodes = (head.childNodes || []);
for(var i=0; i<childNodes.length; i++)
{
if((childNodes[i].tagName || "").toLowerCase() == "script")
{
beforeNode = childNodes[i];
break;
}
}
$style.text(cssText);
return;
}
if(beforeNode)
head.insertBefore(style, beforeNode);
else
head.appendChild(style);
style.id = id;
style.type = "text/css";
// 旧版IE
if (style.styleSheet)
style.styleSheet.cssText = cssText;
else
style.appendChild(document.createTextNode(cssText));
$style = $("<style />").attr("id", styleId)
.attr("dg-generated-style", "true").attr("type", "text/css").text(cssText);
var $head = $("head:first");
var $lastGenStyle = $("style[dg-generated-style]:last", $head);
//后插入的优先级应高于先插入的
if($lastGenStyle.length > 0)
{
$lastGenStyle.after($style);
return;
}
var $lastImport = $("[dg-import-name]:last", $head);
//优先级应高于导入的资源
if($lastImport.length > 0)
{
$lastImport.after($style);
return;
}
var $lastLink = $("link:last", $head);
//优先级应高于link的css
if($lastLink.length > 0)
{
$lastLink.after($style);
return;
}
$head.prepend($style);
};
/**
@ -3665,6 +3763,7 @@
/**
* 生成一个新的页面元素ID
* 这个ID仅包含[a-z][A-Z][0-9]且以字母开头
*
* @param prefix 可选ID前缀
*/
@ -3751,13 +3850,13 @@
*/
chartFactory.buildEchartsTheme = function(chartTheme)
{
var axisColor = this.getGradualColor(chartTheme, 0.7);
var axisScaleLineColor = this.getGradualColor(chartTheme, 0.35);
var areaColor0 = this.getGradualColor(chartTheme, 0.15);
var areaBorderColor0 = this.getGradualColor(chartTheme, 0.3);
var areaColor1 = this.getGradualColor(chartTheme, 0.25);
var areaBorderColor1 = this.getGradualColor(chartTheme, 0.5);
var shadowColor = this.getGradualColor(chartTheme, 0.9);
var axisColor = chartFactory.gradualColor(chartTheme, 0.7);
var axisScaleLineColor = chartFactory.gradualColor(chartTheme, 0.35);
var areaColor0 = chartFactory.gradualColor(chartTheme, 0.15);
var areaBorderColor0 = chartFactory.gradualColor(chartTheme, 0.3);
var areaColor1 = chartFactory.gradualColor(chartTheme, 0.25);
var areaBorderColor1 = chartFactory.gradualColor(chartTheme, 0.5);
var shadowColor = chartFactory.gradualColor(chartTheme, 0.9);
// < @deprecated 兼容1.8.1版本有ChartTheme.axisColor的结构
if(chartTheme.axisColor)

View File

@ -115,7 +115,10 @@
//创建表单样式表
if(options.chartTheme)
chartSetting.setDataSetParamValueFormStyle($form, options.chartTheme);
{
var styleName = chartSetting.dataSetParamValueFormThemeStyle(options.chartTheme);
$form.addClass(styleName);
}
var $head = $(".dg-dspv-form-head", $form);
var $content = $(".dg-dspv-form-content", $form);
@ -237,64 +240,85 @@
return formEle;
};
chartSetting.setDataSetParamValueFormStyle = function($form, chartTheme)
chartSetting.dataSetParamValueFormThemeStyle = function(chartTheme)
{
var styleClassName = chartTheme._dataSetParamValueFormStyleClassName;
if(!styleClassName)
var styleNameKey = chartFactory.builtinPropName("DataSetParamValueFormStyleName");
var styleName = chartTheme[styleNameKey];
if(styleName)
return styleName;
styleName = (chartTheme[styleNameKey] = chartFactory.nextElementId());
chartFactory.themeStyleSheet(chartTheme, chartFactory.builtinPropName("DataSetParamValueForm"), function()
{
styleClassName = chartFactory.nextElementId();
chartTheme._dataSetParamValueFormStyleClassName = styleClassName;
}
var color = chartFactory.gradualColor(chartTheme, 1);
var bgColor = chartFactory.gradualColor(chartTheme, 0);
var borderColor = chartFactory.gradualColor(chartTheme, 0.5);
var cssPrefix = "." + styleName + ".dg-dspv-form";
var css =
[
{
name: cssPrefix,
value:
{
"color": color,
"background-color": bgColor,
"border-color": borderColor
}
},
{
name:
[
cssPrefix + " .dg-dspv-form-item-value input",
cssPrefix + " .dg-dspv-form-item-value textarea",
cssPrefix + " .dg-dspv-form-item-value select",
cssPrefix + " .dg-dspv-form-item-value select option",
cssPrefix + " .dg-dspv-form-item-value .input"
],
value:
{
"color": color,
"background-color": bgColor,
"border-color": borderColor
}
},
{
name:
[
cssPrefix + " button",
cssPrefix + " input[type=button]",
cssPrefix + " input[type=submit]",
cssPrefix + " .button"
],
value:
{
"color": color,
"background-color": chartFactory.gradualColor(chartTheme, 0.1),
"border-color": borderColor
}
},
{
name:
[
cssPrefix + " button:hover",
cssPrefix + " input[type=button]:hover",
cssPrefix + " input[type=submit]:hover",
cssPrefix + " .button:hover"
],
value:
{
"background-color": chartFactory.gradualColor(chartTheme, 0.3)
}
}
];
return css;
});
$form.addClass(styleClassName);
var styleId = (chartTheme._dataSetParamValueFormStyleSheetId
|| (chartTheme._dataSetParamValueFormStyleSheetId = chartFactory.nextElementId()));
if(chartFactory.isStyleSheetCreated(styleId))
return false;
var qualifier = "." + styleClassName;
var color = chartFactory.getGradualColor(chartTheme, 1);
var bgColor = chartFactory.getGradualColor(chartTheme, 0);
var borderColor = chartFactory.getGradualColor(chartTheme, 0.5);
var hoverColor = chartFactory.getGradualColor(chartTheme, 0.3);
var cssText =
qualifier + ".dg-dspv-form{"
+" color: "+color+";"
+" background: "+bgColor+";"
+" border-color: "+borderColor+";"
+" }\n"
+qualifier + ".dg-dspv-form .dg-dspv-form-item-value input,\n"
+qualifier + ".dg-dspv-form .dg-dspv-form-item-value textarea,\n"
+qualifier + ".dg-dspv-form .dg-dspv-form-item-value select,\n"
+qualifier + ".dg-dspv-form .dg-dspv-form-item-value select option,\n"
+qualifier + ".dg-dspv-form .dg-dspv-form-item-value .input{"
+" color: "+color+";"
+" background: "+bgColor+";"
+" border-color: "+borderColor+";"
+" }\n"
+qualifier + ".dg-dspv-form button,\n"
+qualifier + ".dg-dspv-form input[type=button],\n"
+qualifier + ".dg-dspv-form input[type=submit],\n"
+qualifier + ".dg-dspv-form .button{"
+" color: "+color+";"
+" background: "+chartFactory.getGradualColor(chartTheme, 0.1)+";"
+" border-color: "+borderColor+";"
+"}\n"
+qualifier + ".dg-dspv-form button:hover,\n"
+qualifier + ".dg-dspv-form input[type=button]:hover,\n"
+qualifier + ".dg-dspv-form input[type=submit]:hover,\n"
+qualifier + ".dg-dspv-form .button:hover{"
+" background: "+chartFactory.getGradualColor(chartTheme, 0.3)+";"
+" }\n"
;
chartFactory.createStyleSheet(styleId, cssText, "beforeFirstScript");
return true;
return styleName;
};
/**
@ -657,6 +681,8 @@
$input.attr("dg-validation-number", "true");
};
chartSetting._DATETIME_PICKER_ROOT_ID = chartFactory._BUILT_IN_NAME_PART + "DatetimepickerRoot";
chartSetting.datetimepicker = function($input, datetimepickerOptions, chartTheme)
{
//在这里检查并重写,避免依赖加载顺序
@ -668,22 +694,24 @@
chartSetting._datetimepickerSetLocale = true;
}
var $rootWrapper = $("#" + chartSetting._DATETIME_PICKER_ROOT_ID);
if($rootWrapper.length < 1)
$rootWrapper = $("<div />").attr("id", chartSetting._DATETIME_PICKER_ROOT_ID).appendTo(document.body);
var wrapperId = chartFactory.nextElementId();
var $wrapper = $("<div />").attr("id", wrapperId).appendTo($rootWrapper);
if(chartTheme)
{
var containerId = (chartTheme._datetimepickerContainerId
|| (chartTheme._datetimepickerContainerId = chartFactory.nextElementId()));
var container = document.getElementById(containerId);
if(!container)
container = $("<div class='dg-dspv-datetimepicker-container' />").attr("id", containerId).appendTo(document.body);
chartSetting.datetimepickerSetStyle("#"+containerId, chartTheme);
var styleName = chartSetting.datetimepickerThemeStyle(chartTheme);
$wrapper.addClass(styleName);
}
datetimepickerOptions = $.extend(
{
//inline应该为false为true的话下面的datetimepickerSetStyle函数创建的样式将不起作用
//inline应该为false为true的话下面的datetimepickerThemeStyle函数创建的样式将不起作用
inline: false,
parentID: (chartTheme ? "#"+containerId : document.body),
parentID: "#"+wrapperId,
i18n: chartSetting.datetimepickerI18n
},
datetimepickerOptions);
@ -694,7 +722,7 @@
{
//显示确定按钮,用于直接选中默认年份
datetimepickerOptions.showApplyButton = true;
datetimepickerOptions.onGenerate = function(currentValue,$input)
datetimepickerOptions.onGenerate = function(currentValue, $input)
{
var yearPickerInited = $(this).attr("yearPickerInited");
if(!yearPickerInited)
@ -731,102 +759,165 @@
};
/**
* 创建与指定图表主题匹配的datetimepicker组件样式表
* 获取或创建与指定图表主题匹配的datetimepicker组件样式表并返回CSS类名
*
* @param parentSelector datetimepicker组件所在的父元素CSS选择器
* @param chartTheme
*/
chartSetting.datetimepickerSetStyle = function(parentSelector, chartTheme)
chartSetting.datetimepickerThemeStyle = function(chartTheme)
{
var styleId = (chartTheme._datetimepickerStyleSheetId
|| (chartTheme._datetimepickerStyleSheetId = chartFactory.nextElementId()));
var styleNameKey = chartFactory.builtinPropName("DatetimepickerStyleName");
var styleName = chartTheme[styleNameKey];
if(chartFactory.isStyleSheetCreated(styleId))
return false;
if(styleName)
return styleName;
var color = chartFactory.getGradualColor(chartTheme, 1);
var bgColor = chartFactory.getGradualColor(chartTheme, 0);
var borderColor = chartFactory.getGradualColor(chartTheme, 0.3);
var shadowColor = chartFactory.getGradualColor(chartTheme, 0.9);
var hoverColor = chartFactory.getGradualColor(chartTheme, 0.3);
styleName = (chartTheme[styleNameKey] = chartFactory.nextElementId());
var cssText =
//主体
parentSelector + " .xdsoft_datetimepicker{"
+" color: "+color+";"
+" background: "+bgColor+";"
+" border-color: "+borderColor+";"
+" box-shadow: 0px 0px 6px "+shadowColor+";"
+" -webkit-box-shadow: 0px 0px 6px "+shadowColor+";"
+" }\n"
//前景色
+parentSelector + " .xdsoft_datetimepicker .xdsoft_calendar td,\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_calendar th{"
+" color: "+color+";"
+" }\n"
//按钮
+parentSelector + " .xdsoft_datetimepicker .xdsoft_label i,\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_next,\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_prev,\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_today_button{"
+" color:"+color+";"
+" }\n"
//年、月
+parentSelector + " .xdsoft_datetimepicker .xdsoft_label{"
+" background: "+bgColor+";"
+" }\n"
//年、月下拉框
+parentSelector + " .xdsoft_datetimepicker .xdsoft_label>.xdsoft_select{"
+" color: "+color+";"
+" background: "+bgColor+";"
+" border-color: "+borderColor+";"
+" box-shadow: 0px 0px 6px "+shadowColor+";"
+" -webkit-box-shadow: 0px 0px 6px "+shadowColor+";"
+" }\n"
//时间框
+parentSelector + " .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box{"
+" border-color: "+borderColor+";"
+" }\n"
//时间条目
+parentSelector + " .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div{"
+" color: "+color+";"
+" border-color: "+borderColor+";"
+" }\n"
//悬停
+parentSelector + " .xdsoft_datetimepicker .xdsoft_calendar td:hover,\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div:hover,\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_label>.xdsoft_select>div>.xdsoft_option:hover{"
+" color: "+color+" !important;"
+" background: "+hoverColor+" !important;"
+" }\n"
//今天
+parentSelector + " .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_today{"
+" color: "+color+";"
+" font-weight: bold;"
+" }\n"
//选中
+parentSelector + " .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_default,\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current,\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current,\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_label>.xdsoft_select>div>.xdsoft_option.xdsoft_current{"
+" color: "+chartTheme.highlightTheme.color+";"
+" background: "+chartTheme.highlightTheme.backgroundColor+";"
+" box-shadow: none;"
+" -webkit-box-shadow: none;"
+" }\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year{"
+" color: "+color+";"
+" background: "+bgColor+";"
+" border: 1px solid "+borderColor+" !important;"
+" }\n"
+parentSelector + " .xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year:hover{"
+" background: "+hoverColor+";"
+" }\n"
;
chartFactory.themeStyleSheet(chartTheme, chartFactory.builtinPropName("Datetimepicker"), function()
{
var color = chartFactory.gradualColor(chartTheme, 1);
var bgColor = chartFactory.gradualColor(chartTheme, 0);
var borderColor = chartFactory.gradualColor(chartTheme, 0.3);
var shadowColor = chartFactory.gradualColor(chartTheme, 0.9);
var hoverColor = chartFactory.gradualColor(chartTheme, 0.3);
var cssPrefix = "." + styleName + " .xdsoft_datetimepicker";
var css =
[
//主体
{
name: cssPrefix,
value:
{
"color": color,
"background": bgColor,
"border-color": borderColor,
"box-shadow": "0px 0px 6px " + shadowColor,
"-webkit-box-shadow": "0px 0px 6px " + shadowColor
}
},
//前景色
{
name: [ cssPrefix + " .xdsoft_calendar td", cssPrefix + " .xdsoft_calendar th" ],
value:
{
"color": color
}
},
//按钮
{
name:
[
cssPrefix + " .xdsoft_label i",
cssPrefix + " .xdsoft_next",
cssPrefix + " .xdsoft_prev",
cssPrefix + " .xdsoft_today_button"
],
value:
{
"color": color
}
},
//年、月
{
name: cssPrefix + " .xdsoft_label",
value:
{
"background": bgColor
}
},
//年、月下拉框
{
name: cssPrefix + " .xdsoft_label>.xdsoft_select",
value:
{
"color": color,
"background": bgColor,
"border-color": borderColor,
"box-shadow": "0px 0px 6px " + shadowColor,
"-webkit-box-shadow": "0px 0px 6px " + shadowColor
}
},
//时间框
{
name: cssPrefix + " .xdsoft_timepicker .xdsoft_time_box",
value:
{
"border-color": borderColor
}
},
//时间条目
{
name: cssPrefix + " .xdsoft_timepicker .xdsoft_time_box>div>div",
value:
{
"color": color,
"border-color": borderColor
}
},
//悬停
{
name:
[
cssPrefix + " .xdsoft_calendar td:hover",
cssPrefix + " .xdsoft_timepicker .xdsoft_time_box>div>div:hover",
cssPrefix + " .xdsoft_label>.xdsoft_select>div>.xdsoft_option:hover"
],
value:
{
"color": color + " !important",
"background": hoverColor + " !important"
}
},
//今天
{
name: cssPrefix + " .xdsoft_calendar td.xdsoft_today",
value:
{
"color": color,
"font-weight": "bold"
}
},
//选中
{
name:
[
cssPrefix + " .xdsoft_calendar td.xdsoft_default",
cssPrefix + " .xdsoft_calendar td.xdsoft_current",
cssPrefix + " .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current",
cssPrefix + " .xdsoft_label>.xdsoft_select>div>.xdsoft_option.xdsoft_current"
],
value:
{
"color": chartTheme.highlightTheme.color,
"background": chartTheme.highlightTheme.backgroundColor,
"box-shadow": "none",
"-webkit-box-shadow": "none"
}
},
{
name: cssPrefix + " .xdsoft_save_selected.xdsoft_save_selected_year",
value:
{
"color": color,
"background": bgColor,
"border": "1px solid "+borderColor+" !important"
}
},
{
name: cssPrefix + " .xdsoft_save_selected.xdsoft_save_selected_year:hover",
value:
{
"background": hoverColor
}
}
];
return css;
});
chartFactory.createStyleSheet(styleId, cssText, "beforeFirstScript");
return true;
return styleName;
};
chartSetting.evalDataSetParamInputPayload = function(dataSetParam, defaultValue)
@ -1189,7 +1280,7 @@
{
$box = $("<div class='dg-chart-setting-box' />").appendTo($chart);
chartSetting.setChartSettingBoxStyle($box, chart.theme());
chartSetting.setChartSettingBoxThemeStyle(chart, $box);
//参数
if(!disableSetting.param && chart.hasParamDataSet())
@ -1253,64 +1344,73 @@
$(".dg-chart-setting-box", chart.elementJquery()).hide();
};
chartSetting.setChartSettingBoxStyle = function($box, chartTheme)
chartSetting.setChartSettingBoxThemeStyle = function(chart, $box)
{
var styleClassName = chartTheme._chartSettingBoxStyleClassName;
if(!styleClassName)
chart.themeStyleSheet(chartFactory.builtinPropName("ChartSettingBox"), function()
{
styleClassName = chartFactory.nextElementId();
chartTheme._chartSettingBoxStyleClassName = styleClassName;
}
$box.addClass(styleClassName);
var styleId = (chartTheme._chartSettingBoxStyleSheetId
|| (chartTheme._chartSettingBoxStyleSheetId = chartFactory.nextElementId()));
if(chartFactory.isStyleSheetCreated(styleId))
return false;
var qualifier = "." + styleClassName;
var color = chartFactory.getGradualColor(chartTheme, 1);
var bgColor = chartFactory.getGradualColor(chartTheme, 0);
var borderColor = chartFactory.getGradualColor(chartTheme, 0.5);
var shadowColor = chartFactory.getGradualColor(chartTheme, 0.9);
var cssText =
qualifier + ".dg-chart-setting-box .dg-chart-setting-button{"
+" color: "+color+";"
+" background: "+bgColor+";"
+" border-color: "+borderColor+";"
+"} \n"
+qualifier + ".dg-chart-setting-box .dg-chart-setting-button:hover{"
+" background: "+chartFactory.getGradualColor(chartTheme, 0.2)+";"
+"} \n"
+qualifier + ".dg-chart-setting-box .dg-chart-setting-panel{"
+" color: "+color+";"
+" background: "+bgColor+";"
+" border-color: "+borderColor+";"
+" box-shadow: 0px 0px 6px "+shadowColor+";"
+" -webkit-box-shadow: 0px 0px 6px "+shadowColor+";"
+"} \n"
+qualifier + ".dg-chart-setting-box .dg-chart-setting-panel .dg-chartdataset-section{"
+" color: "+color+";"
+" background: "+bgColor+";"
+" border-color: "+borderColor+";"
+"} \n"
+qualifier + ".dg-chart-setting-box .dg-chart-setting-panel .dg-chart-setting-panel-foot button{"
+" color: "+color+";"
+" background: "+chartFactory.getGradualColor(chartTheme, 0.1)+";"
+" border-color: "+borderColor+";"
+"} \n"
+qualifier + ".dg-chart-setting-box .dg-chart-setting-panel .dg-chart-setting-panel-foot button:hover{"
+" background: "+chartFactory.getGradualColor(chartTheme, 0.3)+";"
+"} \n"
;
chartFactory.createStyleSheet(styleId, cssText, "beforeFirstScript");
return true;
var color = chart.gradualColor(1);
var bgColor = chart.gradualColor(0);
var borderColor = chart.gradualColor(0.5);
var shadowColor = chart.gradualColor(0.9);
var css =
[
{
name: " .dg-chart-setting-box .dg-chart-setting-button",
value:
{
"color": color,
"background-color": bgColor,
"border-color": borderColor
}
},
{
name: " .dg-chart-setting-box .dg-chart-setting-button:hover",
value:
{
"background-color": chart.gradualColor(0.2)
}
},
{
name: " .dg-chart-setting-box .dg-chart-setting-panel",
value:
{
"color": color,
"background-color": bgColor,
"border-color": borderColor,
"box-shadow": "0px 0px 6px " + shadowColor,
"-webkit-box-shadow": "0px 0px 6px " + shadowColor
}
},
{
name: " .dg-chart-setting-box .dg-chart-setting-panel .dg-chartdataset-section",
value:
{
"color": color,
"background-color": bgColor,
"border-color": borderColor
}
},
{
name: " .dg-chart-setting-box .dg-chart-setting-panel .dg-chart-setting-panel-foot button",
value:
{
"color": color,
"background-color": chart.gradualColor(0.1),
"border-color": borderColor
}
},
{
name: " .dg-chart-setting-box .dg-chart-setting-panel .dg-chart-setting-panel-foot button:hover",
value:
{
"background-color": chart.gradualColor(0.3)
}
}
];
return css;
});
};
/**
@ -1467,7 +1567,7 @@
var $panelContent = $("<div class='dg-chart-setting-panel-content' />").appendTo($panel);
var $panelFoot = $("<div class='dg-chart-setting-panel-foot' />").appendTo($panel);
chartSetting.setChartSettingDataPanelStyle($panel, chart.theme());
chartSetting.setChartSettingDataPanelThemeStyle(chart, $panel);
chartSetting.setChartSetingPanelContentSizeRange(chart, $panel, $panelContent,$panelFoot);
for(var i=0; i<chartDataSets.length; i++)
@ -1688,72 +1788,100 @@
return title;
};
chartSetting.setChartSettingDataPanelStyle = function($panel, chartTheme)
chartSetting.setChartSettingDataPanelThemeStyle = function(chart, $panel)
{
var styleClassName = chartTheme._chartSettingDataPanelStyleClassName;
if(!styleClassName)
chart.themeStyleSheet(chartFactory.builtinPropName("ChartSettingDataPanel"), function()
{
styleClassName = chartFactory.nextElementId();
chartTheme._chartSettingDataPanelStyleClassName = styleClassName;
}
$panel.addClass(styleClassName);
var styleId = (chartTheme._chartSettingDataPanelStyleSheetId
|| (chartTheme._chartSettingDataPanelStyleSheetId = chartFactory.nextElementId()));
if(chartFactory.isStyleSheetCreated(styleId))
return false;
//表格背景色应与面板背景色一致,且不能设透明背景色,因为设置了固定列
var bgColor = chartFactory.getGradualColor(chartTheme, 0);
var qualifier = "." + styleClassName;
var cssText =
qualifier + " table.dataTable tbody tr{"
+ " color:"+chartTheme.color+";"
+" }\n"
+qualifier + " table.dataTable thead th,\n"
+qualifier + " table.dataTable thead td{"
+" color:"+chartTheme.titleColor+";"
+" background:"+bgColor+";"
+" }\n"
+qualifier + " table.dataTable.stripe tbody tr.odd,\n"
+qualifier + " table.dataTable.display tbody tr.odd{"
+" background:"+chartFactory.getGradualColor(chartTheme, 0.1)+";"
+" } \n"
+qualifier + " table.dataTable.stripe tbody tr.even,\n"
+qualifier + " table.dataTable.display tbody tr.even{"
+" background:"+bgColor+";"
+" }\n"
+qualifier + " table.dataTable.hover tbody tr.hover,\n"
+qualifier + " table.dataTable.hover tbody tr:hover,\n"
+qualifier + " table.dataTable.display tbody tr:hover,\n"
+qualifier + " table.dataTable.hover tbody tr.hover.selected,\n"
+qualifier + " table.dataTable.hover tbody > tr.selected:hover,\n"
+qualifier + " table.dataTable.hover tbody > tr > .selected:hover,\n"
+qualifier + " table.dataTable.display tbody > tr.selected:hover,\n"
+qualifier + " table.dataTable.display tbody > tr > .selected:hover{"
+" background:"+chartFactory.getGradualColor(chartTheme, 0.3)+";"
+" }\n"
+qualifier + " table.dataTable tbody > tr.selected,\n"
+qualifier + " table.dataTable tbody > tr > .selected,\n"
+qualifier + " table.dataTable.stripe tbody > tr.even.selected,\n"
+qualifier + " table.dataTable.stripe tbody > tr.even > .selected,\n"
+qualifier + " table.dataTable.display tbody > tr.even.selected,\n"
+qualifier + " table.dataTable.display tbody > tr.even > .selected,\n"
+qualifier + " table.dataTable.stripe tbody > tr.odd.selected,\n"
+qualifier + " table.dataTable.stripe tbody > tr.odd > .selected,\n"
+qualifier + " table.dataTable.display tbody > tr.odd.selected,\n"
+qualifier + " table.dataTable.display tbody > tr.odd > .selected{"
+" color:"+chartTheme.highlightTheme.color+";"
+" background:"+chartTheme.highlightTheme.backgroundColor+";"
+" }\n";
chartFactory.createStyleSheet(styleId, cssText, "beforeFirstScript");
return true;
var theme = chart.theme();
//表格背景色应与面板背景色一致,且不能设透明背景色,因为设置了固定列
var bgColor = chart.gradualColor(0);
var cssPrefix = " .dg-chart-setting-box .dg-chart-setting-data-panel";
var css =
[
{
name: cssPrefix + " table.dataTable tbody tr",
value:
{
"color": theme.color
}
},
{
name:
[
cssPrefix + " table.dataTable thead th",
cssPrefix + " table.dataTable thead td"
],
value:
{
"color": theme.titleColor,
"background-color": bgColor
}
},
{
name:
[
cssPrefix + " table.dataTable.stripe tbody tr.odd",
cssPrefix + " table.dataTable.display tbody tr.odd"
],
value:
{
"background-color": chart.gradualColor(0.1)
}
},
{
name:
[
cssPrefix + " table.dataTable.stripe tbody tr.even",
cssPrefix + " table.dataTable.display tbody tr.even"
],
value:
{
"background-color": bgColor
}
},
{
name:
[
cssPrefix + " table.dataTable.hover tbody tr.hover",
cssPrefix + " table.dataTable.hover tbody tr:hover",
cssPrefix + " table.dataTable.display tbody tr:hover",
cssPrefix + " table.dataTable.hover tbody tr.hover.selected",
cssPrefix + " table.dataTable.hover tbody > tr.selected:hover",
cssPrefix + " table.dataTable.hover tbody > tr > .selected:hover",
cssPrefix + " table.dataTable.display tbody > tr.selected:hover",
cssPrefix + " table.dataTable.display tbody > tr > .selected:hover"
],
value:
{
"background-color": chart.gradualColor(0.3)
}
},
{
name:
[
cssPrefix + " table.dataTable tbody > tr.selected",
cssPrefix + " table.dataTable tbody > tr > .selected",
cssPrefix + " table.dataTable.stripe tbody > tr.even.selected",
cssPrefix + " table.dataTable.stripe tbody > tr.even > .selected",
cssPrefix + " table.dataTable.display tbody > tr.even.selected",
cssPrefix + " table.dataTable.display tbody > tr.even > .selected",
cssPrefix + " table.dataTable.stripe tbody > tr.odd.selected",
cssPrefix + " table.dataTable.stripe tbody > tr.odd > .selected",
cssPrefix + " table.dataTable.display tbody > tr.odd.selected",
cssPrefix + " table.dataTable.display tbody > tr.odd > .selected"
],
value:
{
"color": theme.highlightTheme.color,
"background-color": theme.highlightTheme.backgroundColor
}
}
];
return css;
});
};
chartSetting.updateChartSettingDataTableData = function(chart, chartDataSets, index, $dataTable)

View File

@ -1954,12 +1954,11 @@
for(var j=0; j<data.length; j++)
{
//在ECharts-4.9.0时,这里格式为:{name: ..., value:[经度值, 纬度值, 关系数值]},是没问题的,
//但是升级至ECharts-5.0+后会报错Can not read property 'off' of undefined
//按照ECharts-5.0+的graph的官方配置项这里格式应为{name: ..., x: 经度值, y: 纬度值, value: 关系数值}
//但是这样仍然会报上述错误!
//所以这里仍恢复为采用ECharts-4.9.0时的格式配合修改了ECharts-5.1.2的源码后,终于解决了上述问题!
//具体源码修改位置参考echarts-5.1.2/echarts.js的58833行
//ECharts-4.9.0时graph官方数据格式为【名/值数组】:{name: ..., value:[经度值, 纬度值, 关系数值]}
//ECharts-5.0+ 时graph官方数据格式为【名/X/Y/值】:{name: ..., x: 经度值, y: 纬度值, value: 关系数值}
//在ECharts由4.9.0升级至5.1.2版本后,【名/值数组】、【名/X/Y/值】格式都会报错Can not read property 'off' of undefined
//在修改了源码修改位置参考DataGear-2.8.0版本echarts-5.1.2/echarts.js的58833行同时采用【名/值数组】格式后才解决。
//在ECharts由5.1.2升级至5.2.0版本后,【名/X/Y/值】格式不会报错但是显示位置不对,【名/值数组】则可以正常展示
var sd = { name: chart.resultRowCell(data[j], snp), value: [ chart.resultRowCell(data[j], slop), chart.resultRowCell(data[j], slap) ] };
var td = { name: chart.resultRowCell(data[j], tnp), value: [ chart.resultRowCell(data[j], tlop), chart.resultRowCell(data[j], tlap) ] };
@ -3936,10 +3935,10 @@
hideVerticalScrollbar: true
};
var themeBindTableOptions = chartTheme._chartTableThemeBindOptions;
if(themeBindTableOptions == null)
var themeAwareOptionsAttrTable = chartTheme._chartTableThemeAwareOptionsAttrTable;
if(themeAwareOptionsAttrTable == null)
{
themeBindTableOptions=
themeAwareOptionsAttrTable=
{
//表头样式
"header":
@ -3980,10 +3979,10 @@
renderValue: undefined
};
themeBindTableOptions._chartTableStyleClassName = chartFactory.nextElementId();
themeBindTableOptions._chartTableStyleSheetId = chartFactory.nextElementId();
themeAwareOptionsAttrTable._chartTableStyleClassName = chartFactory.nextElementId();
themeAwareOptionsAttrTable._chartTableStyleSheetId = chartFactory.nextElementId();
chartTheme._chartTableThemeBindOptions = themeBindTableOptions;
chartTheme._chartTableThemeAwareOptionsAttrTable = themeAwareOptionsAttrTable;
}
var columns = [];
@ -4016,14 +4015,14 @@
"backgroundColor": chartTheme.backgroundColor
},
//表格格式参考上面的themeBindTableOptions
//表格格式参考上面的themeAwareOptionsAttrTable
table: undefined,
//轮播格式可以为true、false、轮播interval数值、轮播interval返回函数、{...}
carousel: undefined,
//后置处理列函数格式为function(columns){ return columns; }
postProcessColumns: undefined,
//是否美化滚动条仅支持webkit内核浏览器
beautifyScrollbar: true,
//DataTable配置项
"columns": columns,
@ -4059,12 +4058,12 @@
},
options, null, function(options)
{
//如果没有定义table选项则采用全局themeBindTableOptions
//如果没有定义table选项则采用全局themeAwareOptionsAttrTable
if(options.table == null)
options.table = themeBindTableOptions;
options.table = themeAwareOptionsAttrTable;
else
{
options.table = $.extend(true, {}, themeBindTableOptions, options.table);
options.table = $.extend(true, {}, themeAwareOptionsAttrTable, options.table);
options.table._chartTableStyleClassName =chartFactory.nextElementId();
options.table._chartTableStyleSheetId = chartFactory.nextElementId();
}
@ -4133,9 +4132,14 @@
if(evalHeight)
options.scrollY = 4;
if(options.beautifyScrollbar)
chartEle.addClass("dg-chart-beautify-scrollbar");
if(options.carousel.enable)
chartEle.addClass("dg-chart-table-carousel");
chartEle.addClass(options.table._chartTableStyleClassName);
chartSupport.tableCreateTableStyleSheet(chart, options,
options.table._chartTableStyleClassName, options.table._chartTableStyleSheetId);
@ -4252,10 +4256,14 @@
chartSupport.tableDestroy = function(chart)
{
var chartEle = chart.elementJquery();
var renderOptions = chart.renderOptions();
chartSupport.tableStopCarousel(chart);
chartEle.removeClass("dg-chart-table");
chartEle.removeClass("dg-hide-title");
chartEle.removeClass("dg-chart-table-carousel");
chartEle.removeClass("dg-chart-beautify-scrollbar");
chartEle.removeClass(renderOptions.table._chartTableStyleClassName);
$(".dg-chart-table-title", chartEle).remove();
$(".dg-chart-table-content", chartEle).remove();
};
@ -4330,13 +4338,12 @@
chartSupport.tableCreateTableStyleSheet = function(chart, chartOptions, styleClassName, styleSheetId)
{
chart.elementJquery().addClass(styleClassName);
if(chartFactory.isStyleSheetCreated(styleSheetId))
return false;
//样式要加".dg-chart-table-content"限定因为图表的数据透视表功能也采用的是DataTable组件可能会处在同一个表格图表div内
var qualifier = "." + styleClassName + " .dg-chart-table-content";
var qualifierBeautifyScrollbar = "." + styleClassName + ".dg-chart-beautify-scrollbar .dg-chart-table-content";
var cssText =
qualifier + " table.dataTable tbody tr{"
@ -4386,9 +4393,21 @@
+qualifier + " table.dataTable thead th.sorting_desc div.DataTables_sort_wrapper span{"
+ " border-top-color:" + chartOptions.table.header.color+";"
+ " background: none;"
+" }\n";
+" }\n"
+qualifierBeautifyScrollbar + " .dataTables_scrollBody::-webkit-scrollbar{"
+ " width: 10px;"
+ " height: 10px;"
+" }\n"
+qualifierBeautifyScrollbar + " .dataTables_scrollBody::-webkit-scrollbar-thumb{"
+ " border-radius: 10px;"
+ " background: "+chart.gradualColor(0.3)+";"
+" }\n"
+qualifierBeautifyScrollbar + " .dataTables_scrollBody::-webkit-scrollbar-track{"
+ " background: "+chart.gradualColor(0.1)+";"
+" }\n"
;
chartFactory.createStyleSheet(styleSheetId, cssText, "beforeFirstScript");
chartFactory.styleSheetText(styleSheetId, cssText);
return true;
};
@ -4681,10 +4700,6 @@
var chartEle = chart.elementJquery();
chartEle.addClass("dg-chart-label");
var labelWrapper = $(".dg-chart-label-wrapper", chartEle);
if(labelWrapper.length == 0)
labelWrapper = $("<div class='dg-chart-label-wrapper' />").appendTo(chartEle);
options = chartSupport.inflateRenderOptions(chart,
{
//将在update中设置
@ -4692,6 +4707,9 @@
//是否所有标签都行内显示
"inline": false,
//是否以flex布局展示标签
//弹性布局true 是、居中间隔false 否;"around" 居中间隔;"start" 左对齐;"end" 右对齐;"center" 居中;"between" 贴边间隔;
"flex": false,
//是否标签值在前
"valueFirst": false,
//标签名样式,这里不必添加默认样式,因为图表元素已设置
@ -4705,7 +4723,23 @@
options);
if(options.inline == true)
labelWrapper.addClass("dg-chart-label-inline");
chartEle.addClass("dg-chart-label-inline");
if(options.flex != null && options.flex != false)
{
chartEle.addClass("dg-chart-label-flex");
if(options.flex == "start")
chartEle.addClass("dg-chart-label-flex-start");
else if(options.flex == "end")
chartEle.addClass("dg-chart-label-flex-end");
else if(options.flex == "center")
chartEle.addClass("dg-chart-label-flex-center");
else if(options.flex == "between")
chartEle.addClass("dg-chart-label-flex-between");
else
chartEle.addClass("dg-chart-label-flex-around");
}
// < @deprecated 兼容2.7.0版本的{label:{name:{...},value:{...}}}配置项结构,未来版本会移除
if(options.label && options.label.name)
@ -4714,7 +4748,7 @@
options.value = $.extend(true, {}, options.value, options.label.value);
// > @deprecated 兼容2.7.0版本的{label:{name:{...},value:{...}}}配置项结构,未来版本会移除
chart.internal(labelWrapper[0]);
chart.internal(chart.element());
};
chartSupport.labelUpdate = function(chart, results)
@ -4855,8 +4889,10 @@
chartSupport.labelDestroy = function(chart)
{
var chartEle = chart.elementJquery();
chartEle.removeClass("dg-chart-label");
$(chart.internal()).remove();
chartEle.removeClass("dg-chart-label dg-chart-label-inline dg-chart-label-flex "
+"dg-chart-label-flex-around dg-chart-label-flex-start dg-chart-label-flex-end "
+"dg-chart-label-flex-center dg-chart-label-flex-between");
$(".dg-chart-label-item", chart.internal()).remove();
};
chartSupport.labelOn = function(chart, eventType, handler)
@ -4902,6 +4938,276 @@
chartSupport.setChartEventOriginalInfo(chart, chartEvent, chartData);
};
//下拉框
chartSupport.selectRender = function(chart, nameSign, valueSign, options)
{
chartSupport.chartSignNameMap(chart, { name: nameSign, value: valueSign });
var chartEle = chart.elementJquery();
chartEle.addClass("dg-chart-select");
options = chartSupport.inflateRenderOptions(chart,
{
//将在update中设置
//下拉框数据:
// data:
// [
// {
// //选项名,可选,默认为选项值
// name: "...",
// //选项值
// value: ...,
// //是否选中可选默认为false
// selected: true 或 false,
// //选项css样式可选
// itemStyle: { ... }
// },
// ...
// ]
//下拉框名称
name: undefined,
//是否多选
multiple: false,
//可见选项数目
size: undefined,
//默认选中项null默认数值或其数组选中指定索引的选项
selected: undefined,
//前置添加的条目项格式同data元素或者其数组通常用于添加默认选中项
prepend: undefined,
//是否美化多选时的滚动条仅支持webkit内核浏览器
beautifyScrollbar: true,
//下拉框是否填满父元素,"auto" 当是内联框时填满true 是false 否
fillParent: "auto",
//select框css样式格式为{ ... }
selectStyle: undefined,
//option选项整体css样式格式为{ ... }
itemStyle: undefined
},
options);
chartSupport.selectThemeStyleSheet(chart);
var isDropdown = (!options.multiple && (options.size == null || options.size <= 1));
if(options.beautifyScrollbar)
chartEle.addClass("dg-chart-beautify-scrollbar");
if(isDropdown)
chartEle.addClass("dg-chart-select-dropdown");
if(options.fillParent === true || (options.fillParent == "auto" && !isDropdown))
chartEle.addClass("dg-chart-select-fill");
var $select = $("<select class='dg-chart-select-select' />").appendTo(chartEle);
if(options.name)
$select.attr("name", options.name);
if(options.multiple)
$select.attr("multiple", "multiple");
if(options.size != null)
$select.attr("size", options.size);
if(options.selectStyle)
chartFactory.setStyles($select, options.selectStyle);
chart.internal($select[0]);
};
chartSupport.selectUpdate = function(chart, results)
{
var signNameMap = chartSupport.chartSignNameMap(chart);
var renderOptions = chart.renderOptions();
var chartDataSets = chart.chartDataSetsMain();
var $select = $(chart.internal());
$select.empty();
var selected = renderOptions.selected;
if(selected != null && typeof(selected) == "number")
selected = [ selected ];
var updateOptions = { data: [] };
for(var i=0; i<chartDataSets.length; i++)
{
var chartDataSet = chartDataSets[i];
var result = chart.resultOf(results, chartDataSet);
var nps = chart.dataSetPropertiesOfSign(chartDataSet, signNameMap.name);
var vps = chart.dataSetPropertiesOfSign(chartDataSet, signNameMap.value);
var hasNps = (nps && nps.length > 0);
if(hasNps && nps.length != vps.length)
throw new Error("The ["+signNameMap.name+"] sign column must be "
+"one-to-one with ["+signNameMap.value+"] sign column");
var namess = (hasNps ? chart.resultRowArrays(result, nps) : []);
var valuess = chart.resultRowArrays(result, vps);
for(var j=0; j<valuess.length; j++)
{
var values = valuess[j];
var names = (hasNps ? namess[j] : values);
for(var k=0; k<names.length; k++)
{
var sv = { name: names[k], value: values[k] };
chart.originalInfo(sv, chartDataSet, j);
updateOptions.data.push(sv);
}
}
}
updateOptions = chart.inflateUpdateOptions(results, updateOptions);
var data = updateOptions.data;
if(renderOptions.prepend)
{
var newData = ($.isArray(renderOptions.prepend) ? renderOptions.prepend : [ renderOptions.prepend ]);
data = newData.concat(data);
}
for(var i=0; i<data.length; i++)
{
var optData = data[i];
var $opt = $("<option />").attr("value", optData.value)
.html(optData.name ? optData.name : optData.value).appendTo($select);
if(optData.selected || (selected != null && $.inArray(i, selected) > -1))
$opt.attr("selected", "selected");
$opt.data("_dgChartSelectOptionChartData", optData);
var itemStyle = null;
if(renderOptions.itemStyle && optData.itemStyle)
itemStyle = $.extend({}, renderOptions.itemStyle, optData.itemStyle);
else if(renderOptions.itemStyle)
itemStyle = renderOptions.itemStyle;
else if(optData.itemStyle)
itemStyle = optData.itemStyle;
if(itemStyle)
chartFactory.setStyles($opt, itemStyle);
}
};
chartSupport.selectResize = function(chart)
{
};
chartSupport.selectDestroy = function(chart)
{
var chartEle = chart.elementJquery();
chartEle.removeClass("dg-chart-select dg-chart-select-dropdown dg-chart-beautify-scrollbar");
$(chart.internal()).remove();
};
chartSupport.selectOn = function(chart, eventType, handler)
{
var handlerDelegation = function(htmlEvent)
{
var $select = $(this);
var chartEvent = chart.eventNewHtml(eventType, htmlEvent);
chartSupport.selectSetChartEventData(chart, chartEvent, htmlEvent, $select);
chart.callEventHandler(handler, chartEvent);
};
chart.registerEventHandlerDelegation(eventType, handler, handlerDelegation);
$(chart.internal()).on(eventType, handlerDelegation);
};
chartSupport.selectOff = function(chart, eventType, handler)
{
var internal = $(chart.internal());
chart.removeEventHandlerDelegation(eventType, handler, function(et, eh, ehd)
{
internal.off(et, ehd);
});
};
chartSupport.selectSetChartEventData = function(chart, chartEvent, htmlEvent, $select)
{
var signNameMap = chartSupport.chartSignNameMap(chart);
var chartData = $select.data("_dgChartSelectOptionChartData");
var data = {};
if(chartData)
{
data[signNameMap.name] = chartData.name;
data[signNameMap.value] = chartData.value;
}
chart.eventData(chartEvent, data);
chartSupport.setChartEventOriginalInfo(chart, chartEvent, chartData);
};
chartSupport.selectThemeStyleSheet = function(chart)
{
chart.themeStyleSheet(chartFactory.builtinPropName("SelectChart"), function()
{
var chartTheme = chart.theme();
var css=
[
{
name: " .dg-chart-select-select",
value:
{
"color": chartTheme.color,
"background-color": chartTheme.backgroundColor,
"border-color": chartTheme.borderColor
}
},
{
name: ".dg-chart-select-dropdown .dg-chart-select-select option",
value:
{
"color": chartTheme.color,
"background-color": chart.gradualColor(0.1)
}
},
{
name: ".dg-chart-beautify-scrollbar .dg-chart-select-select::-webkit-scrollbar",
value:
{
"width": "10px",
"height": "10px"
}
},
{
name: ".dg-chart-beautify-scrollbar .dg-chart-select-select::-webkit-scrollbar-thumb",
value:
{
"border-radius": "10px",
"background": chart.gradualColor(0.3)
}
},
{
name: ".dg-chart-beautify-scrollbar .dg-chart-select-select::-webkit-scrollbar-track",
value:
{
"background": chart.gradualColor(0.1)
}
}
];
return css;
});
};
//自定义
chartSupport.customAsyncRender = function(chart)

View File

@ -2141,7 +2141,7 @@
var re = [];
var pname = chartFactory.DATA_ORIGINAL_INFO_PROP_NAME;
var pname = chartFactory._DATA_ORIGINAL_INFO_PROP_NAME;
for(var i=0; i<data.length; i++)
{

View File

@ -3391,7 +3391,7 @@
}
};
$.handleAjaxOperationMessage = function(jqXHR, errorThrown)
$.handleAjaxOperationMessage = function(event, jqXHR, ajaxSettings, data, thrownError)
{
if(!window._showAjaxOperationMessageDetail)
{
@ -3399,9 +3399,9 @@
{
$.closeTip();
var $operationMessageParent = $("#__operationMessageParent");
var $omp = $("#__operationMessageParent");
var isSuccessMessage = ("true" == $operationMessageParent.attr("success"));
var isSuccessMessage = ("true" == $omp.attr("success"));
var $dialog = $("<div id='dialog-"+new Date().getTime()+"' class='operation-message-dialog'></div>").appendTo(document.body);
@ -3409,11 +3409,11 @@
if(!isSuccessMessage)
$messageDetail.addClass("ui-state-error");
$messageDetail.appendTo($dialog);
$messageDetail.html($(".message-detail", $operationMessageParent).html());
$messageDetail.html($(".message-detail", $omp).html());
$._dialog($dialog,
{
title : $(".message", $operationMessageParent).text(),
title : $(".message", $omp).text(),
modal : true,
height: "60%",
position: {my: "center top", at: "center top+3"},
@ -3436,25 +3436,24 @@
};
}
var isSuccessMessage = (jqXHR.status == 200);
var $omp = $("#__operationMessageParent");
if($omp.length == 0)
$omp = $("<div id='__operationMessageParent' style='display:none;' />").appendTo(document.body);
var isSuccessResponse = (jqXHR.status == 200);
var hasResponseMessage = false;
if(jqXHR.responseText)
{
var $operationMessageParent = $("#__operationMessageParent");
if($operationMessageParent.length == 0)
$operationMessageParent = $("<div id='__operationMessageParent' style='display:none;' />").appendTo(document.body);
var operationMessage = $.getResponseJson(jqXHR);
var hasMessage = false;
//操作消息的JSON响应
//响应为JSON操作消息的
if(operationMessage && operationMessage.type && operationMessage.code && operationMessage.message)
{
$operationMessageParent.empty();
$omp.empty();
var $omdiv = $("<div class='operation-message "+operationMessage.type+"' />").appendTo($operationMessageParent);
var $mdiv = $("<div class='message' />").appendTo($omdiv).html(operationMessage.message);
var $omdiv = $("<div class='operation-message "+operationMessage.type+"' />").appendTo($omp);
$("<div class='message' />").appendTo($omdiv).html(operationMessage.message);
if(operationMessage.detail)
{
@ -3465,54 +3464,64 @@
$("<div />").appendTo($ddiv).html(operationMessage.detail);
}
hasMessage = true;
hasResponseMessage = true;
}
else
{
if(isSuccessMessage)
hasMessage = false;
else
var rtPrefix = jqXHR.responseText.substr(0, 100);
var dpnValue = null;
var dpnToken = "dg-page-name=\"";
var dpnStartIdx = rtPrefix.indexOf(dpnToken);
if(dpnStartIdx > -1)
{
//操作消息的HTML响应
$operationMessageParent.html(jqXHR.responseText);
hasMessage = true;
dpnStartIdx = dpnStartIdx + dpnToken.length;
var dpnEndIdx = rtPrefix.indexOf("\"", dpnStartIdx);
dpnValue = (dpnEndIdx > dpnStartIdx ? rtPrefix.substring(dpnStartIdx, dpnEndIdx) : null);
}
}
if(hasMessage)
{
$operationMessageParent.attr("success", isSuccessMessage);
var message = $(".message", $operationMessageParent).html();
if($(".message-detail", $operationMessageParent).length > 0)
message += "<span class='ui-icon ui-icon-comment message-detail-icon' onclick='_showAjaxOperationMessageDetail();'></span>";
if(isSuccessMessage)
$.tipSuccess(message);
else
$.tipError(message);
//响应为HTML操作消息的
if(dpnValue == "error")
{
$omp.html(jqXHR.responseText);
hasResponseMessage = true;
}
//当登录超时后列表页点击【查询】按钮ajax响应可能会重定向到登录页这里特殊处理
else if(dpnValue == "login")
{
var url = ajaxSettings.url;
if(url && url.indexOf("/login") < 0)
{
thrownError = "Login expired";
hasResponseMessage = false;
}
}
}
}
else
if(hasResponseMessage)
{
if(isSuccessMessage)
;
$omp.attr("success", isSuccessResponse);
var message = $(".message", $omp).html();
if($(".message-detail", $omp).length > 0)
message += "<span class='ui-icon ui-icon-comment message-detail-icon' onclick='_showAjaxOperationMessageDetail();'></span>";
if(isSuccessResponse)
$.tipSuccess(message);
else
{
/* firefoxcometd
var msg = (jqXHR.statusText || "Error");
if(errorThrown && errorThrown.message)
{
if(msg)
msg += " : ";
msg += errorThrown.message;
}
$.tipError(msg);
*/
}
$.tipError(message);
}
//客户端处理ajax响应出错
else if(thrownError)
{
$.tipError(thrownError);
}
//客户端连接出错
else if(event && event.type=="ajaxError")
{
$.tipError("Error");
}
};
@ -3531,12 +3540,12 @@
$(document).ajaxError(function(event, jqXHR, ajaxSettings, thrownError)
{
$.handleAjaxOperationMessage(jqXHR, thrownError);
$.handleAjaxOperationMessage(event, jqXHR, ajaxSettings, null, thrownError);
});
$(document).ajaxSuccess(function(event, jqXHR, ajaxSettings, thrownError)
$(document).ajaxSuccess(function(event, jqXHR, ajaxSettings, data)
{
$.handleAjaxOperationMessage(jqXHR, thrownError);
$.handleAjaxOperationMessage(event, jqXHR, ajaxSettings, data, null);
});
/**

View File

@ -62,6 +62,18 @@ form .form-content .form-item .form-item-value textarea.error{
background-color: #f58400;
}
/*危险操作按钮*/
.ui-button.danger, .ui-button.danger:active{
border: 1px solid red;
background-color: red;
color: #ffffff;
}
.ui-button.danger:hover, .ui-button.danger:focus{
border: 1px solid #ff5252;
background-color: #ff5252;
color: #ffffff;
}
/*对话框*/
/*可保持ui-state-active状态组件样式默认图标是灰色这了改成白色*/
.stated-active.ui-state-active .ui-icon, .stated-active.ui-state-active:focus .ui-icon, .stated-active.ui-state-active:hover .ui-icon{

View File

@ -62,6 +62,18 @@ form .form-content .form-item .form-item-value textarea.error{
background-color: #59c908;
}
/*危险操作按钮*/
.ui-button.danger, .ui-button.danger:active{
border: 1px solid red;
background-color: red;
color: #ffffff;
}
.ui-button.danger:hover, .ui-button.danger:focus{
border: 1px solid #ff5252;
background-color: #ff5252;
color: #ffffff;
}
/*对话框*/
/*可保持ui-state-active状态组件样式默认图标是灰色这了改成白色*/
.stated-active.ui-state-active .ui-icon, .stated-active.ui-state-active:focus .ui-icon, .stated-active.ui-state-active:hover .ui-icon{

View File

@ -62,6 +62,18 @@ form .form-content .form-item .form-item-value textarea.error{
background-color: #007fff;
}
/*危险操作按钮*/
.ui-button.danger, .ui-button.danger:active{
border: 1px solid red;
background-color: red;
color: #ffffff;
}
.ui-button.danger:hover, .ui-button.danger:focus{
border: 1px solid #ff5252;
background-color: #ff5252;
color: #ffffff;
}
/*对话框*/
/*可保持ui-state-active状态组件样式默认图标是灰色这了改成白色*/
.stated-active.ui-state-active .ui-icon, .stated-active.ui-state-active:focus .ui-icon, .stated-active.ui-state-active:hover .ui-icon{

View File

@ -101,9 +101,7 @@ readonly 是否只读操作允许为null
po.element(".nameRow-radios").controlgroup();
po.initWorkspaceHeight();
po.initWorkspaceTabs(true);
po.initDataSetPropertiesTable(po.dataSetProperties);
po.initDataSetParamsTable(po.dataSetParams);
po.initPreviewParamValuePanel();
po.initParamPropertyDataFormat(po.dataSetParams, po.dataSetProperties);
po.initNameRowOperation(${(dataSet.nameRow)!"1"});
po.initDataSetFileInput(po.url("uploadFile"), "${((dataSet.fileSourceType)!'')?js_string?no_esc}", ${isAdd?string("true", "false")});
@ -142,11 +140,12 @@ readonly 是否只读操作允许为null
var pd = po.previewOptions.data.dataSet;
var dataSetResDirectory = (pd.dataSetResDirectory || {});
return (pd.fileSourceType != fileSourceType)
return ((pd.fileSourceType != fileSourceType)
|| (po.isFileSourceTypeUpload(fileSourceType) && pd.fileName != fileName)
|| (po.isFileSourceTypeServer(fileSourceType) && (dataSetResDirectory.id != dataSetResDirectoryId || pd.dataSetResFileName != dataSetResFileName))
|| (pd.encoding != encoding)
|| (pd.nameRow != nameRow) ;
|| (pd.nameRow != nameRow)
|| po.isPreviewParamPropertyDataFormatModified());
};
po.previewOptions.url = po.url("previewCsvFile");

View File

@ -103,9 +103,7 @@ readonly 是否只读操作允许为null
var selectionRange = po.csvEditor.getSelectionRange();
return (po.csvEditor.session.getTextRange(selectionRange) || "");
};
po.initDataSetPropertiesTable(po.dataSetProperties);
po.initDataSetParamsTable(po.dataSetParams);
po.initPreviewParamValuePanel();
po.initParamPropertyDataFormat(po.dataSetParams, po.dataSetProperties);
po.initNameRowOperation(${(dataSet.nameRow)!"1"});
po.updatePreviewOptionsData = function()
@ -131,7 +129,8 @@ readonly 是否只读操作允许为null
var pd = po.previewOptions.data.dataSet;
return (pd.value != value) || (pd.nameRow != nameRow);
return (pd.value != value || pd.nameRow != nameRow
|| po.isPreviewParamPropertyDataFormatModified());
};
po.previewOptions.url = po.url("previewCsvValue");

View File

@ -133,9 +133,7 @@ readonly 是否只读操作允许为null
po.element("#${pageId}-forceXls-${((dataSet.forceXls)!true)?string('true', 'false')}").click();
po.initWorkspaceHeight();
po.initWorkspaceTabs(true);
po.initDataSetPropertiesTable(po.dataSetProperties);
po.initDataSetParamsTable(po.dataSetParams);
po.initPreviewParamValuePanel();
po.initParamPropertyDataFormat(po.dataSetParams, po.dataSetProperties);
po.initNameRowOperation(${(dataSet.nameRow)!"1"});
po.initDataSetFileInput(po.url("uploadFile"), "${((dataSet.fileSourceType)!'')?js_string?no_esc}", ${isAdd?string("true", "false")});
@ -180,12 +178,13 @@ readonly 是否只读操作允许为null
var pd = po.previewOptions.data.dataSet;
var dataSetResDirectory = (pd.dataSetResDirectory || {});
return (pd.fileSourceType != fileSourceType)
|| (po.isFileSourceTypeUpload(fileSourceType) && pd.fileName != fileName)
|| (po.isFileSourceTypeServer(fileSourceType) && (dataSetResDirectory.id != dataSetResDirectoryId || pd.dataSetResFileName != dataSetResFileName))
|| (pd.sheetIndex != sheetIndex)
|| (pd.nameRow != nameRow) || (pd.dataRowExp != dataRowExp)
|| (pd.dataColumnExp != dataColumnExp) || (pd.forceXls != forceXls);
return ((pd.fileSourceType != fileSourceType)
|| (po.isFileSourceTypeUpload(fileSourceType) && pd.fileName != fileName)
|| (po.isFileSourceTypeServer(fileSourceType) && (dataSetResDirectory.id != dataSetResDirectoryId || pd.dataSetResFileName != dataSetResFileName))
|| (pd.sheetIndex != sheetIndex)
|| (pd.nameRow != nameRow) || (pd.dataRowExp != dataRowExp)
|| (pd.dataColumnExp != dataColumnExp) || (pd.forceXls != forceXls)
|| po.isPreviewParamPropertyDataFormatModified());
};
po.previewOptions.url = po.url("previewExcel");

View File

@ -199,9 +199,7 @@ readonly 是否只读操作允许为null
var selectionRange = currentEditor.getSelectionRange();
return (currentEditor.session.getTextRange(selectionRange) || "");
};
po.initDataSetPropertiesTable(po.dataSetProperties);
po.initDataSetParamsTable(po.dataSetParams);
po.initPreviewParamValuePanel();
po.initParamPropertyDataFormat(po.dataSetParams, po.dataSetProperties);
po.updatePreviewOptionsData = function()
{
@ -245,10 +243,11 @@ readonly 是否只读操作允许为null
var pd = po.previewOptions.data.dataSet;
return (pd.uri != uri) || (pd.requestMethod != requestMethod) || (pd.requestContentType != requestContentType)
return ((pd.uri != uri) || (pd.requestMethod != requestMethod) || (pd.requestContentType != requestContentType)
|| (pd.requestContentCharset != requestContentCharset) || (pd.responseContentType != responseContentType)
|| (pd.requestContent != requestContent) || (pd.headerContent != headerContent)
|| (pd.responseDataJsonPath != responseDataJsonPath);
|| (pd.responseDataJsonPath != responseDataJsonPath)
|| po.isPreviewParamPropertyDataFormatModified());
};
po.previewOptions.url = po.url("previewHttp");
@ -264,6 +263,11 @@ readonly 是否只读操作允许为null
if(!this.data.dataSet.uri)
return false;
};
po.previewOptions.error = function(operationMessage)
{
if(operationMessage && operationMessage.data)
return operationMessage.data[1];
};
po.initPreviewOperations();

View File

@ -87,9 +87,7 @@ readonly 是否只读操作允许为null
po.element("select[name='encoding']").selectmenu({ appendTo : po.element(), classes : { "ui-selectmenu-menu" : "encoding-selectmenu-menu" } });
po.initWorkspaceHeight();
po.initWorkspaceTabs(true);
po.initDataSetPropertiesTable(po.dataSetProperties);
po.initDataSetParamsTable(po.dataSetParams);
po.initPreviewParamValuePanel();
po.initParamPropertyDataFormat(po.dataSetParams, po.dataSetProperties);
po.initDataSetFileInput(po.url("uploadFile"), "${((dataSet.fileSourceType)!'')?js_string?no_esc}", ${isAdd?string("true", "false")});
@ -127,10 +125,11 @@ readonly 是否只读操作允许为null
var pd = po.previewOptions.data.dataSet;
var dataSetResDirectory = (pd.dataSetResDirectory || {});
return (pd.fileSourceType != fileSourceType)
return ((pd.fileSourceType != fileSourceType)
|| (po.isFileSourceTypeUpload(fileSourceType) && pd.fileName != fileName)
|| (po.isFileSourceTypeServer(fileSourceType) && (dataSetResDirectory.id != dataSetResDirectoryId || pd.dataSetResFileName != dataSetResFileName))
|| (pd.dataJsonPath != dataJsonPath) || (pd.encoding != encoding);
|| (pd.dataJsonPath != dataJsonPath) || (pd.encoding != encoding)
|| po.isPreviewParamPropertyDataFormatModified());
};
po.previewOptions.url = po.url("previewJsonFile");

View File

@ -82,9 +82,7 @@ readonly 是否只读操作允许为null
var selectionRange = po.jsonEditor.getSelectionRange();
return (po.jsonEditor.session.getTextRange(selectionRange) || "");
};
po.initDataSetPropertiesTable(po.dataSetProperties);
po.initDataSetParamsTable(po.dataSetParams);
po.initPreviewParamValuePanel();
po.initParamPropertyDataFormat(po.dataSetParams, po.dataSetProperties);
po.updatePreviewOptionsData = function()
{
@ -107,7 +105,7 @@ readonly 是否只读操作允许为null
var pd = po.previewOptions.data.dataSet;
return (pd.value != value);
return (pd.value != value || po.isPreviewParamPropertyDataFormatModified());
};
po.previewOptions.url = po.url("previewJsonValue");

View File

@ -119,9 +119,7 @@ readonly 是否只读操作允许为null
var selectionRange = po.sqlEditor.getSelectionRange();
return (po.sqlEditor.session.getTextRange(selectionRange) || "");
};
po.initDataSetPropertiesTable(po.dataSetProperties);
po.initDataSetParamsTable(po.dataSetParams);
po.initPreviewParamValuePanel();
po.initParamPropertyDataFormat(po.dataSetParams, po.dataSetProperties);
po.updatePreviewOptionsData = function()
{
@ -147,7 +145,7 @@ readonly 是否只读操作允许为null
var pd = po.previewOptions.data.dataSet;
return (pd.sql != sql) || (po.previewOptions.data.schemaId != schemaId);
return (pd.sql != sql || po.previewOptions.data.schemaId != schemaId || po.isPreviewParamPropertyDataFormatModified());
};
po.previewOptions.url = po.url("previewSql");

View File

@ -37,6 +37,9 @@ DataSetEntity dataSet 允许为null
<input type="text" class="resultFetchSizeInput ui-widget ui-widget-content ui-corner-all" />
</div>
</div>
<div class="preview-error-info ui-state-error">
<textarea class="ui-widget ui-widget-content"></textarea>
</div>
</div>
<div id="${pageId}-dataSetParams" class="params-table-wrapper minor-dataTable">
<div class="operation">

View File

@ -690,7 +690,13 @@ po.previewOptions.url = "...";
return po.buildDataSetPropertiesColumns(previewResponse.properties);
},
//预览请求成功回调函数
success: function(previewResponse){}
success: function(previewResponse){},
//预览出错回调函数,返回非空字符串表明将其显示在错误信息区内
error: function(operationMessage, jqXHR)
{
if(operationMessage && operationMessage.data)
return operationMessage.data[1];
}
};
po.resultFetchSizeVal = function(val)
@ -750,9 +756,79 @@ po.previewOptions.url = "...";
table.empty();
}
};
po.isPreviewParamPropertyDataFormatModified = function()
{
var formParams = (po.getFormDataSetParams() || []);
var formProperties = (po.getFormDataSetProperties() || []);
var formDataFormat = (po.getFormDataFormat() || {});
var params = (po.previewOptions.data.dataSet.params || []);
var properties = (po.previewOptions.data.dataSet.properties || []);
var dataFormat = (po.previewOptions.data.dataSet.dataFormat || {});
//参数数组大小必须一致,因为不一致有可能影响数据集结果
if(formParams.length != params.length)
return true;
for(var i=0; i<formParams.length; i++)
{
var fp = formParams[i];
var p = null;
for(var j=0; j<params.length; j++)
{
if(params[j].name == fp.name)
p = params[j];
}
if(p == null || fp.name != p.name || fp.type != p.type || fp.required != p.required
|| fp.inputType != p.inputType || fp.inputPayload != p.inputPayload)
{
return true;
}
}
//属性数组大小不必一致,因为不一致不一定影响数据集结果
for(var i=0; i<formProperties.length; i++)
{
var fp = formProperties[i];
var p = null;
for(var j=0; j<properties.length; j++)
{
if(properties[j].name == fp.name)
p = properties[j];
}
if(p == null || fp.name != p.name || fp.type != p.type || fp.defaultValue != p.defaultValue)
{
return true;
}
}
if(formDataFormat.dateFormat != dataFormat.dateFormat || formDataFormat.timeFormat != dataFormat.timeFormat
|| formDataFormat.timestampFormat != dataFormat.timestampFormat || formDataFormat.numberFormat != dataFormat.numberFormat)
{
return true;
}
return false;
};
po.initParamPropertyDataFormat = function(params, properties)
{
po.initDataSetParamsTable(po.dataSetParams);
po.initDataSetPropertiesTable(po.dataSetProperties);
po.initPreviewParamValuePanel();
};
po.initPreviewOperations = function()
{
po.previewOptions.data.dataSet.params = po.getFormDataSetParams();
po.previewOptions.data.dataSet.properties = po.getFormDataSetProperties();
po.previewOptions.data.dataSet.dataFormat = po.getFormDataFormat();
po.element(".preview-result-table-wrapper .preview-button").click(function(event)
{
var previewValueModified = po.isPreviewValueModified();
@ -845,6 +921,7 @@ po.previewOptions.url = "...";
$(this).button("disable");
});
po.element(".preview-error-info").hide();
po.element(".preview-result-foot").hide();
var table = po.previewResultTableElement();
@ -865,7 +942,10 @@ po.previewOptions.url = "...";
//如果工作区内容已变更才更新属性,防止上次保存后的属性被刷新
//属性表单内容为空也更新,比如用户删除了所有属性时
if(previewValueModified || !po.hasFormDataSetProperty())
{
po.updateFormDataSetProperties(previewResponse.properties);
po.previewOptions.data.dataSet.properties = po.getFormDataSetProperties();
}
var tableData = (previewResponse.result.data || []);
if(!$.isArray(tableData))
@ -928,9 +1008,17 @@ po.previewOptions.url = "...";
po.previewOptions.success(previewResponse);
},
error: function()
error: function(jqXHR)
{
po.previewSuccess(false);
var errorInfo = po.previewOptions.error(jqXHR.responseJSON, jqXHR);
if(errorInfo)
{
po.element(".preview-error-info textarea").val(errorInfo);
po.element(".preview-error-info").show();
}
},
complete: function()
{

View File

@ -14,6 +14,7 @@
<#include "include/html_doctype.ftl">
<html>
<head>
<meta dg-page-name="error" />
<#include "include/html_head.ftl">
<title><#include "include/html_title_app_name.ftl"><@spring.message code='error.errorOccure' /></title>
</head>

View File

@ -10,6 +10,7 @@
<#include "include/html_doctype.ftl">
<html>
<head>
<meta dg-page-name="login" />
<#include "include/html_head.ftl">
${detectNewVersionScript?no_esc}
<title><#include "include/html_title_app_name.ftl"><@spring.message code='login.login' /></title>

View File

@ -0,0 +1,172 @@
<#--
*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*
-->
<#include "../include/import_global.ftl">
<#include "../include/html_doctype.ftl">
<#--
titleMessageKey 标题标签I18N关键字不允许null
formAction 表单提交action允许为null
-->
<#assign formAction=(formAction!'#')>
<html>
<head>
<#include "../include/html_head.ftl">
<title><#include "../include/html_title_app_name.ftl"><@spring.message code='${titleMessageKey}' /></title>
</head>
<body>
<#include "../include/page_js_obj.ftl" >
<div id="${pageId}" class="page-form page-form-user-delete">
<form id="${pageId}-form" action="${contextPath}/user/${formAction}" method="POST">
<div class="form-head"></div>
<div class="form-content">
<div class="form-item">
<div class="form-item-label">
<label><@spring.message code='user.name' /></label>
</div>
<div class="form-item-value">
<div class="delete-users ui-widget ui-widget-content input minor-list deletable-list">
</div>
<input type="text" name="deleteUserPlaceholder" style="display:none;" />
</div>
</div>
<div class="form-item">
<div class="form-item-label">
<label title="<@spring.message code='user.migrateDataToUser.desc' />">
<@spring.message code='user.migrateDataToUser' />
</label>
</div>
<div class="form-item-value">
<input type="text" name="migrateUserName" value="" class="ui-widget ui-widget-content" readonly="readonly" />
<input type="hidden" name="migrateToId" value="" />
<button class="selectUserBtn" type="button"><@spring.message code='select' /></button>
</div>
</div>
</div>
<div class="form-foot" style="text-align:center;">
<input type="submit" value="<@spring.message code='delete' />" class="danger" />
</div>
</form>
</div>
<#include "../include/page_obj_form.ftl">
<script type="text/javascript">
(function(po)
{
po.deleteUsers = <@writeJson var=deleteUsers />;
$.initButtons(po.element());
po.url = function(action)
{
return "${contextPath}/user/" + action;
};
po.element(".delete-users").on("click", ".delete-icon", function()
{
$(this).closest(".minor-list-item").remove();
});
po.renderUsers = function(roles)
{
roles = (roles || []);
var $parent = po.element(".delete-users");
for(var i=0; i<roles.length; i++)
po.renderUser($parent, roles[i]);
}
po.renderUser = function($parent, user)
{
var $item = $("<div class='minor-list-item ui-widget ui-widget-content ui-corner-all' />").appendTo($parent);
$("<input type='hidden' class='deleteUserIds' name='ids[]' />").attr("value", user.id).appendTo($item);
$("<span class='delete-icon ui-icon ui-icon-close' title='<@spring.message code='delete' />' />").appendTo($item);
$("<div class='item-content' />").text(user.nameLabel).appendTo($item);
};
po.element(".selectUserBtn").click(function()
{
var options =
{
pageParam :
{
select : function(user)
{
po.element("input[name='migrateToId']").val(user.id);
po.element("input[name='migrateUserName']").val(user.nameLabel);
}
}
};
$.setGridPageHeightOption(options);
po.open("${contextPath}/user/select", options);
});
$.validator.addMethod("deleteUserIdRequired", function(value, element)
{
var $du = po.element(".deleteUserIds");
return ($du.length > 0);
});
$.validator.addMethod("migrateToUserIdIllegal", function(value, element)
{
var $du = po.element(".deleteUserIds");
var mu = po.element("input[name='migrateToId']").val();
for(var i=0; i<$du.length; i++)
{
if(mu == $($du[i]).val())
return false;
}
return true;
});
po.form().validate(
{
ignore : "",
rules :
{
deleteUserPlaceholder : "deleteUserIdRequired",
migrateUserName : { "required": true, "migrateToUserIdIllegal": true }
},
messages :
{
deleteUserPlaceholder : "<@spring.message code='validation.required' />",
migrateUserName :
{
"required": "<@spring.message code='validation.required' />",
"migrateToUserIdIllegal": "<@spring.message code='user.validation.migrateToUserIdIllegal' />"
}
},
submitHandler : function(form)
{
var data = $.formToJson(form, ["deleteUserPlaceholder", "migrateUserName"]);
$.ajaxJson($(form).attr("action"),
{
data: data,
success : function(response)
{
po.pageParamCallAfterSave(true, response.data);
}
});
},
errorPlacement : function(error, element)
{
error.appendTo(element.closest(".form-item-value"));
}
});
po.renderUsers(po.deleteUsers);
})
(${pageId});
</script>
</body>
</html>

View File

@ -34,7 +34,7 @@ readonly 是否只读操作允许为null
<label><@spring.message code='user.name' /></label>
</div>
<div class="form-item-value">
<input type="text" name="name" value="${(user.name)!''}" class="ui-widget ui-widget-content" />
<input type="text" name="name" value="${(user.name)!''}" class="ui-widget ui-widget-content" autocomplete="off" />
</div>
</div>
<#if !readonly>
@ -60,7 +60,7 @@ readonly 是否只读操作允许为null
<label><@spring.message code='user.realName' /></label>
</div>
<div class="form-item-value">
<input type="text" name="realName" value="${(user.realName)!''}" class="ui-widget ui-widget-content" />
<input type="text" name="realName" value="${(user.realName)!''}" class="ui-widget ui-widget-content" autocomplete="off" />
</div>
</div>
<#if !disableRoles>

View File

@ -114,7 +114,12 @@ boolean readonly 是否只读操作默认为false
{
po.executeOnSelects(function(rows)
{
po.confirmDeleteEntities(po.url("delete"), rows);
var data = $.getPropertyParamString(rows, "id");
po.open(po.url("delete"),
{
data : data
});
});
});

View File

@ -4,7 +4,7 @@
<groupId>org.datagear</groupId>
<artifactId>datagear</artifactId>
<version>2.8.0</version>
<version>2.9.0</version>
<packaging>pom</packaging>
<name>datagear</name>
@ -13,7 +13,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<springboot.version>2.4.6</springboot.version>
<springboot.version>2.4.10</springboot.version>
<javax.json.version>1.0.4</javax.json.version>
<commons-csv.version>1.4</commons-csv.version>
<poi.version>3.17</poi.version>