提交 50d3a1c3 authored 作者: taojinlong's avatar taojinlong

refactor: 解决冲突

FROM registry.cn-qingdao.aliyuncs.com/dataease/fabric8-java-alpine-openjdk8-jre
FROM registry.cn-qingdao.aliyuncs.com/dataease/fabric8-java-alpine-openjdk8-jre:3.15.0
RUN echo -e 'http://mirrors.aliyun.com/alpine/v3.15/main/\nhttp://mirrors.aliyun.com/alpine/v3.15/community/' > /etc/apk/repositories
RUN apk add chromium chromium-chromedriver fontconfig --no-cache --allow-untrusted
ADD simsun.ttc /usr/share/fonts/
RUN cd /usr/share/fonts/ \
&& mkfontscale \
&& mkfontdir \
&& fc-cache -fv
ARG IMAGE_TAG
......
......@@ -12,12 +12,12 @@ public class ShiroServiceImpl implements ShiroService {
private final static String ANON = "anon";
@Override
public Map<String, String> loadFilterChainDefinitionMap() {
// 权限控制map
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 配置过滤:不会被拦截的链接 -> 放行 start ----------------------------------------------------------
// 配置过滤:不会被拦截的链接 -> 放行 start
// ----------------------------------------------------------
// 放行Swagger2页面,需要放行这些
filterChainDefinitionMap.put("/doc.html**", "doc");
......@@ -42,17 +42,20 @@ public class ShiroServiceImpl implements ShiroService {
filterChainDefinitionMap.put("/index.html", ANON);
filterChainDefinitionMap.put("/link.html", ANON);
//获取主题信息
// 获取主题信息
filterChainDefinitionMap.put("/plugin/theme/themes", ANON);
filterChainDefinitionMap.put("/plugin/theme/items/**", ANON);
//验证链接
// 验证链接
filterChainDefinitionMap.put("/api/link/validate**", ANON);
filterChainDefinitionMap.put("/api/map/areaEntitys/**", ANON);
filterChainDefinitionMap.put("/dataset/field/fieldValues/**", ANON);
filterChainDefinitionMap.put("/linkJump/queryPanelJumpInfo/**", ANON);
filterChainDefinitionMap.put("/tempMobileLink/**", ANON);
filterChainDefinitionMap.put("/de-app/**", ANON);
filterChainDefinitionMap.put("/app.html", ANON);
filterChainDefinitionMap.put("/**/*.json", ANON);
filterChainDefinitionMap.put("/system/ui/**", ANON);
filterChainDefinitionMap.put("/**/*.js", ANON);
......@@ -70,7 +73,6 @@ public class ShiroServiceImpl implements ShiroService {
filterChainDefinitionMap.put("/plugin/oidc/authInfo", ANON);
filterChainDefinitionMap.put("/sso/callBack*", ANON);
filterChainDefinitionMap.put("/unauth", ANON);
filterChainDefinitionMap.put("/display/**", ANON);
filterChainDefinitionMap.put("/tokenExpired", ANON);
......@@ -82,7 +84,6 @@ public class ShiroServiceImpl implements ShiroService {
filterChainDefinitionMap.put("/api/link/resourceDetail/**", "link");
filterChainDefinitionMap.put("/api/link/viewDetail/**", "link");
filterChainDefinitionMap.put("/**", "authc");
filterChainDefinitionMap.put("/**", "jwt");
......@@ -90,9 +91,9 @@ public class ShiroServiceImpl implements ShiroService {
return filterChainDefinitionMap;
}
@Override
public void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, Integer roleId, Boolean isRemoveSession) {
public void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, Integer roleId,
Boolean isRemoveSession) {
}
......
package io.dataease.base.domain;
import java.io.Serializable;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class PanelGroup implements Serializable {
@ApiModelProperty("ID")
private String id;
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("父ID")
private String pid;
@ApiModelProperty("级别")
private Integer level;
@ApiModelProperty("节点类型")
private String nodeType;
@ApiModelProperty("创建者")
private String createBy;
@ApiModelProperty("创建时间")
private Long createTime;
@ApiModelProperty("类型")
private String panelType;
@ApiModelProperty("源")
private String source;
@ApiModelProperty("拓展1")
private String extend1;
@ApiModelProperty("拓展2")
private String extend2;
@ApiModelProperty("重新标记")
private String remark;
private Boolean mobileLayout;
private static final long serialVersionUID = 1L;
}
\ No newline at end of file
......@@ -923,6 +923,66 @@ public class PanelGroupExample {
addCriterion("remark not between", value1, value2, "remark");
return (Criteria) this;
}
public Criteria andMobileLayoutIsNull() {
addCriterion("mobile_layout is null");
return (Criteria) this;
}
public Criteria andMobileLayoutIsNotNull() {
addCriterion("mobile_layout is not null");
return (Criteria) this;
}
public Criteria andMobileLayoutEqualTo(Boolean value) {
addCriterion("mobile_layout =", value, "mobileLayout");
return (Criteria) this;
}
public Criteria andMobileLayoutNotEqualTo(Boolean value) {
addCriterion("mobile_layout <>", value, "mobileLayout");
return (Criteria) this;
}
public Criteria andMobileLayoutGreaterThan(Boolean value) {
addCriterion("mobile_layout >", value, "mobileLayout");
return (Criteria) this;
}
public Criteria andMobileLayoutGreaterThanOrEqualTo(Boolean value) {
addCriterion("mobile_layout >=", value, "mobileLayout");
return (Criteria) this;
}
public Criteria andMobileLayoutLessThan(Boolean value) {
addCriterion("mobile_layout <", value, "mobileLayout");
return (Criteria) this;
}
public Criteria andMobileLayoutLessThanOrEqualTo(Boolean value) {
addCriterion("mobile_layout <=", value, "mobileLayout");
return (Criteria) this;
}
public Criteria andMobileLayoutIn(List<Boolean> values) {
addCriterion("mobile_layout in", values, "mobileLayout");
return (Criteria) this;
}
public Criteria andMobileLayoutNotIn(List<Boolean> values) {
addCriterion("mobile_layout not in", values, "mobileLayout");
return (Criteria) this;
}
public Criteria andMobileLayoutBetween(Boolean value1, Boolean value2) {
addCriterion("mobile_layout between", value1, value2, "mobileLayout");
return (Criteria) this;
}
public Criteria andMobileLayoutNotBetween(Boolean value1, Boolean value2) {
addCriterion("mobile_layout not between", value1, value2, "mobileLayout");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
......
package io.dataease.base.domain;
import java.io.Serializable;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
......@@ -11,9 +9,8 @@ import lombok.ToString;
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PanelGroupWithBLOBs extends PanelGroup implements Serializable {
@ApiModelProperty("仪表板样式")
private String panelStyle;
@ApiModelProperty("仪表板数据")
private String panelData;
private static final long serialVersionUID = 1L;
......
......@@ -14,6 +14,7 @@
<result column="extend1" jdbcType="VARCHAR" property="extend1" />
<result column="extend2" jdbcType="VARCHAR" property="extend2" />
<result column="remark" jdbcType="VARCHAR" property="remark" />
<result column="mobile_layout" jdbcType="BIT" property="mobileLayout" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.dataease.base.domain.PanelGroupWithBLOBs">
<result column="panel_style" jdbcType="LONGVARCHAR" property="panelStyle" />
......@@ -79,7 +80,7 @@
</sql>
<sql id="Base_Column_List">
id, `name`, pid, `level`, node_type, create_by, create_time, panel_type, `source`,
extend1, extend2, remark
extend1, extend2, remark, mobile_layout
</sql>
<sql id="Blob_Column_List">
panel_style, panel_data
......@@ -137,12 +138,14 @@
`level`, node_type, create_by,
create_time, panel_type, `source`,
extend1, extend2, remark,
panel_style, panel_data)
mobile_layout, panel_style, panel_data
)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{pid,jdbcType=VARCHAR},
#{level,jdbcType=INTEGER}, #{nodeType,jdbcType=VARCHAR}, #{createBy,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{panelType,jdbcType=VARCHAR}, #{source,jdbcType=VARCHAR},
#{extend1,jdbcType=VARCHAR}, #{extend2,jdbcType=VARCHAR}, #{remark,jdbcType=VARCHAR},
#{panelStyle,jdbcType=LONGVARCHAR}, #{panelData,jdbcType=LONGVARCHAR})
#{mobileLayout,jdbcType=BIT}, #{panelStyle,jdbcType=LONGVARCHAR}, #{panelData,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.dataease.base.domain.PanelGroupWithBLOBs">
insert into panel_group
......@@ -183,6 +186,9 @@
<if test="remark != null">
remark,
</if>
<if test="mobileLayout != null">
mobile_layout,
</if>
<if test="panelStyle != null">
panel_style,
</if>
......@@ -227,6 +233,9 @@
<if test="remark != null">
#{remark,jdbcType=VARCHAR},
</if>
<if test="mobileLayout != null">
#{mobileLayout,jdbcType=BIT},
</if>
<if test="panelStyle != null">
#{panelStyle,jdbcType=LONGVARCHAR},
</if>
......@@ -280,6 +289,9 @@
<if test="record.remark != null">
remark = #{record.remark,jdbcType=VARCHAR},
</if>
<if test="record.mobileLayout != null">
mobile_layout = #{record.mobileLayout,jdbcType=BIT},
</if>
<if test="record.panelStyle != null">
panel_style = #{record.panelStyle,jdbcType=LONGVARCHAR},
</if>
......@@ -305,6 +317,7 @@
extend1 = #{record.extend1,jdbcType=VARCHAR},
extend2 = #{record.extend2,jdbcType=VARCHAR},
remark = #{record.remark,jdbcType=VARCHAR},
mobile_layout = #{record.mobileLayout,jdbcType=BIT},
panel_style = #{record.panelStyle,jdbcType=LONGVARCHAR},
panel_data = #{record.panelData,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
......@@ -324,7 +337,8 @@
`source` = #{record.source,jdbcType=VARCHAR},
extend1 = #{record.extend1,jdbcType=VARCHAR},
extend2 = #{record.extend2,jdbcType=VARCHAR},
remark = #{record.remark,jdbcType=VARCHAR}
remark = #{record.remark,jdbcType=VARCHAR},
mobile_layout = #{record.mobileLayout,jdbcType=BIT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
......@@ -365,6 +379,9 @@
<if test="remark != null">
remark = #{remark,jdbcType=VARCHAR},
</if>
<if test="mobileLayout != null">
mobile_layout = #{mobileLayout,jdbcType=BIT},
</if>
<if test="panelStyle != null">
panel_style = #{panelStyle,jdbcType=LONGVARCHAR},
</if>
......@@ -387,6 +404,7 @@
extend1 = #{extend1,jdbcType=VARCHAR},
extend2 = #{extend2,jdbcType=VARCHAR},
remark = #{remark,jdbcType=VARCHAR},
mobile_layout = #{mobileLayout,jdbcType=BIT},
panel_style = #{panelStyle,jdbcType=LONGVARCHAR},
panel_data = #{panelData,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
......@@ -403,7 +421,8 @@
`source` = #{source,jdbcType=VARCHAR},
extend1 = #{extend1,jdbcType=VARCHAR},
extend2 = #{extend2,jdbcType=VARCHAR},
remark = #{remark,jdbcType=VARCHAR}
remark = #{remark,jdbcType=VARCHAR},
mobile_layout = #{mobileLayout,jdbcType=BIT}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>
\ No newline at end of file
......@@ -19,6 +19,7 @@ import java.io.IOException;
@RequestMapping
public class IndexController {
private static final int FOR_EVER = 3600 * 24 * 30 * 12 * 10; // 10 years in second
@Resource
private DefaultLicenseService defaultLicenseService;
......@@ -35,7 +36,6 @@ public class IndexController {
return "index.html";
}
@GetMapping("/deApi")
public String deApi() {
F2CLicenseResponse f2CLicenseResponse = defaultLicenseService.validateLicense();
......@@ -59,5 +59,20 @@ public class IndexController {
}
}
@GetMapping("/tempMobileLink/{id}/{token}")
public void tempMobileLink(@PathVariable("id") String id, @PathVariable("token") String token) {
String url = "http://localhost:8081/#preview/" + id;
HttpServletResponse response = ServletUtils.response();
Cookie cookie = new Cookie("Authorization", token);
cookie.setPath("/");
cookie.setMaxAge(FOR_EVER);
response.addCookie(cookie);
try {
response.sendRedirect(url);
} catch (IOException e) {
LogUtil.error(e.getMessage());
DEException.throwException(e);
}
}
}
......@@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author gin
......@@ -75,4 +76,11 @@ public class DataSetTableFieldController {
public List<Object> fieldValues(@PathVariable String fieldId) {
return dataSetFieldService.fieldValues(fieldId);
}
@ApiOperation("多字段值枚举")
@PostMapping("multFieldValues")
public List<Object> multFieldValues(@RequestBody List<String> fieldIds) {
List<Object> results = fieldIds.stream().map(fieldId -> dataSetFieldService.fieldValues(fieldId)).flatMap(list -> list.stream()).distinct().collect(Collectors.toList());
return results;
}
}
......@@ -17,4 +17,6 @@ public class ChartFieldCustomFilterDTO extends ChartViewFieldBaseDTO implements
private List<ChartCustomFilterItemDTO> filter;
private DatasetTableField field;
private List<String> enumCheckField;
}
......@@ -48,4 +48,6 @@ public class ChartViewFieldBaseDTO implements Serializable {
private ChartFieldCompareDTO compareCalc;
private String logic;
private String filterType;
}
......@@ -735,62 +735,74 @@ public class MysqlQueryProvider extends QueryProvider {
for (ChartFieldCustomFilterDTO request : requestList) {
List<SQLObj> list = new ArrayList<>();
DatasetTableField field = request.getField();
List<ChartCustomFilterItemDTO> filter = request.getFilter();
for (ChartCustomFilterItemDTO filterItemDTO : filter) {
if (ObjectUtils.isEmpty(field)) {
continue;
if (ObjectUtils.isEmpty(field)) {
continue;
}
String whereName = "";
String originName;
if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 2) {
// 解析origin name中有关联的字段生成sql表达式
originName = calcFieldRegex(field.getOriginName(), tableObj);
} else if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 1) {
originName = String.format(MySQLConstants.KEYWORD_FIX, tableObj.getTableAlias(), field.getOriginName());
} else {
originName = String.format(MySQLConstants.KEYWORD_FIX, tableObj.getTableAlias(), field.getOriginName());
}
if (field.getDeType() == 1) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
whereName = String.format(MySQLConstants.STR_TO_DATE, originName, MySQLConstants.DEFAULT_DATE_FORMAT);
}
String value = filterItemDTO.getValue();
String whereName = "";
String whereTerm = transMysqlFilterTerm(filterItemDTO.getTerm());
String whereValue = "";
String originName;
if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 2) {
// 解析origin name中有关联的字段生成sql表达式
originName = calcFieldRegex(field.getOriginName(), tableObj);
} else if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 1) {
originName = String.format(MySQLConstants.KEYWORD_FIX, tableObj.getTableAlias(), field.getOriginName());
} else {
originName = String.format(MySQLConstants.KEYWORD_FIX, tableObj.getTableAlias(), field.getOriginName());
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
String cast = String.format(MySQLConstants.CAST, originName, MySQLConstants.DEFAULT_INT_FORMAT) + "/1000";
whereName = String.format(MySQLConstants.FROM_UNIXTIME, cast, MySQLConstants.DEFAULT_DATE_FORMAT);
}
if (field.getDeType() == 1) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
whereName = String.format(MySQLConstants.STR_TO_DATE, originName, MySQLConstants.DEFAULT_DATE_FORMAT);
}
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
String cast = String.format(MySQLConstants.CAST, originName, MySQLConstants.DEFAULT_INT_FORMAT) + "/1000";
whereName = String.format(MySQLConstants.FROM_UNIXTIME, cast, MySQLConstants.DEFAULT_DATE_FORMAT);
if (field.getDeExtractType() == 1) {
whereName = originName;
}
} else {
whereName = originName;
}
if (StringUtils.equalsIgnoreCase(request.getFilterType(), "enum")) {
if (CollectionUtils.isNotEmpty(request.getEnumCheckField())) {
res.add("(" + whereName + " IN ('" + String.join("','", request.getEnumCheckField()) + "'))");
}
} else {
List<ChartCustomFilterItemDTO> filter = request.getFilter();
for (ChartCustomFilterItemDTO filterItemDTO : filter) {
if (ObjectUtils.isEmpty(field)) {
continue;
}
if (field.getDeExtractType() == 1) {
whereName = originName;
String value = filterItemDTO.getValue();
String whereTerm = transMysqlFilterTerm(filterItemDTO.getTerm());
String whereValue = "";
if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "null")) {
whereValue = "";
} else if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "not_null")) {
whereValue = "";
} else if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "empty")) {
whereValue = "''";
} else if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "not_empty")) {
whereValue = "''";
} else if (StringUtils.containsIgnoreCase(filterItemDTO.getTerm(), "in")) {
whereValue = "('" + StringUtils.join(value, "','") + "')";
} else if (StringUtils.containsIgnoreCase(filterItemDTO.getTerm(), "like")) {
whereValue = "'%" + value + "%'";
} else {
whereValue = String.format(MySQLConstants.WHERE_VALUE_VALUE, value);
}
} else {
whereName = originName;
list.add(SQLObj.builder()
.whereField(whereName)
.whereTermAndValue(whereTerm + whereValue)
.build());
}
if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "null")) {
whereValue = "";
} else if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "not_null")) {
whereValue = "";
} else if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "empty")) {
whereValue = "''";
} else if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "not_empty")) {
whereValue = "''";
} else if (StringUtils.containsIgnoreCase(filterItemDTO.getTerm(), "in")) {
whereValue = "('" + StringUtils.join(value, "','") + "')";
} else if (StringUtils.containsIgnoreCase(filterItemDTO.getTerm(), "like")) {
whereValue = "'%" + value + "%'";
} else {
whereValue = String.format(MySQLConstants.WHERE_VALUE_VALUE, value);
List<String> strList = new ArrayList<>();
list.forEach(ele -> strList.add(ele.getWhereField() + " " + ele.getWhereTermAndValue()));
if (CollectionUtils.isNotEmpty(list)) {
res.add("(" + String.join(" " + getLogic(request.getLogic()) + " ", strList) + ")");
}
list.add(SQLObj.builder()
.whereField(whereName)
.whereTermAndValue(whereTerm + whereValue)
.build());
}
List<String> strList = new ArrayList<>();
list.forEach(ele -> strList.add(ele.getWhereField() + " " + ele.getWhereTermAndValue()));
if (CollectionUtils.isNotEmpty(list)) {
res.add("(" + String.join(" " + getLogic(request.getLogic()) + " ", strList) + ")");
}
}
return CollectionUtils.isNotEmpty(res) ? "(" + String.join(" AND ", res) + ")" : null;
......
......@@ -245,19 +245,29 @@ public class ChartViewService {
// 过滤来自仪表板的条件
List<ChartExtFilterRequest> extFilterList = new ArrayList<>();
//组件过滤条件
if (ObjectUtils.isNotEmpty(requestList.getFilter())) {
for (ChartExtFilterRequest request : requestList.getFilter()) {
DatasetTableField datasetTableField = dataSetTableFieldsService.get(request.getFieldId());
request.setDatasetTableField(datasetTableField);
if (StringUtils.equalsIgnoreCase(datasetTableField.getTableId(), view.getTableId())) {
if (CollectionUtils.isNotEmpty(request.getViewIds())) {
if (request.getViewIds().contains(view.getId())) {
extFilterList.add(request);
// 解析多个fieldId,fieldId是一个逗号分隔的字符串
String fieldId = request.getFieldId();
if (StringUtils.isNotEmpty(fieldId)) {
String[] fieldIds = fieldId.split(",");
for (String fId : fieldIds) {
ChartExtFilterRequest filterRequest = new ChartExtFilterRequest();
BeanUtils.copyBean(filterRequest, request);
filterRequest.setFieldId(fId);
DatasetTableField datasetTableField = dataSetTableFieldsService.get(fId);
filterRequest.setDatasetTableField(datasetTableField);
if (StringUtils.equalsIgnoreCase(datasetTableField.getTableId(), view.getTableId())) {
if (CollectionUtils.isNotEmpty(filterRequest.getViewIds())) {
if (filterRequest.getViewIds().contains(view.getId())) {
extFilterList.add(filterRequest);
}
} else {
extFilterList.add(filterRequest);
}
}
} else {
extFilterList.add(request);
}
}
}
......
......@@ -78,7 +78,8 @@ public class PanelGroupService {
@Transactional
public PanelGroup saveOrUpdate(PanelGroupRequest request) {
try {
panelViewService.syncPanelViews(request);
Boolean mobileLayout = panelViewService.syncPanelViews(request);
request.setMobileLayout(mobileLayout);
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("更新panelView出错panelId:{}", request.getId());
......
......@@ -73,7 +73,8 @@ public class PanelViewService {
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void syncPanelViews(PanelGroupWithBLOBs panelGroup){
public Boolean syncPanelViews(PanelGroupWithBLOBs panelGroup){
Boolean mobileLayout = false;
String panelId = panelGroup.getId();
Assert.notNull(panelId, "panelId cannot be null");
String panelData = panelGroup.getPanelData();
......@@ -85,12 +86,16 @@ public class PanelViewService {
if("view".equals(jsonObject.getString("type"))){
panelViewInsertDTOList.add(new PanelViewInsertDTO(jsonObject.getJSONObject("propValue").getString("viewId"),panelId));
}
if(jsonObject.getBoolean("mobileSelected")!=null&&jsonObject.getBoolean("mobileSelected")){
mobileLayout = true;
}
}
extPanelViewMapper.deleteWithPanelId(panelId);
if(CollectionUtils.isNotEmpty(panelViewInsertDTOList)){
extPanelViewMapper.savePanelView(panelViewInsertDTOList);
}
}
return mobileLayout;
}
public List<PanelViewTableDTO> detailList(String panelId){
......
......@@ -10,9 +10,13 @@ CREATE TABLE `dataset_row_permissions` (
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
ALTER TABLE `panel_link` ADD COLUMN `user_id` BIGINT(20) NULL DEFAULT NULL ;
ALTER TABLE `panel_link_mapping` ADD COLUMN `user_id` BIGINT(20) NULL DEFAULT NULL ;
ALTER TABLE `panel_link`CHANGE COLUMN `user_id` `user_id` BIGINT(20) NOT NULL ,DROP PRIMARY KEY;
ALTER TABLE `panel_group`
ADD COLUMN `mobile_layout` tinyint(1) NULL DEFAULT 0 COMMENT '启用移动端布局' AFTER `remark`;
......@@ -62,7 +62,6 @@
<!--要生成的数据库表 -->
<table tableName="panel_link_mapping">
</table>
<table tableName="panel_group"/>
</context>
</generatorConfiguration>
......@@ -138,6 +138,15 @@ export function fieldValues(fieldId) {
})
}
export function multFieldValues(data) {
return request({
url: '/dataset/field/multFieldValues',
method: 'post',
loading: true,
data
})
}
export function isKettleRunning(showLoading = true) {
return request({
url: '/dataset/group/isKettleRunning',
......
......@@ -9,6 +9,7 @@
[classNameResizable]: resizable,
[classNameRotating]: rotating,
[classNameRotatable]: rotatable,
[classNameActive]: enabled ,
['linkageSetting']:linkageActive,
['positionChange']:!(dragging || resizing||rotating)
},
......@@ -22,7 +23,7 @@
<div
:class="[
{
[classNameActive]: enabled ,
['de-drag-active-inner']:enabled,
[classNameMouseOn]: mouseOn || active
},
className
......@@ -1809,7 +1810,10 @@ export default {
}
.de-drag-active{
outline: 1px solid #70c0ff;
user-select: none;
}
.de-drag-active-inner{
outline: 1px solid #70c0ff;
}
</style>
<template>
<div class="bar-main">
<div style="margin-right: -1px;width: 18px">
<i class="icon iconfont icon-guanbi" @click.stop="closePreview" />
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import bus from '@/utils/bus'
import SettingMenu from '@/components/canvas/components/Editor/SettingMenu'
import LinkageField from '@/components/canvas/components/Editor/LinkageField'
export default {
components: { },
props: {
},
data() {
return {
}
},
computed: {
},
mounted() {
},
beforeDestroy() {
},
methods: {
closePreview() {
this.$emit('closePreview')
}
}
}
</script>
<style lang="scss" scoped>
.bar-main{
position: absolute;
right: 0px;
float:right;
z-index: 2;
border-radius:2px;
padding-left: 5px;
padding-right: 2px;
cursor:pointer!important;
background-color: #0a7be0;
}
.bar-main i{
color: white;
float: right;
margin-right: 3px;
}
</style>
......@@ -6,6 +6,7 @@
@mousedown="elementMouseDown"
>
<edit-bar v-if="componentActiveFlag" :element="config" @showViewDetails="showViewDetails" />
<close-bar v-if="previewVisible" @closePreview="closePreview" />
<de-out-widget
v-if="config.type==='custom'"
:id="'component' + config.id"
......@@ -14,6 +15,7 @@
:out-style="config.style"
:element="config"
:in-screen="inScreen"
:h="config.style.height"
/>
<component
:is="config.component"
......@@ -28,6 +30,7 @@
:search-count="searchCount"
:h="config.style.height"
:edit-mode="'preview'"
:terminal="terminal"
/>
</div>
</template>
......@@ -40,9 +43,10 @@ import { mapState } from 'vuex'
import DeOutWidget from '@/components/dataease/DeOutWidget'
import EditBar from '@/components/canvas/components/Editor/EditBar'
import MobileCheckBar from '@/components/canvas/components/Editor/MobileCheckBar'
import CloseBar from '@/components/canvas/components/Editor/CloseBar'
export default {
components: { MobileCheckBar, DeOutWidget, EditBar },
components: { CloseBar, MobileCheckBar, DeOutWidget, EditBar },
mixins: [mixins],
props: {
config: {
......@@ -64,11 +68,20 @@ export default {
type: Boolean,
required: false,
default: true
},
terminal: {
type: String,
default: 'pc'
}
},
data() {
return {
previewVisible: false
}
},
computed: {
componentActiveFlag() {
return this.curComponent && this.config === this.curComponent
return (this.curComponent && this.config === this.curComponent) && !this.previewVisible
},
curGap() {
return this.config.auxiliaryMatrix ? this.componentGap : 0
......@@ -156,7 +169,14 @@ export default {
this.$store.commit('setCurComponent', { component: this.config, index: this.index })
},
showViewDetails() {
this.$refs.wrapperChild.openChartDetailsDialog()
if (this.terminal === 'pc') {
this.$refs.wrapperChild.openChartDetailsDialog()
} else {
this.previewVisible = true
}
},
closePreview() {
this.previewVisible = false
}
}
}
......
<template>
<div class="bar-main">
<div v-if="linkageSettingStatus&&element!==curLinkageView&&element.type==='view'" style="margin-right: -1px;width: 18px">
<div v-if="linkageAreaShow" style="margin-right: -1px;width: 18px">
<el-checkbox v-model="linkageInfo.linkageActive" />
<linkage-field v-if="linkageInfo.linkageActive" :element="element" />
</div>
<div v-else-if="!linkageSettingStatus">
<div v-if="normalAreaShow">
<setting-menu v-if="activeModel==='edit'" style="float: right;height: 24px!important;" @amRemoveItem="amRemoveItem" @linkJumpSet="linkJumpSet">
<span slot="icon" :title="$t('panel.setting')">
<i class="icon iconfont icon-shezhi" style="margin-top:2px" />
......@@ -26,7 +26,6 @@
<i v-if="curComponent.type==='view'&&existLinkage" class="icon iconfont icon-quxiaoliandong" @click.stop="clearLinkage" />
</span>
</div>
</div>
</template>
......@@ -54,6 +53,10 @@ export default {
type: String,
required: false,
default: 'preview'
},
previewVisible: {
type: Boolean,
default: false
}
},
data() {
......@@ -70,6 +73,14 @@ export default {
mounted() {
},
computed: {
// 联动区域按钮显示
linkageAreaShow() {
return this.linkageSettingStatus && this.element !== this.curLinkageView && this.element.type === 'view'
},
// 编辑或预览区域显示
normalAreaShow() {
return !this.linkageSettingStatus
},
existLinkage() {
let linkageFiltersCount = 0
this.componentData.forEach(item => {
......@@ -102,6 +113,9 @@ export default {
beforeDestroy() {
},
methods: {
closePreview() {
this.$emit('closePreview')
},
createTimer() {
if (!this.timer) {
this.timer = setInterval(() => {
......
......@@ -51,7 +51,7 @@
<svg-icon v-if="item.deType === 2 || item.value === 3" icon-class="field_value" class="field-icon-value" />
<svg-icon v-if="item.deType === 5" icon-class="field_location" class="field-icon-location" />
</span>
<span style="float: left; color: #8492a6; font-size: 12px">{{ itemLinkage.targetField }}-{{ item.name }}</span>
<span style="float: left; color: #8492a6; font-size: 12px">{{ item.name }}</span>
</el-option>
</el-select>
</div>
......
......@@ -19,6 +19,7 @@
:config="item"
:search-count="searchCount"
:in-screen="inScreen"
:terminal="terminal"
/>
<!--视图详情-->
<el-dialog
......@@ -36,6 +37,17 @@
</span>
<UserViewDialog ref="userViewDialog" :chart="showChartInfo" :chart-table="showChartTableInfo" />
</el-dialog>
<!--手机视图详情-->
<el-dialog
:title="'['+showChartInfo.name+']'+$t('chart.chart_details')"
:visible.sync="mobileChartDetailsVisible"
:fullscreen="true"
class="mobile-dialog-css"
:destroy-on-close="true"
>
<UserViewMobileDialog :chart="showChartInfo" :chart-table="showChartTableInfo" />
</el-dialog>
</div>
</div>
</div>
......@@ -52,9 +64,10 @@ import eventBus from '@/components/canvas/utils/eventBus'
import elementResizeDetectorMaker from 'element-resize-detector'
import UserViewDialog from '@/components/canvas/custom-component/UserViewDialog'
import CanvasOptBar from '@/components/canvas/components/Editor/CanvasOptBar'
import UserViewMobileDialog from '@/components/canvas/custom-component/UserViewMobileDialog'
export default {
components: { ComponentWrapper, UserViewDialog, CanvasOptBar },
components: { UserViewMobileDialog, ComponentWrapper, UserViewDialog, CanvasOptBar },
model: {
prop: 'show',
event: 'change'
......@@ -102,6 +115,7 @@ export default {
mainHeight: '100%',
searchCount: 0,
chartDetailsVisible: false,
mobileChartDetailsVisible: false,
showChartInfo: {},
showChartTableInfo: {},
// 布局展示 1.pc pc端布局 2.mobile 移动端布局
......@@ -215,6 +229,7 @@ export default {
const canvasWidth = document.getElementById('canvasInfoMain').offsetWidth
this.scaleWidth = (canvasWidth) * 100 / this.canvasStyleData.width // 获取宽度比
this.scaleHeight = canvasHeight * 100 / this.canvasStyleData.height// 获取高度比
this.$store.commit('setPreviewCanvasScale', (this.scaleWidth / 100), (this.scaleHeight / 100))
this.handleScaleChange()
},
resetID(data) {
......@@ -248,7 +263,11 @@ export default {
openChartDetailsDialog(chartInfo) {
this.showChartInfo = chartInfo.chart
this.showChartTableInfo = chartInfo.tableChart
this.chartDetailsVisible = true
if (this.terminal === 'pc') {
this.chartDetailsVisible = true
} else {
this.mobileChartDetailsVisible
}
},
exportExcel() {
this.$refs['userViewDialog'].exportExcel()
......@@ -308,9 +327,16 @@ export default {
padding: 10px 20px 20px;
}
.mobile-dialog-css > > > .el-dialog__body {
padding: 0px;
}
::-webkit-scrollbar {
width: 0px!important;
height: 0px!important;
}
::v-deep .el-tabs__nav{
z-index: 0;
}
</style>
......@@ -80,6 +80,7 @@
:element="item"
:out-style="getShapeStyleInt(item.style)"
:active="item === curComponent"
:h="getShapeStyleIntDeDrag(item.style,'height')"
/>
<component
:is="item.component"
......@@ -1194,6 +1195,7 @@ export default {
matrixStyleOriginWidth: this.matrixStyle.originWidth,
matrixStyleOriginHeight: this.matrixStyle.originHeight
})
this.$store.commit('setPreviewCanvasScale', this.scalePointWidth, this.scalePointHeight)
}
},
getShapeStyleIntDeDrag(style, prop) {
......@@ -1567,13 +1569,6 @@ export default {
padding:3px;
}
// 拖拽组件样式
.de-drag-active{
outline: 1px solid #70c0ff;
user-select: none;
}
.ref-line {
position: absolute;
background-color: #70c0ff;;
......
......@@ -69,6 +69,7 @@ import DrillPath from '@/views/chart/view/DrillPath'
import { areaMapping } from '@/api/map/map'
import ChartComponentG2 from '@/views/chart/components/ChartComponentG2'
import EditBarView from '@/components/canvas/components/Editor/EditBarView'
import { customAttrTrans, customStyleTrans, recursionTransObj } from '@/components/canvas/utils/style'
export default {
name: 'UserView',
......@@ -108,6 +109,10 @@ export default {
type: Boolean,
require: false,
default: true
},
terminal: {
type: String,
default: 'pc'
}
},
data() {
......@@ -125,12 +130,23 @@ export default {
msg: ''
},
timeMachine: null,
scaleTimeMachine: null,
changeIndex: 0,
changeScaleIndex: 0,
pre: null,
preCanvasPanel: null
preCanvasPanel: null,
sourceCustomAttrStr: null,
sourceCustomStyleStr: null
}
},
computed: {
scaleCoefficient() {
if (this.terminal === 'pc') {
return 1.1
} else {
return 4
}
},
editBarViewShowFlag() {
return this.active && this.inTab
},
......@@ -210,7 +226,8 @@ export default {
'canvasStyleData',
'nowPanelTrackInfo',
'nowPanelJumpInfo',
'publicLinkStatus'
'publicLinkStatus',
'previewCanvasScale'
])
},
......@@ -269,6 +286,16 @@ export default {
if (newVal === 'map' && newVal !== oldVal) {
this.initAreas()
}
},
// 监控缩放比例
previewCanvasScale: {
handler(newVal, oldVal) {
console.log('previewCanvasScale:' + JSON.stringify(this.previewCanvasScale))
this.destroyScaleTimeMachine()
this.changeScaleIndex++
this.chartScale(this.changeScaleIndex)
},
deep: true
}
},
created() {
......@@ -278,6 +305,24 @@ export default {
}
},
methods: {
// 根据仪表板的缩放比例,修改视图内部参数
mergeScale() {
const scale = Math.min(this.previewCanvasScale.scalePointWidth, this.previewCanvasScale.scalePointHeight) * this.scaleCoefficient
const customAttrChart = JSON.parse(this.sourceCustomAttrStr)
const customStyleChart = JSON.parse(this.sourceCustomStyleStr)
recursionTransObj(customAttrTrans, customAttrChart, scale)
recursionTransObj(customStyleTrans, customStyleChart, scale)
this.chart = {
...this.chart,
customAttr: JSON.stringify(customAttrChart),
customStyle: JSON.stringify(customStyleChart)
}
// console.log('customAttrChartSource:' + JSON.stringify(JSON.parse(this.sourceCustomAttrStr)))
// console.log('customAttrChart:' + JSON.stringify(customAttrChart))
// console.log('customStyleChartSource:' + JSON.stringify(JSON.parse(this.sourceCustomStyleStr)))
// console.log('customStyleChart:' + JSON.stringify(customStyleChart))
this.mergeStyle()
},
mergeStyle() {
if ((this.requestStatus === 'success' || this.requestStatus === 'merging') && this.chart.stylePriority === 'panel' && this.canvasStyleData.chart) {
const customAttrChart = JSON.parse(this.chart.customAttr)
......@@ -319,6 +364,8 @@ export default {
// 将视图传入echart组件
if (response.success) {
this.chart = response.data
this.sourceCustomAttrStr = this.chart.customAttr
this.sourceCustomStyleStr = this.chart.customStyle
this.chart.drillFields = this.chart.drillFields ? JSON.parse(this.chart.drillFields) : []
if (!response.data.drill) {
this.drillClickDimensionList.splice(this.drillClickDimensionList.length - 1, 1)
......@@ -327,7 +374,7 @@ export default {
this.drillFilters = JSON.parse(JSON.stringify(response.data.drillFilters ? response.data.drillFilters : []))
this.drillFields = JSON.parse(JSON.stringify(response.data.drillFields))
this.requestStatus = 'merging'
this.mergeStyle()
this.mergeScale()
this.requestStatus = 'success'
this.httpRequest.status = true
} else {
......@@ -534,6 +581,10 @@ export default {
this.timeMachine && clearTimeout(this.timeMachine)
this.timeMachine = null
},
destroyScaleTimeMachine() {
this.scaleTimeMachine && clearTimeout(this.scaleTimeMachine)
this.scaleTimeMachine = null
},
// 边框变化
chartResize(index) {
......@@ -547,6 +598,18 @@ export default {
}
},
// 边框变化 修改视图内部参数
chartScale(index) {
if (this.$refs[this.element.propValue.id]) {
this.scaleTimeMachine = setTimeout(() => {
if (index === this.changeScaleIndex) {
this.mergeScale()
}
this.destroyScaleTimeMachine()
}, 100)
}
},
renderComponent() {
return this.chart.render
}
......
<template>
<de-container>
<de-main-container v-if="!chart.type.includes('table')" :style="customStyle" class="full-div">
<chart-component v-if="!chart.type.includes('text') && renderComponent() === 'echarts'" class="chart-class" :chart="chart" />
<chart-component-g2 v-if="!chart.type.includes('text') && renderComponent() === 'antv'" class="chart-class" :chart="chart" />
<label-normal v-if="chart.type.includes('text')" :chart="chart" class="table-class" />
</de-main-container>
<de-main-container v-else>
<table-normal :chart="chartTable" :show-summary="false" class="table-class" />
</de-main-container>
</de-container>
</template>
<script>
import ChartComponent from '@/views/chart/components/ChartComponent.vue'
import TableNormal from '@/views/chart/components/table/TableNormal'
import LabelNormal from '@/views/chart/components/normal/LabelNormal'
import { mapState } from 'vuex'
import ChartComponentG2 from '@/views/chart/components/ChartComponentG2'
import DeMainContainer from '@/components/dataease/DeMainContainer'
import DeContainer from '@/components/dataease/DeContainer'
export default {
name: 'UserViewMobileDialog',
components: { DeContainer, DeMainContainer, ChartComponentG2, ChartComponent, TableNormal, LabelNormal },
props: {
chart: {
type: Object,
default: null
},
chartTable: {
type: Object,
default: null
}
},
data() {
return {
refId: null
}
},
computed: {
customStyle() {
let style = {
}
if (this.canvasStyleData.openCommonStyle) {
if (this.canvasStyleData.panel.backgroundType === 'image' && this.canvasStyleData.panel.imageUrl) {
style = {
background: `url(${this.canvasStyleData.panel.imageUrl}) no-repeat`,
...style
}
} else if (this.canvasStyleData.panel.backgroundType === 'color') {
style = {
background: this.canvasStyleData.panel.color,
...style
}
}
}
if (!style.background) {
style.background = '#FFFFFF'
}
return style
},
...mapState([
'isClickComponent',
'curComponent',
'componentData',
'canvasStyleData'
])
},
methods: {
renderComponent() {
return this.chart.render
}
}
}
</script>
<style lang="scss" scoped>
.ms-main-container {
border: 0px;
}
.chart-class{
height: 100%;
}
.table-class{
height: 100%;
}
</style>
......@@ -85,7 +85,7 @@ export const assistList = [
component: 'rect-shape',
type: 'rect-shape',
label: '矩形',
icon: 'iconfont icon-juxing',
icon: 'iconfont icon-juxing1',
defaultClass: 'text-filter'
},
{
......
......@@ -75,7 +75,7 @@ export function colorRgb(color, opacity) {
sColor = sColorNew
}
// 处理六位的颜色值
var sColorChange = []
const sColorChange = []
for (let i = 1; i < 7; i += 2) {
sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
}
......@@ -88,3 +88,100 @@ export function colorRgb(color, opacity) {
return sColor
}
}
export const customAttrTrans = {
'size': [
'barWidth',
'lineWidth',
'lineSymbolSize',
'pieInnerRadius',
'pieOuterRadius',
'funnelWidth', // 漏斗图 最大宽度
'tableTitleFontSize',
'tableItemFontSize',
'tableTitleHeight',
'tableItemHeight',
'dimensionFontSize',
'quotaFontSize',
'spaceSplit', // 间隔
'scatterSymbolSize', // 气泡大小,散点图
'treemapWidth', // 矩形树图
'treemapHeight',
'radarSize'// 雷达占比
],
'label': [
'fontSize'
],
'tooltip': {
'textStyle': ['fontSize']
}
}
export const customStyleTrans = {
'text': ['fontSize'],
'legend': {
'textStyle': ['fontSize']
},
'xAxis': {
'nameTextStyle': ['fontSize'],
'axisLabel': ['fontSize'],
'splitLine': {
'lineStyle': ['width']
}
},
'yAxis': {
'nameTextStyle': ['fontSize'],
'axisLabel': ['fontSize'],
'splitLine': {
'lineStyle': ['width']
}
},
'split': {
'name': ['fontSize'],
'axisLine': {
'lineStyle': ['width']
},
'axisTick': {
'lineStyle': ['width']
},
'axisLabel': ['margin', 'fontSize'],
'splitLine': {
'lineStyle': ['width']
}
}
}
export function getScaleValue(propValue, scale) {
const propValueTemp = Math.round(propValue * scale)
return propValueTemp > 1 ? propValueTemp : 1
}
export function recursionTransObj(template, infoObj, scale) {
// console.log('recursionObj++')
for (const templateKey in template) {
// 如果是数组 进行赋值计算
if (template[templateKey] instanceof Array) {
template[templateKey].forEach(templateProp => {
if (infoObj[templateKey] && infoObj[templateKey][templateProp]) {
const afterValue = getScaleValue(infoObj[templateKey][templateProp], scale)
console.log(templateKey + '.' + templateProp + '=' + infoObj[templateKey][templateProp] + ';scale:' + scale + ',after:' + afterValue)
infoObj[templateKey][templateProp] = afterValue
}
})
} else {
// 如果是对象 继续进行递归
if (infoObj[templateKey]) {
recursionTransObj(template[templateKey], infoObj[templateKey], scale)
}
}
}
}
export function componentScalePublic(chartInfo, heightScale, widthScale) {
const scale = Math.min(heightScale, widthScale)
// attr 缩放转换
recursionTransObj(this.customAttrTrans, chartInfo.customAttr, scale)
// style 缩放转换
recursionTransObj(this.customStyleTrans, chartInfo.customStyle, scale)
return chartInfo
}
......@@ -51,7 +51,7 @@ export function mobile2MainCanvas(mainSource, mobileSource) {
top: mobileSource.style.top
}
mainSource.mobileStyle.x = mobileSource.x
mainSource.mobileStyle.y = mobileSource.x
mainSource.mobileStyle.y = mobileSource.y
mainSource.mobileStyle.sizex = mobileSource.sizex
mainSource.mobileStyle.sizey = mobileSource.sizey
}
......@@ -23,6 +23,7 @@
:element="element"
:in-draw="inDraw"
:in-screen="inScreen"
:size="sizeInfo"
/>
</div>
</div>
......@@ -39,7 +40,7 @@ export default {
props: {
element: {
type: Object,
default: null
default: () => {}
},
inDraw: {
type: Boolean,
......@@ -49,16 +50,37 @@ export default {
type: Boolean,
required: false,
default: true
},
h: {
type: Number,
default: 50
}
},
data() {
return {
inputMaxSize: 46,
inputLargeSize: 42,
inputSmallSize: 38,
inputMiniSize: 34,
options: null,
showNumber: false,
mainClass: ''
}
},
computed: {
sizeInfo() {
let size
if (this.h > this.inputMaxSize) {
} else if (this.h > this.inputLargeSize) {
size = 'medium'
} else if (this.h > this.inputSmallSize) {
size = 'small'
} else {
size = 'mini'
}
return size
}
},
mounted() {
this.watchSize()
},
......
......@@ -4,6 +4,7 @@
v-if="options!== null && options.attrs!==null"
:type="options.attrs.type"
:round="options.attrs.round"
:size="size"
>
{{ options.value }}
</el-button>
......@@ -20,7 +21,8 @@ export default {
inDraw: {
type: Boolean,
default: true
}
},
size: String
},
data() {
return {
......
<template>
<el-date-picker
v-if="options!== null && options.attrs!==null"
v-if="element.options!== null && element.options.attrs!==null"
ref="dateRef"
v-model="values"
:type="options.attrs.type"
:range-separator="$t(options.attrs.rangeSeparator)"
:start-placeholder="$t(options.attrs.startPlaceholder)"
:end-placeholder="$t(options.attrs.endPlaceholder)"
:placeholder="$t(options.attrs.placeholder)"
:type="element.options.attrs.type"
:range-separator="$t(element.options.attrs.rangeSeparator)"
:start-placeholder="$t(element.options.attrs.startPlaceholder)"
:end-placeholder="$t(element.options.attrs.endPlaceholder)"
:placeholder="$t(element.options.attrs.placeholder)"
:append-to-body="inScreen"
style="min-height: 36px;"
value-format="timestamp"
:size="size"
:editable="false"
@change="dateChange"
/>
</template>
<script>
import { ApplicationContext } from '@/utils/ApplicationContext'
import { timeSection } from '@/utils'
export default {
......@@ -32,24 +34,62 @@ export default {
type: Boolean,
required: false,
default: true
}
},
size: String
},
data() {
return {
options: null,
operator: 'between',
values: null
}
},
computed: {
defaultoptions() {
if (!this.element || !this.element.options || !this.element.options.attrs.default) return ''
return JSON.stringify(this.element.options.attrs.default)
},
defaultValueStr() {
if (!this.element || !this.element.options || !this.element.options.value) return ''
return this.element.options.value.toString()
}
},
watch: {
'defaultValueStr': function(value, old) {
if (this.element.serviceName === 'timeDateWidget' && this.element.options.attrs.default.isDynamic) {
// 如果设置了动态时间 不做任何操作
return
}
if (value === old) return
this.values = this.fillValueDerfault()
this.dateChange(value)
},
'defaultoptions': function(val, old) {
// console.log('default chaneg')
if (this.element.serviceName !== 'timeDateWidget') {
if (!this.element.options.attrs.default.isDynamic) {
this.values = this.fillValueDerfault()
this.dateChange(this.values)
return
}
}
if (val === old) return
const widget = ApplicationContext.getService(this.element.serviceName)
this.values = widget.dynamicDateFormNow(this.element)
this.dateChange(this.values)
}
},
created() {
this.options = this.element.options
if (this.options.value) {
if (this.options.attrs.type !== 'daterange') {
this.values = Array.isArray(this.options.value) ? this.options.value[0] : this.options.value
} else {
this.values = this.options.value
if (this.element.serviceName === 'timeDateWidget' && this.element.options.attrs.default.isDynamic) {
if (this.element.options.attrs.default) {
const widget = ApplicationContext.getService(this.element.serviceName)
this.values = widget.dynamicDateFormNow(this.element)
this.dateChange(this.values)
}
return
}
if (this.element.options.value) {
this.values = this.fillValueDerfault()
this.dateChange(this.values)
}
},
methods: {
......@@ -57,32 +97,35 @@ export default {
this.setCondition()
},
setCondition() {
if (this.values) {
if (this.options.attrs.type !== 'daterange') {
this.options.value = Array.isArray(this.values) ? this.values[0] : this.values
} else {
this.options.value = this.values
}
} else {
this.options.value = []
}
const param = {
component: this.element,
value: Array.isArray(this.options.value) ? this.options.value : [this.options.value],
value: this.formatFilterValue(),
operator: this.operator
}
param.value = this.formatValues(param.value)
this.inDraw && this.$store.commit('addViewFilter', param)
},
dateChange(value) {
if (!this.inDraw) {
if (value === null) {
this.element.options.value = ''
} else {
this.element.options.value = Array.isArray(value) ? value.join() : value.toString()
}
}
this.setCondition()
this.styleChange()
},
formatFilterValue() {
if (this.values === null) return []
if (Array.isArray(this.values)) return this.values
return [this.values]
},
formatValues(values) {
if (!values || values.length === 0) {
return []
}
if (this.options.attrs.type === 'daterange') {
if (this.element.options.attrs.type === 'daterange') {
if (values.length !== 2) {
return null
}
......@@ -94,11 +137,21 @@ export default {
return results
} else {
const value = values[0]
return timeSection(value, this.options.attrs.type)
return timeSection(parseFloat(value), this.element.options.attrs.type)
}
},
styleChange() {
this.$store.commit('recordStyleChange')
},
fillValueDerfault() {
const defaultV = this.element.options.value === null ? '' : this.element.options.value.toString()
if (this.element.options.attrs.type === 'daterange') {
if (defaultV === null || typeof defaultV === 'undefined' || defaultV === '') return []
return defaultV.split(',').map(item => parseFloat(item))
} else {
if (defaultV === null || typeof defaultV === 'undefined' || defaultV === '') return null
return parseFloat(defaultV.split(',')[0])
}
}
}
}
......
<template>
<el-input
v-if="options!== null && options.attrs!==null"
v-if="element.options!== null && element.options.attrs!==null"
v-model="value"
resize="vertical"
:placeholder="$t(options.attrs.placeholder)"
:placeholder="$t(element.options.attrs.placeholder)"
@input="valueChange"
@keypress.enter.native="search"
@dblclick="setEdit"
:size="size"
>
<el-button slot="append" icon="el-icon-search" @click="search" />
......@@ -25,42 +27,51 @@ export default {
inDraw: {
type: Boolean,
default: true
}
},
size: String
},
data() {
return {
options: null,
operator: 'like',
value: null,
canEdit: false
}
},
watch: {
'element.options.value': function(value, old) {
if (value === old) return
this.value = value
this.search()
}
},
created() {
this.options = this.element.options
if (this.inDraw && this.options.value && this.options.value.length > 0) {
this.value = this.options.value[0]
if (this.element.options.value) {
this.value = this.element.options.value
this.search()
}
},
methods: {
search() {
// this.options.value && this.setCondition()
this.options.value = []
if (this.inDraw && this.value) {
this.options.value = [this.value]
if (!this.inDraw) {
this.element.options.value = this.value
}
this.setCondition()
},
setCondition() {
const param = {
component: this.element,
value: !this.options.value ? [] : Array.isArray(this.options.value) ? this.options.value : [this.options.value],
value: !this.value ? [] : [this.value],
operator: this.operator
}
this.inDraw && this.$store.commit('addViewFilter', param)
},
setEdit() {
this.canEdit = true
},
valueChange(val) {
if (!this.inDraw) {
this.element.options.value = val
}
}
}
}
......
<template>
<el-form v-if="options!== null && options.attrs!==null" ref="form" :model="form" :rules="rules">
<el-form v-if="element.options!== null && element.options.attrs!==null" ref="form" :model="form" :rules="rules">
<div class="de-number-range-container">
<el-form-item prop="min">
<el-input v-model="form.min" :placeholder="$t(options.attrs.placeholder_min)" @change="handleMinChange" />
<el-input v-model="form.min" :placeholder="$t(element.options.attrs.placeholder_min)" @input="inputChange" @change="handleMinChange" :size="size"/>
</el-form-item>
<span>{{ $t('denumberrange.split_placeholder') }}</span>
<el-form-item prop="max">
<el-input v-model="form.max" :placeholder="$t(options.attrs.placeholder_max)" @change="handleMaxChange" />
<el-input v-model="form.max" :placeholder="$t(element.options.attrs.placeholder_max)" @input="inputChange" @change="handleMaxChange" :size="size"/>
</el-form-item>
</div>
</el-form>
......@@ -27,12 +27,12 @@ export default {
inDraw: {
type: Boolean,
default: true
}
},
size: String
},
data() {
return {
options: null,
operator: 'between',
values: null,
canEdit: false,
......@@ -54,7 +54,24 @@ export default {
timeMachine: null
}
},
computed: {
defaultvalues() {
if (!this.element.options.value) {
return JSON.stringify([])
}
return JSON.stringify(this.element.options.value)
}
},
watch: {
'defaultvalues': function(value, old) {
if (value === old) return
const values = this.element.options.value
this.form.min = values[0]
if (values.length > 1) {
this.form.max = values[1]
}
this.search()
},
form: {
handler(value) {
this.destryTimeMachine()
......@@ -65,12 +82,13 @@ export default {
}
},
created() {
this.options = this.element.options
if (this.inDraw && this.options.value && this.options.value.length > 0) {
this.form.min = this.options.value[0]
if (this.options.value.length > 1) {
this.form.max = this.options.value[1]
if (this.element.options.value && this.element.options.value.length > 0) {
const values = this.element.options.value
this.form.min = values[0]
if (values.length > 1) {
this.form.max = values[1]
}
this.search()
}
},
methods: {
......@@ -136,13 +154,15 @@ export default {
},
search() {
this.$refs.form.validate(valid => {
if (!valid) {
return false
}
this.$nextTick(() => {
this.$refs.form.validate(valid => {
if (!valid) {
return false
}
this.setCondition()
this.$store.commit('recordStyleChange')
this.setCondition()
this.$store.commit('recordStyleChange')
})
})
},
setCondition() {
......@@ -153,7 +173,6 @@ export default {
operator: this.operator
}
this.inDraw && (this.options.value = param.value)
if (this.form.min && this.form.max) {
this.inDraw && this.$store.commit('addViewFilter', param)
return
......@@ -178,6 +197,13 @@ export default {
},
styleChange() {
this.$store.commit('recordStyleChange')
},
inputChange(val) {
if (!this.inDraw) {
const values = [this.form.min, this.form.max]
this.element.options.value = values
}
}
}
}
......@@ -186,6 +212,7 @@ export default {
<style lang="scss" scoped>
.de-number-range-container {
display: inline;
max-height: 40px;
>>>div.el-form-item {
width: calc(50% - 10px) !important;
display: inline-block;
......
......@@ -2,8 +2,9 @@
<el-quarter
v-if="options!== null && options.attrs!==null"
v-model="options.value"
:placeholder="options.attrs.placeholder"
:size="size"
:editable="false"
/>
</template>
......@@ -18,7 +19,8 @@ export default {
inDraw: {
type: Boolean,
default: true
}
},
size: String
},
data() {
return {
......
<template>
<el-select
v-if="options!== null && options.attrs!==null"
v-if="element.options!== null && element.options.attrs!==null && show"
ref="deSelect"
v-model="options.value"
v-model="value"
:collapse-tags="showNumber"
:clearable="!options.attrs.multiple"
:multiple="options.attrs.multiple"
:placeholder="$t(options.attrs.placeholder)"
:clearable="!element.options.attrs.multiple"
:multiple="element.options.attrs.multiple"
:placeholder="$t(element.options.attrs.placeholder)"
:popper-append-to-body="inScreen"
:size="size"
@change="changeValue"
@focus="setOptionWidth"
>
<el-option
v-for="item in options.attrs.datas"
:key="item[options.attrs.key]"
v-for="item in datas"
:key="item[element.options.attrs.key]"
:style="{width:selectOptionWidth}"
:label="item[options.attrs.label]"
:value="item[options.attrs.value]"
:label="item[element.options.attrs.label]"
:value="item[element.options.attrs.value]"
>
<span :title="item[options.attrs.label]" style="display:inline-block;width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;">{{ item[options.attrs.label] }}</span>
<span :title="item[element.options.attrs.label]" style="display:inline-block;width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;">{{ item[element.options.attrs.label] }}</span>
</el-option>
</el-select>
</template>
<script>
import { fieldValues } from '@/api/dataset/dataset'
import { multFieldValues } from '@/api/dataset/dataset'
export default {
props: {
element: {
type: Object,
default: null
default: () => {}
},
inDraw: {
type: Boolean,
......@@ -42,58 +43,89 @@ export default {
type: Boolean,
required: false,
default: true
}
},
size: String
},
data() {
return {
options: null,
showNumber: false,
selectOptionWidth: 0
selectOptionWidth: 0,
show: true,
value: null,
datas: []
}
},
computed: {
operator() {
return this.options.attrs.multiple ? 'in' : 'eq'
return this.element.options.attrs.multiple ? 'in' : 'eq'
},
defaultValueStr() {
if (!this.element || !this.element.options || !this.element.options.value) return ''
return this.element.options.value.toString()
}
},
watch: {
'options.attrs.multiple': function(value) {
const sourceValue = this.options.value
const sourceValid = !!sourceValue && Object.keys(sourceValue).length > 0
if (value) {
!sourceValid && (this.options.value = [])
sourceValid && !Array.isArray(sourceValue) && (this.options.value = sourceValue.split(','))
!this.inDraw && (this.options.value = [])
} else {
!sourceValid && (this.options.value = null)
sourceValid && Array.isArray(sourceValue) && (this.options.value = sourceValue[0])
!this.inDraw && (this.options.value = null)
'defaultValueStr': function(value, old) {
if (value === old) return
this.value = this.fillValueDerfault()
this.changeValue(value)
},
'element.options.attrs.fieldId': function(value, old) {
if (typeof value === 'undefined' || value === old) return
this.datas = []
this.element.options.attrs.fieldId &&
this.element.options.attrs.fieldId.length > 0 &&
multFieldValues(this.element.options.attrs.fieldId.split(',')).then(res => {
this.datas = this.optionDatas(res.data)
}) || (this.element.options.value = '')
},
'element.options.attrs.multiple': function(value, old) {
if (typeof old === 'undefined' || value === old) return
if (!this.inDraw) {
this.value = value ? [] : null
this.element.options.value = ''
}
}
},
created() {
this.options = this.element.options
if (this.options.attrs.fieldId) {
fieldValues(this.options.attrs.fieldId).then(res => {
this.options.attrs.datas = this.optionDatas(res.data)
this.show = false
this.$nextTick(() => {
this.show = true
})
}
// this.setCondition()
},
mounted() {
// this.$nextTick(() => {
// this.options && this.options.value && this.changeValue(this.options.value)
// })
this.options && this.options.value && Object.keys(this.options.value).length > 0 && this.changeValue(this.options.value)
created() {
this.initLoad()
},
methods: {
initLoad() {
this.value = this.fillValueDerfault()
this.datas = []
if (this.element.options.attrs.fieldId) {
multFieldValues(this.element.options.attrs.fieldId.split(',')).then(res => {
this.datas = this.optionDatas(res.data)
})
}
if (this.element.options.value) {
this.value = this.fillValueDerfault()
this.changeValue(this.value)
}
},
changeValue(value) {
if (!this.inDraw) {
if (value === null) {
this.element.options.value = ''
} else {
this.element.options.value = Array.isArray(value) ? value.join() : value
}
}
this.setCondition()
this.styleChange()
this.showNumber = false
this.$nextTick(() => {
if (!this.$refs.deSelect.$refs.tags || !this.options.attrs.multiple) {
if (!this.element.options.attrs.multiple || !this.$refs.deSelect || !this.$refs.deSelect.$refs.tags) {
return
}
const kids = this.$refs.deSelect.$refs.tags.children[0].children
......@@ -108,11 +140,26 @@ export default {
setCondition() {
const param = {
component: this.element,
value: Array.isArray(this.options.value) ? this.options.value : [this.options.value],
value: this.formatFilterValue(),
operator: this.operator
}
this.inDraw && this.$store.commit('addViewFilter', param)
},
formatFilterValue() {
if (this.value === null) return []
if (Array.isArray(this.value)) return this.value
return this.value.split(',')
},
fillValueDerfault() {
const defaultV = this.element.options.value === null ? '' : this.element.options.value.toString()
if (this.element.options.attrs.multiple) {
if (defaultV === null || typeof defaultV === 'undefined' || defaultV === '') return []
return defaultV.split(',')
} else {
if (defaultV === null || typeof defaultV === 'undefined' || defaultV === '') return null
return defaultV.split(',')[0]
}
},
styleChange() {
this.$store.commit('recordStyleChange')
},
......
<template>
<el-select v-if="options!== null && options.attrs!==null" v-model="values" :multiple="options.attrs.multiple" :placeholder="options.attrs.placeholder" :popper-append-to-body="inScreen" @change="changeValue">
<el-select :size="size" v-if="options!== null && options.attrs!==null" v-model="values" :multiple="options.attrs.multiple" :placeholder="options.attrs.placeholder" :popper-append-to-body="inScreen" @change="changeValue">
<el-option
v-for="item in options.attrs.datas"
:key="item[options.attrs.key]"
......@@ -28,7 +28,8 @@ export default {
type: Boolean,
required: false,
default: true
}
},
size: String
},
data() {
return {
......
......@@ -11,7 +11,9 @@ const dialogPanel = {
attrs: {
placeholder_min: 'denumberrange.please_key_min',
placeholder_max: 'denumberrange.please_key_max',
viewIds: []
viewIds: [],
fieldId: '',
dragItems: []
},
value: ''
},
......
......@@ -16,7 +16,9 @@ const dialogPanel = {
datas: [],
key: 'id',
label: 'text',
value: 'id'
value: 'id',
fieldId: '',
dragItems: []
},
value: ''
},
......
......@@ -13,9 +13,12 @@ const dialogPanel = {
multiple: false,
placeholder: 'denumberselect.placeholder',
datas: [],
viewIds: [],
key: 'id',
label: 'text',
value: 'id'
value: 'id',
fieldId: '',
dragItems: []
},
value: ''
},
......
......@@ -10,7 +10,9 @@ const dialogPanel = {
options: {
attrs: {
placeholder: 'deinputsearch.placeholder',
viewIds: []
viewIds: [],
fieldId: '',
dragItems: []
},
value: ''
......
......@@ -16,7 +16,9 @@ const dialogPanel = {
datas: [],
key: 'id',
label: 'text',
value: 'id'
value: 'id',
fieldId: '',
dragItems: []
},
value: ''
},
......
......@@ -16,7 +16,9 @@ const dialogPanel = {
datas: [],
key: 'id',
label: 'text',
value: 'id'
value: 'id',
fieldId: '',
dragItems: []
},
value: ''
},
......
......@@ -13,7 +13,9 @@ const dialogPanel = {
rangeSeparator: 'dedaterange.split_placeholder',
startPlaceholder: 'dedaterange.from_placeholder',
endPlaceholder: 'dedaterange.to_placeholder',
viewIds: []
viewIds: [],
fieldId: '',
dragItems: []
},
value: ''
},
......
......@@ -11,7 +11,16 @@ const dialogPanel = {
attrs: {
type: 'date',
placeholder: 'dedate.placeholder',
viewIds: []
viewIds: [],
fieldId: '',
dragItems: [],
default: {
isDynamic: false,
dkey: 0,
dynamicPrefix: 1,
dynamicInfill: 'day',
dynamicSuffix: 'before'
}
},
value: ''
},
......@@ -62,6 +71,69 @@ class TimeDateServiceImpl extends WidgetService {
return field['deType'] === 1
})
}
dynamicDateFormNow(element) {
if (element.options.attrs.default === null || typeof element.options.attrs.default === 'undefined' || !element.options.attrs.default.isDynamic) return null
if (element.options.attrs.default.dkey === 0) {
return Date.now()
}
if (element.options.attrs.default.dkey === 1) {
const oneday = 24 * 3600 * 1000
return Date.now() - oneday
}
if (element.options.attrs.default.dkey === 2) {
const now = new Date()
const nowMonth = now.getMonth()
var nowYear = now.getFullYear()
return new Date(nowYear, nowMonth, 1).getTime()
}
if (element.options.attrs.default.dkey === 3) {
const dynamicPrefix = element.options.attrs.default.dynamicPrefix
const dynamicInfill = element.options.attrs.default.dynamicInfill
const dynamicSuffix = element.options.attrs.default.dynamicSuffix
if (dynamicInfill === 'day') {
const oneday = 24 * 3600 * 1000
const step = oneday * dynamicPrefix
return dynamicSuffix === 'before' ? (Date.now() - step) : (Date.now() + step)
}
if (dynamicInfill === 'week') {
const oneday = 24 * 3600 * 1000
const step = oneday * dynamicPrefix * 7
return dynamicSuffix === 'before' ? (Date.now() - step) : (Date.now() + step)
}
if (dynamicInfill === 'month') {
const now = new Date()
const nowMonth = now.getMonth()
const nowYear = now.getFullYear()
const nowDate = now.getDate()
const tarYear = nowYear
if (dynamicSuffix === 'before') {
const deffMonth = nowMonth - dynamicPrefix
let diffYear = deffMonth / 12
if (deffMonth < 0) {
diffYear -= 1
}
return new Date(tarYear + diffYear, nowMonth - dynamicPrefix % 12, nowDate).getTime()
} else {
const deffMonth = nowMonth + dynamicPrefix
const diffYear = deffMonth / 12
return new Date(tarYear + diffYear, deffMonth % 12, nowDate).getTime()
}
}
if (dynamicInfill === 'year') {
const now = new Date()
const nowMonth = now.getMonth()
const nowYear = now.getFullYear()
const nowDate = now.getDate()
return new Date(nowYear - 1, nowMonth, nowDate).getTime()
}
}
}
}
const timeDateServiceImpl = new TimeDateServiceImpl({ name: 'timeDateWidget' })
export default timeDateServiceImpl
......@@ -11,7 +11,9 @@ const dialogPanel = {
attrs: {
type: 'month',
placeholder: 'deyearmonth.placeholder',
viewIds: []
viewIds: [],
fieldId: '',
dragItems: []
},
value: ''
},
......
......@@ -11,7 +11,9 @@ const dialogPanel = {
attrs: {
type: 'year',
placeholder: 'deyear.placeholder',
viewIds: []
viewIds: [],
fieldId: '',
dragItems: []
},
value: ''
},
......
......@@ -994,7 +994,11 @@ export default {
data_percent: 'Percent',
compare_calc_expression: 'Expression',
and: 'And',
or: 'Or'
or: 'Or',
logic_exp: 'Logic',
enum_exp: 'Enum',
pls_slc: 'Please Select',
filter_exp: 'Filter Value'
},
dataset: {
sheet_warn: 'There are multiple sheet pages, and the first one is extracted by default',
......
......@@ -994,7 +994,11 @@ export default {
data_percent: '差值百分比',
compare_calc_expression: '計算公式',
and: '與',
or: '或'
or: '或',
logic_exp: '邏輯條件',
enum_exp: '枚舉條件',
pls_slc: '請選擇',
filter_exp: '過濾條件'
},
dataset: {
sheet_warn: '有多個 Sheet 頁,默認抽取第一個',
......
......@@ -997,7 +997,11 @@ export default {
data_percent: '差值百分比',
compare_calc_expression: '计算公式',
and: '与',
or: '或'
or: '或',
logic_exp: '逻辑条件',
enum_exp: '枚举条件',
pls_slc: '请选择',
filter_exp: '过滤条件'
},
dataset: {
sheet_warn: '有多个 Sheet 页,默认抽取第一个',
......
......@@ -57,6 +57,11 @@ const data = {
curComponent: null,
curCanvasScale: null,
curComponentIndex: null,
// 预览仪表板缩放信息
previewCanvasScale: {
scalePointWidth: 1,
scalePointHeight: 1
},
// 点击画布时是否点中组件,主要用于取消选中组件用。
// 如果没点中组件,并且在画布空白处弹起鼠标,则取消当前组件的选中状态
isClickComponent: false,
......@@ -135,7 +140,14 @@ const data = {
setCurCanvasScale(state, curCanvasScale) {
state.curCanvasScale = curCanvasScale
},
setPreviewCanvasScale(state, scaleWidth, scaleHeight) {
if (scaleWidth) {
state.previewCanvasScale.scalePointWidth = scaleWidth
}
if (scaleHeight) {
state.previewCanvasScale.scalePointHeight = scaleHeight
}
},
setShapeStyle({ curComponent, canvasStyleData, curCanvasScale }, { top, left, width, height, rotate }) {
if (top || top === 0) curComponent.style.top = (top / curCanvasScale.scalePointHeight) + 0.0000001
if (left || left === 0) curComponent.style.left = (left / curCanvasScale.scalePointWidth) + 0.0000001
......
@font-face {
font-family: "iconfont"; /* Project id 2459092 */
src: url('iconfont.woff2?t=1636516993563') format('woff2'),
url('iconfont.woff?t=1636516993563') format('woff'),
url('iconfont.ttf?t=1636516993563') format('truetype');
src: url('iconfont.woff2?t=1639622225820') format('woff2'),
url('iconfont.woff?t=1639622225820') format('woff'),
url('iconfont.ttf?t=1639622225820') format('truetype');
}
.iconfont {
......@@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-guanbi:before {
content: "\e60d";
}
.icon-juxing1:before {
content: "\e67e";
}
.icon-yidongduan:before {
content: "\e653";
}
......@@ -37,10 +45,6 @@
content: "\e91b";
}
.icon-tabs:before {
content: "\e9a8";
}
.icon-shijian:before {
content: "\e665";
}
......@@ -81,6 +85,10 @@
content: "\e8e6";
}
.icon-tabs:before {
content: "\e62a";
}
.icon-xiyu:before {
content: "\e619";
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -5,6 +5,20 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "1367318",
"name": "关闭",
"font_class": "guanbi",
"unicode": "e60d",
"unicode_decimal": 58893
},
{
"icon_id": "23446403",
"name": "矩形",
"font_class": "juxing1",
"unicode": "e67e",
"unicode_decimal": 59006
},
{
"icon_id": "11799014",
"name": "移动端",
......@@ -47,13 +61,6 @@
"unicode": "e91b",
"unicode_decimal": 59675
},
{
"icon_id": "11982148",
"name": "tabs",
"font_class": "tabs",
"unicode": "e9a8",
"unicode_decimal": 59816
},
{
"icon_id": "658039",
"name": "时间",
......@@ -124,6 +131,13 @@
"unicode": "e8e6",
"unicode_decimal": 59622
},
{
"icon_id": "15196968",
"name": "44.tabs",
"font_class": "tabs",
"unicode": "e62a",
"unicode_decimal": 58922
},
{
"icon_id": "23570269",
"name": "洗浴",
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论