Merge branch 'dev' of github.com:dataease/dataease into dev

This commit is contained in:
taojinlong 2022-05-24 23:05:35 +08:00
commit a346a7718d
27 changed files with 913 additions and 73 deletions

View File

@ -97,6 +97,13 @@ public class PanelGroupController {
return panelGroupService.queryPanelViewTree();
}
@ApiOperation("仪表板视图复用信息")
@PostMapping("/queryPanelMultiplexingViewTree")
@I18n
public List<VAuthModelDTO> queryPanelMultiplexingViewTree() {
return panelGroupService.queryPanelMultiplexingViewTree();
}
@ApiOperation("仪表板组件信息")
@GetMapping("/queryPanelComponents/{id}")
@I18n

View File

@ -293,6 +293,7 @@ public class PanelGroupService {
List<String> panelIds = panelResult.stream().map(VAuthModelDTO::getId).collect(Collectors.toList());
VAuthModelRequest viewRequest = new VAuthModelRequest();
viewRequest.setPids(panelIds);
// Version 1.11 only gets the current panel
List<VAuthModelDTO> viewResult = extVAuthModelMapper.queryAuthModelViews(viewRequest);
if (CollectionUtils.isNotEmpty(viewResult)) {
result.addAll(viewResult);
@ -310,6 +311,36 @@ public class PanelGroupService {
return result;
}
public List<VAuthModelDTO> queryPanelMultiplexingViewTree() {
List<VAuthModelDTO> result = new ArrayList<>();
VAuthModelRequest panelRequest = new VAuthModelRequest();
panelRequest.setUserId(String.valueOf(AuthUtils.getUser().getUserId()));
panelRequest.setModelType("panel");
List<VAuthModelDTO> panelResult = extVAuthModelMapper.queryAuthModel(panelRequest);
// 获取仪表板下面的视图
if (CollectionUtils.isNotEmpty(panelResult)) {
result.addAll(panelResult);
List<String> panelIds = panelResult.stream().map(VAuthModelDTO::getId).collect(Collectors.toList());
VAuthModelRequest viewRequest = new VAuthModelRequest();
viewRequest.setPids(panelIds);
// Version 1.11 only gets the current panel
// List<VAuthModelDTO> viewResult = extVAuthModelMapper.queryAuthModelViews(viewRequest);
// if (CollectionUtils.isNotEmpty(viewResult)) {
// result.addAll(viewResult);
// }
result = TreeUtils.mergeTree(result, "panel_list");
// if (AuthUtils.getUser().getIsAdmin()) {
// // 原有视图的目录结构
// List<VAuthModelDTO> viewOriginal = extVAuthModelMapper.queryAuthViewsOriginal(viewRequest);
// if (CollectionUtils.isNotEmpty(viewOriginal) && viewOriginal.size() > 1) {
// result.addAll(TreeUtils.mergeTree(viewOriginal, "public_chart"));
// }
// }
}
return result;
}
public String panelGroupCopy(PanelGroupRequest request, String newPanelId, boolean checkName) {
String sourcePanelId = request.getId(); //源仪表板ID
if (StringUtils.isEmpty(newPanelId)) {
@ -559,9 +590,9 @@ public class PanelGroupService {
}
}
public void updatePanelStatus(String panelId,PanelGroupBaseInfoRequest request){
Assert.notNull(request.getStatus(),"status can not be null");
Assert.notNull(panelId,"panelId can not be null");
public void updatePanelStatus(String panelId, PanelGroupBaseInfoRequest request) {
Assert.notNull(request.getStatus(), "status can not be null");
Assert.notNull(panelId, "panelId can not be null");
PanelGroupWithBLOBs panelGroup = new PanelGroupWithBLOBs();
panelGroup.setId(panelId);
panelGroup.setStatus(request.getStatus());

View File

@ -165,6 +165,14 @@ export function queryPanelViewTree() {
})
}
export function queryPanelMultiplexingViewTree() {
return request({
url: '/panel/group/queryPanelMultiplexingViewTree',
method: 'post',
loading: false
})
}
export function initPanelComponentsData(panelId, callback) {
// 加载仪表板组件视图数据
queryPanelComponents(panelId).then(rep => {

View File

@ -39,8 +39,8 @@ export default {
z-index: 10;
height: 20px;
border-radius:2px;
padding-left: 5px;
padding-right: 2px;
padding-left: 3px;
padding-right: 0px;
cursor:pointer!important;
opacity: 0.8;
/*background-color: #0a7be0;*/

View File

@ -45,8 +45,8 @@ export default {
float:right;
z-index: 2;
border-radius:2px;
padding-left: 5px;
padding-right: 2px;
padding-left: 3px;
padding-right: 0px;
cursor:pointer!important;
background-color: #0a7be0;
}

View File

@ -37,6 +37,8 @@
:filters="filters"
:terminal="terminal"
:screen-shot="screenShot"
:canvas-style-data="canvasStyleData"
:show-position="showPosition"
/>
</div>
</div>
@ -88,6 +90,18 @@ export default {
screenShot: {
type: Boolean,
default: false
},
canvasStyleData: {
type: Object,
required: false,
default: function() {
return {}
}
},
showPosition: {
type: String,
required: false,
default: 'NotProvided'
}
},
data() {
@ -129,7 +143,6 @@ export default {
},
...mapState([
'mobileLayoutStatus',
'canvasStyleData',
'curComponent',
'componentGap'
])

View File

@ -286,8 +286,8 @@ export default {
float:right;
z-index: 2;
border-radius:2px;
padding-left: 5px;
padding-right: 2px;
padding-left: 3px;
padding-right: 0px;
cursor:pointer!important;
background-color: rgba(10,123,224, 1);
}

View File

@ -1,6 +1,6 @@
<template>
<div class="bar-main">
<div>
<div v-if="!positionCheck('multiplexing')">
<span v-if="isEdit" :title="$t('panel.edit')">
<i class="icon iconfont icon-edit" @click.stop="edit" />
</span>
@ -8,7 +8,9 @@
<i class="icon iconfont icon-fangda" @click.stop="showViewDetails" />
</span>
</div>
<div v-if="positionCheck('multiplexing')" style="margin-right: -1px;width: 18px;z-index: 5">
<el-checkbox size="medium" @change="multiplexingCheck" />
</div>
</div>
</template>
@ -17,14 +19,24 @@ import bus from '@/utils/bus'
import { mapState } from 'vuex'
export default {
props: {
element: {
type: Object,
default: null
},
viewId: {
type: String,
required: true
},
// Deprecated
isEdit: {
type: Boolean,
required: false,
default: true
},
showPosition: {
type: String,
required: false,
default: 'NotProvided'
}
},
data() {
@ -39,10 +51,19 @@ export default {
}
},
computed: {
// gapStyle() {
// return {
// 'right': this.curGap + 'px!important'
// }
// },
// curGap() {
// return (this.canvasStyleData.panel.gap === 'yes' && this.element.auxiliaryMatrix) ? this.componentGap : 0
// },
...mapState([
'linkageSettingStatus',
'componentData',
'canvasStyleData'
'canvasStyleData',
'componentGap'
])
},
mounted() {
@ -63,7 +84,20 @@ export default {
},
showViewDetails() {
this.$emit('showViewDetails')
},
positionCheck(position) {
return this.showPosition === position
},
multiplexingCheck(val) {
if (val) {
// push
this.$store.commit('addCurMultiplexingComponent', { 'component': this.element, 'componentId': this.viewId })
} else {
// remove
this.$store.commit('removeCurMultiplexingComponentWithId', this.viewId)
}
}
}
}
</script>
@ -74,9 +108,9 @@ export default {
right: 0px;
float:right;
z-index: 2;
border-radius:2px;
padding-left: 5px;
padding-right: 2px;
border-radius:2px!important;
padding-left: 3px!important;
padding-right: 0px!important;
cursor:pointer!important;
background-color: #0a7be0;
}

View File

@ -29,6 +29,8 @@
:terminal="terminal"
:filters="filterMap[item.propValue && item.propValue.viewId]"
:screen-shot="screenShot"
:canvas-style-data="canvasStyleData"
:show-position="showPosition"
/>
<!--视图详情-->
<el-dialog
@ -114,6 +116,25 @@ export default {
type: String,
required: false,
default: 'none'
},
componentData: {
type: Array,
required: false,
default: function() {
return []
}
},
canvasStyleData: {
type: Object,
required: false,
default: function() {
return {}
}
},
showPosition: {
type: String,
required: false,
default: 'NotProvided'
}
},
data() {
@ -224,11 +245,7 @@ export default {
return this.componentDataShow
},
...mapState([
'isClickComponent',
'curComponent',
'componentData',
'canvasStyleData',
'componentGap'
'isClickComponent'
]),
filterMap() {
const map = buildFilterMap(this.componentData)

View File

@ -1,6 +1,12 @@
<template>
<div v-loading="dataLoading" class="bg" :style="bgStyle">
<Preview v-if="!dataLoading" :back-screen-shot="backScreenShot" @mainHeightChange="mainHeightChange" />
<Preview
v-if="!dataLoading"
:component-data="componentData"
:canvas-style-data="canvasStyleData"
:back-screen-shot="backScreenShot"
@mainHeightChange="mainHeightChange"
/>
</div>
</template>
<script>
@ -10,6 +16,7 @@ import { initPanelData } from '@/api/panel/panel'
import { queryTargetPanelJumpInfo } from '@/api/panel/linkJump'
import { proxyInitPanelData } from '@/api/panel/shareProxy'
import { getOuterParamsInfo } from '@/api/panel/outerParams'
import { mapState } from 'vuex'
export default {
components: { Preview },
@ -28,7 +35,11 @@ export default {
} else {
return { height: '100vh!important' }
}
}
},
...mapState([
'canvasStyleData',
'componentData'
])
},
watch: {
'$route.params.reportId': function() {

View File

@ -1,7 +1,12 @@
<template>
<div style="width: 100%;height: 100vh;">
<fullscreen style="height:100%;background: #f7f8fa;overflow-y: auto" :fullscreen.sync="fullscreen" @change="fullscreenChange">
<Preview v-if="fullscreen" :in-screen="!fullscreen" />
<Preview
v-if="fullscreen"
:component-data="componentData"
:canvas-style-data="canvasStyleData"
:in-screen="!fullscreen"
/>
</fullscreen>
</div>
</template>
@ -10,9 +15,16 @@
import Preview from './Preview'
import bus from '@/utils/bus'
import { mapState } from 'vuex'
export default {
components: { Preview },
computed: {
...mapState([
'canvasStyleData',
'componentData'
])
},
data() {
return {
fullscreen: false

View File

@ -15,7 +15,6 @@
>
<!-- 网格线 -->
<Grid v-if="showGrid" :matrix-style="matrixStyle" />
<!-- positionBox:{{positionBoxInfo}}-->
<PGrid v-if="psDebug" :position-box="positionBoxInfoArray" :matrix-style="matrixStyle" />
<!-- 仪表板联动清除按钮-->
@ -99,6 +98,7 @@
:active="item === curComponent"
:edit-mode="'edit'"
:h="getShapeStyleIntDeDrag(item.style,'height')"
:canvas-style-data="canvasStyleData"
@input="handleInput"
/>
</de-drag>
@ -212,12 +212,6 @@ import { buildFilterMap } from '@/utils/conditionUtil'
import _ from 'lodash'
import $ from 'jquery'
import Background from '@/views/background/index'
import { ApplicationContext } from '@/utils/ApplicationContext'
import {
BASE_MOBILE_STYLE,
COMMON_BACKGROUND_NONE,
HYPERLINKS
} from '@/components/canvas/custom-component/component-list'
let positionBox = []
let coordinates = [] //
@ -1013,12 +1007,6 @@ export default {
}
},
watch: {
// 'canvasStyleData.aidedDesign.matrixBase': {
// handler(newVal, oldVal) {
// this.changeComponentSizePoint(newVal / oldVal)
// },
// deep: true
// },
customStyle: {
handler(newVal) {
//

View File

@ -8,7 +8,14 @@
'rect-shape'
]"
>
<EditBarView v-if="editBarViewShowFlag" :is-edit="isEdit" :view-id="element.propValue.viewId" @showViewDetails="openChartDetailsDialog" />
<EditBarView
v-if="editBarViewShowFlag"
:element="element"
:show-position="showPosition"
:is-edit="isEdit"
:view-id="element.propValue.viewId"
@showViewDetails="openChartDetailsDialog"
/>
<div v-if="requestStatus==='error'" class="chart-error-class">
<div class="chart-error-message-class">
{{ message }},{{ $t('chart.chart_show_error') }}
@ -163,6 +170,18 @@ export default {
filters: {
type: Array,
default: () => []
},
canvasStyleData: {
type: Object,
required: false,
default: function() {
return {}
}
},
showPosition: {
type: String,
required: false,
default: 'NotProvided'
}
},
data() {
@ -214,7 +233,7 @@ export default {
}
},
editBarViewShowFlag() {
return this.active && this.inTab && !this.mobileLayoutStatus
return (this.active && this.inTab && !this.mobileLayoutStatus) || this.showPosition === 'multiplexing'
},
charViewShowFlag() {
return this.httpRequest.status && this.chart.type && !this.chart.type.includes('table') && !this.chart.type.includes('text') && this.chart.type !== 'label' && this.renderComponent() === 'echarts'
@ -298,13 +317,11 @@ export default {
return this.element.commonBackground && this.element.commonBackground.innerPadding || 0
},
...mapState([
'canvasStyleData',
'nowPanelTrackInfo',
'nowPanelJumpInfo',
'publicLinkStatus',
'previewCanvasScale',
'mobileLayoutStatus',
'componentData',
'panelViewDetailsInfo',
'componentViewsData',
'curBatchOptComponents'

View File

@ -351,7 +351,7 @@ const list = [
height: 200
},
x: 1,
y: 36,
y: 108,
sizex: 12,
sizey: 6,
auxiliaryMatrix: true,

View File

@ -8,9 +8,60 @@ import { uuid } from 'vue-uuid'
export default {
state: {
copyData: null, // 复制粘贴剪切
isCut: false
isCut: false,
viewBase: {
style: {
width: 300,
height: 200,
top: 0,
left: 0
},
x: 1,
y: 108,
sizex: 48,
sizey: 24
}
},
mutations: {
copyMultiplexingComponents(state) {
const _this = this
state.isCut = false
const canvasStyleData = state.canvasStyleData
const curCanvasScale = state.curCanvasScale
const componentGap = state.componentGap
Object.keys(state.curMultiplexingComponents).forEach(function(viewId, index) {
const component =
{
...deepCopy(state.curMultiplexingComponents[viewId]),
...deepCopy(state.viewBase),
'auxiliaryMatrix': canvasStyleData.auxiliaryMatrix
}
const tilePosition = index % 3
const divisiblePosition = parseInt(index / 3)
if (canvasStyleData.auxiliaryMatrix) {
const width = component.sizex * curCanvasScale.matrixStyleOriginWidth
// 取余 平铺4个 此处x 位置偏移
component.x = component.x + component.sizex * tilePosition
component.style.left = (component.x - 1) * curCanvasScale.matrixStyleOriginWidth
component.style.top = (component.y - 1) * curCanvasScale.matrixStyleOriginHeight
component.style.width = width
component.style.height = component.sizey * curCanvasScale.matrixStyleOriginHeight
} else {
const width = component.style.width
const height = component.style.height
component.style.top = component.style.top + divisiblePosition * (height + componentGap)
component.style.left = component.style.left + tilePosition * (width + componentGap)
component.style.width = width
component.style.height = height
}
state.copyData = {
data: component,
index: index
}
_this.commit('paste', true)
})
},
copy(state) {
if (!state.curComponent) return
state.copyData = {

View File

@ -68,6 +68,14 @@ export function mobile2MainCanvas(mainSource, mobileSource) {
}
export function panelInit(componentData, componentStyle) {
panelDataPrepare(componentData, componentStyle, function() {
// 将data 和 style 数据设置到全局store中
store.commit('setComponentData', resetID(componentData))
store.commit('setCanvasStyle', componentStyle)
})
}
export function panelDataPrepare(componentData, componentStyle, callback) {
// style初始化
componentStyle.refreshTime = (componentStyle.refreshTime || 5)
componentStyle.refreshViewLoading = (componentStyle.refreshViewLoading || false)
@ -109,9 +117,10 @@ export function panelInit(componentData, componentStyle) {
})
// 初始化密度为最高密度
componentStyle.aidedDesign.matrixBase = 4
// 将data 和 style 数据设置到全局store中
store.commit('setComponentData', resetID(componentData))
store.commit('setCanvasStyle', componentStyle)
callback({
'componentData': resetID(componentData),
'componentStyle': componentStyle
})
}
export function resetID(data) {

View File

@ -1448,6 +1448,7 @@ export default {
sure_bt: 'Confirm'
},
panel: {
multiplexing: 'Multiplexing',
panel_off: 'Off the shelf',
batch_opt: 'Batch Operation',
edit_leave_tips: 'Do You Want To Abandon And Leave The Current Page?',

View File

@ -131,8 +131,8 @@ export default {
default_login: '普通登錄'
},
commons: {
publish: '布',
unpublished: '取消布',
publish: '布',
unpublished: '取消布',
default_pwd: '初始密碼',
stop: '停止',
first_login_tips: '您使用的是初始密碼,記得修改密碼哦',
@ -915,10 +915,10 @@ export default {
color_fast: '輕快',
color_spiritual: '靈動',
chart_details: '視圖明細',
details: '明',
image: '片',
details: '明',
image: '片',
export_details: '導出明細',
export: '出',
export: '出',
chart_data: '數據',
chart_style: '樣式',
drag_block_type_axis: '類別軸',
@ -1096,7 +1096,7 @@ export default {
unit_million: '百萬',
unit_hundred_million: '億',
formatter_decimal_count_error: '請輸入0-10的整數',
gauge_threshold_compare_error: '值範圍需逐級遞增',
gauge_threshold_compare_error: '值範圍需逐級遞增',
tick_count: '刻度間隔數',
custom_sort: '自定義',
custom_sort_tip: '自定義排序優先級最高,且僅支持單個字段自定義',
@ -1341,8 +1341,8 @@ export default {
},
datasource: {
auth_method: '認證方式',
passwd: '用户名密码',
kerbers_info: '请确保 krb5.Conf、Keytab Key已经添加到路径/opt/dataease/conf',
passwd: '用戶名密碼',
kerbers_info: '請確保 krb5.Conf、Keytab Key已經添加到路徑/opt/dataease/conf',
client_principal: 'Client Principal',
keytab_Key_path: 'Keytab Key Path',
datasource: '數據源',
@ -1449,16 +1449,17 @@ export default {
sure_bt: '確定'
},
panel: {
panel_off: '仪表板已下架',
multiplexing: '復用',
panel_off: '儀表板已下架',
batch_opt: '批量操作',
edit_leave_tips: '是否放弃编辑离开当前界面?',
edit_leave_tips: '是否放棄編輯離開當前界面?',
hyperlinks: '超鏈接',
is_live: '是否直播',
yes: '是',
no: '否',
live_tips: '優先HTTPS鏈接',
stream_media_add_tips: '請點擊添加配置流媒體信息...',
stream_mobile_tips: 'IOS终端可能无法显示',
stream_mobile_tips: 'IOS終端可能無法顯示',
json_params_error: '第三方參數解析失敗,請檢查參數格式是否正確',
inner_padding: '內邊距',
board_radio: '邊框半徑',
@ -1545,7 +1546,7 @@ export default {
save_to_panel: '保存爲模闆',
export_to_panel: '導出爲模闆',
export_to_pdf: '導出爲PDF',
export_to_img: '導出爲片',
export_to_img: '導出爲片',
preview: '預覽',
fullscreen_preview: '全屏預覽',
new_tab_preview: '新Tab頁預覽',
@ -2062,6 +2063,6 @@ export default {
search_by_key: '搜索詳情'
},
plugin_style: {
border: '框'
border: '框'
}
}

View File

@ -1456,6 +1456,7 @@ export default {
sure_bt: '确定'
},
panel: {
multiplexing: '复用',
panel_off: '仪表板已下架',
batch_opt: '批量操作',
edit_leave_tips: '是否放弃编辑离开当前界面?',

View File

@ -21,7 +21,7 @@ import event from '@/components/canvas/store/event'
import layer from '@/components/canvas/store/layer'
import snapshot from '@/components/canvas/store/snapshot'
import lock from '@/components/canvas/store/lock'
import { valueValid, formatCondition, formatLinkageCondition } from '@/utils/conditionUtil'
import { valueValid, formatCondition } from '@/utils/conditionUtil'
import { Condition } from '@/components/widget/bean/Condition'
import {
@ -118,6 +118,8 @@ const data = {
batchOptStatus: false,
// Currently selected components
curBatchOptComponents: [],
// Currently selected Multiplexing components
curMultiplexingComponents: {},
mixProperties: [],
mixPropertiesInner: {},
batchOptChartInfo: null,
@ -559,6 +561,14 @@ const data = {
}
}
},
removeCurMultiplexingComponentWithId(state, id) {
delete state.curMultiplexingComponents[id]
},
addCurMultiplexingComponent(state, { component, componentId }) {
if (componentId) {
state.curMultiplexingComponents[componentId] = component
}
},
setBatchOptChartInfo(state) {
let render = null
let type = null
@ -647,9 +657,11 @@ const data = {
this.commit('setCurComponent', { component: null, index: null })
this.commit('clearLinkageSettingInfo', false)
this.commit('resetViewEditInfo')
this.commit('initCurMultiplexingComponents')
state.batchOptStatus = false
// Currently selected components
state.curBatchOptComponents = []
state.curMultiplexingComponents = {}
state.mixProperties = []
state.mixPropertyInnder = {}
state.batchOptChartInfo = null
@ -664,6 +676,9 @@ const data = {
plugin.isPlugin = true
})
state.allViewRender = [...TYPE_CONFIGS, ...pluginViews]
},
initCurMultiplexingComponents(state) {
state.curMultiplexingComponents = {}
}
},
modules: {

View File

@ -1,6 +1,10 @@
<template>
<div style="width: 100%;height: 100vh;background-color: #f7f8fa">
<Preview v-if="show" />
<Preview
v-if="show"
:component-data="componentData"
:canvas-style-data="canvasStyleData"
/>
</div>
</template>
@ -12,6 +16,7 @@ import { getPanelAllLinkageInfo } from '@/api/panel/linkage'
import { queryPanelJumpInfo, queryTargetPanelJumpInfo } from '@/api/panel/linkJump'
import { panelInit } from '@/components/canvas/utils/utils'
import { getOuterParamsInfo } from '@/api/panel/outerParams'
import { mapState } from 'vuex'
export default {
name: 'LinkView',
@ -31,6 +36,12 @@ export default {
show: false
}
},
computed: {
...mapState([
'canvasStyleData',
'componentData'
])
},
created() {
this.show = false
this.setPanelInfo()

View File

@ -0,0 +1,264 @@
<template>
<el-col v-loading="loading">
<el-row style="margin-top: 5px">
<el-row style="margin-left: 5px;margin-right: 5px">
<el-col>
<el-input
v-model="templateFilterText"
:placeholder="$t('panel.filter_keywords')"
size="mini"
clearable
prefix-icon="el-icon-search"
/>
</el-col>
</el-row>
<el-row style="margin-top: 5px">
<el-tree
ref="templateTree"
:default-expanded-keys="defaultExpandedKeys"
:show-checkbox="selectModel"
:data="data"
node-key="id"
:props="defaultProps"
draggable
:allow-drop="allowDrop"
:allow-drag="allowDrag"
:expand-on-click-node="true"
:filter-node-method="filterNode"
:highlight-current="true"
@node-drag-start="handleDragStart"
@check="checkChanged"
@node-drag-end="dragEnd"
>
<span slot-scope="{ node, data }" class="custom-tree-node-list father">
<span style="display: flex; flex: 1 1 0%; width: 0px;">
<span v-if="data.modelInnerType==='history'">
<i class="el-icon-collection" />
</span>
<span v-else-if="data.nodeType === 'spine'">
<i class="el-icon-folder" />
</span>
<span v-else-if="data.modelType==='panel'&& data.nodeType === 'leaf'">
<svg-icon icon-class="panel" class="ds-icon-scene" />
</span>
<span v-else>
<svg-icon :icon-class="data.isPlugin && data.type && data.type !== 'buddle-map' ? ('/api/pluginCommon/staticInfo/' + data.modelInnerType + '/svg') : data.modelInnerType" style="width: 14px;height: 14px" />
</span>
<span style="margin-left: 6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" :title="data.name">{{ data.name }}</span>
</span>
<span v-if="data.mode===1" class="child">
<span @click.stop>
<el-button
icon="el-icon-delete"
type="text"
size="small"
@click="deleteHistory(data, node)"
/>
</span>
</span>
</span>
</el-tree>
</el-row>
</el-row>
</el-col>
</template>
<script>
import componentList from '@/components/canvas/custom-component/component-list'
import { deepCopy } from '@/components/canvas/utils/utils'
import eventBus from '@/components/canvas/utils/eventBus'
import { mapState } from 'vuex'
import { queryPanelViewTree } from '@/api/panel/panel'
import { deleteCircle } from '@/api/chart/chart'
import { pluginTypes } from '@/api/chart/chart'
import { matrixBaseChange } from '@/components/canvas/utils/utils'
export default {
name: 'ViewSelect',
props: {
selectModel: {
type: Boolean,
default: false
}
},
data() {
return {
templateFilterText: '',
defaultExpandedKeys: [],
defaultProps: {
children: 'children',
label: 'name',
disabled: 'disabled'
},
data: [],
showdetail: false,
detailItem: null,
loading: false,
plugins: null
}
},
computed: {
...mapState([
'canvasStyleData'
])
},
watch: {
templateFilterText(val) {
this.$refs.templateTree.filter(val)
}
},
created() {
this.plugins = localStorage.getItem('plugin-views') && JSON.parse(localStorage.getItem('plugin-views'))
if (this.plugins) {
this.loadData()
} else {
pluginTypes().then(res => {
this.plugins = res.data
localStorage.setItem('plugin-views', JSON.stringify(res.data))
this.loadData()
}).catch(e => {
localStorage.setItem('plugin-views', null)
this.plugins = null
this.loadData()
})
}
},
methods: {
filterNode(value, data) {
if (!value) return true
return data.name.indexOf(value) !== -1
},
loadData() {
this.loading = true
queryPanelViewTree().then(res => {
const nodeDatas = res.data
if (this.selectModel) {
this.setParentDisable(nodeDatas)
}
this.data = nodeDatas
this.loading = false
})
},
handleDragStart(node, ev) {
this.$store.commit('setDragComponentInfo', this.viewComponentInfo())
ev.dataTransfer.effectAllowed = 'copy'
const dataTrans = {
type: 'view',
id: node.data.innerId
}
ev.dataTransfer.setData('componentInfo', JSON.stringify(dataTrans))
eventBus.$emit('startMoveIn')
},
dragEnd() {
this.$store.commit('clearDragComponentInfo')
},
//
allowDrag(draggingNode) {
if (draggingNode.data.modelType === 'panel' || draggingNode.data.nodeType === 'spine') {
return false
} else {
return true
}
},
allowDrop(draggingNode, dropNode, type) {
return false
},
newChart() {
this.$emit('newChart')
},
checkChanged(node, status) {
this.$refs.templateTree.setCheckedNodes([])
if (status.checkedKeys && status.checkedKeys.length > 0) {
this.$refs.templateTree.setCheckedNodes([node])
}
},
getCurrentSelected() {
const nodes = this.$refs.templateTree.getCheckedNodes(true, false)
return nodes
},
setParentDisable(nodes) {
nodes.forEach(node => {
if (node.modelType === 'panel' || node.nodeType === 'spine') {
node.disabled = true
}
if (node.modelType === 'view' && node.modelInnerType && this.plugins && this.plugins.length) {
node.isPlugin = this.plugins.some(plugin => plugin.value === node.modelInnerType)
}
if (node.children && node.children.length > 0) {
this.setParentDisable(node.children)
}
})
},
viewComponentInfo() {
let component
//
componentList.forEach(componentTemp => {
if (componentTemp.type === 'view') {
component = matrixBaseChange(deepCopy(componentTemp))
}
})
component.auxiliaryMatrix = this.canvasStyleData.auxiliaryMatrix
component.moveStatus = 'start'
return component
},
deleteHistory(data, node) {
deleteCircle(data.id).then(() => {
this.$success(this.$t('commons.delete_success'))
this.remove(node, data)
// this.loadData()
})
},
remove(node, data) {
const parent = node.parent
const children = parent.data.children || parent.data
const index = children.findIndex(d => d.id === data.id)
children.splice(index, 1)
},
showDetails(node, data) {
this.$emit('showDetails', {
'showType': data.nodeType,
'showId': data.id
})
}
}
}
</script>
<style lang="scss" scoped>
.top-div-class {
max-height: calc(100vh - 335px);
width: 100%;
position: fixed;
overflow-y : auto
}
.detail-class {
width: 300px;
position: fixed;
bottom: 0px;
}
.view-list-thumbnails {
width: 100%;
height: 100%;
}
.father .child {
/*display: none;*/
visibility: hidden;
}
.father:hover .child {
/*display: inline;*/
visibility: visible;
}
.custom-tree-node-list {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding:0 8px;
}
</style>

View File

@ -0,0 +1,122 @@
<template>
<de-container
v-loading="panelLoading"
class="main-class"
>
<de-aside-container v-loading="viewLoading" class="aside-class" type="panel">
<multiplexing-view :view-data="viewData" @showDetails="showDetails" />
</de-aside-container>
<de-main-container>
<Preview
v-if="selectedPanel"
:component-data="componentData"
:canvas-style-data="canvasStyleData"
:show-position="'multiplexing'"
/>
<el-col v-else style="height: 100%;">
<el-row style="height: 100%; background-color: var(--ContentBG);" class="custom-position">
{{ $t('panel.select_panel_from_left') }}
</el-row>
</el-col>
</de-main-container>
</de-container>
</template>
<script>
import DeMainContainer from '@/components/dataease/DeMainContainer'
import DeContainer from '@/components/dataease/DeContainer'
import DeAsideContainer from '@/components/dataease/DeAsideContainer'
import { findOne } from '@/api/panel/panel'
import { panelDataPrepare } from '@/components/canvas/utils/utils'
import Preview from '@/components/canvas/components/Editor/Preview'
import MultiplexingView from '@/views/panel/ViewSelect/multiplexingView'
export default {
name: 'Multiplexing',
components: { MultiplexingView, Preview, DeMainContainer, DeContainer, DeAsideContainer },
props: {
viewData: {
type: Array,
required: true
}
},
data() {
return {
activeName: 'PanelList',
viewLoading: false,
panelLoading: false,
showShare: false,
showEnshrine: false,
msgPanelIds: null,
componentData: [],
canvasStyleData: {},
selectedPanel: null
}
},
watch: {
},
mounted() {
},
methods: {
showDetails(params) {
const _this = this
_this.selectedPanel = params.showId
if (params.showType === 'panel') {
this.panelLoading = true
findOne(params.showId).then(response => {
this.panelLoading = false
panelDataPrepare(JSON.parse(response.data.panelData), JSON.parse(response.data.panelStyle), function(rsp) {
_this.componentData = rsp.componentData
_this.canvasStyleData = rsp.componentStyle
})
})
}
}
}
}
</script>
<style scoped>
.ms-aside-container {
height: calc(100vh - 120px);
padding: 0px;
min-width: 260px;
max-width: 460px;
}
.ms-main-container {
height: calc(100vh - 120px);
padding: 0px;
}
.tab-panel{
height: 100%;
overflow-y: auto;
}
.tab-panel>>>.el-tabs__nav-wrap{
padding: 0 10px;
}
.tab-panel>>>.el-tabs__nav-wrap::after {
height: 1px;
}
.tab-panel>>>.el-tabs__item{
/* width: 10px; */
padding: 0 10px;
}
.main-class {
border: 1px gainsboro solid;
}
::v-deep .drag-bar{
height: calc(100vh - 120px)!important;
}
.custom-position {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
flex-flow: row nowrap;
color: #9ea6b2;
}
</style>

View File

@ -0,0 +1,165 @@
<template>
<el-col v-loading="loading" style="height: 100%; overflow-y: auto">
<el-row style="margin-top: 5px">
<el-row style="margin-left: 5px;margin-right: 5px">
<el-col>
<el-input
v-model="templateFilterText"
:placeholder="$t('panel.filter_keywords')"
size="mini"
clearable
prefix-icon="el-icon-search"
/>
</el-col>
</el-row>
<el-row style="margin-top: 5px">
<el-tree
ref="templateTree"
:data="viewData"
node-key="id"
:props="defaultProps"
:expand-on-click-node="true"
:filter-node-method="filterNode"
:highlight-current="true"
@node-click="showDetails"
>
<span slot-scope="{ node, data }" class="custom-tree-node-list father">
<span style="display: flex; flex: 1 1 0%; width: 0px;">
<span v-if="data.modelInnerType==='history'">
<i class="el-icon-collection" />
</span>
<span v-else-if="data.nodeType === 'spine'">
<i class="el-icon-folder" />
</span>
<span v-else-if="data.modelType==='panel'&& data.nodeType === 'leaf'">
<svg-icon icon-class="panel" class="ds-icon-scene" />
</span>
<span v-else>
<svg-icon :icon-class="data.isPlugin && data.type && data.type !== 'buddle-map' ? ('/api/pluginCommon/staticInfo/' + data.modelInnerType + '/svg') : data.modelInnerType" style="width: 14px;height: 14px" />
</span>
<span style="margin-left: 6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" :title="data.name">{{ data.name }}</span>
</span>
<span v-if="data.mode===1" class="child">
<span @click.stop>
<el-button
icon="el-icon-delete"
type="text"
size="small"
@click="deleteHistory(data, node)"
/>
</span>
</span>
</span>
</el-tree>
</el-row>
</el-row>
</el-col>
</template>
<script>
import { mapState } from 'vuex'
import { deleteCircle } from '@/api/chart/chart'
export default {
name: 'MultiplexingView',
props: {
selectModel: {
type: Boolean,
default: false
},
viewData: {
type: Array,
required: true
}
},
data() {
return {
templateFilterText: '',
defaultProps: {
children: 'children',
label: 'name',
disabled: 'disabled'
},
data: [],
detailItem: null,
loading: false,
plugins: null
}
},
computed: {
...mapState([
'canvasStyleData'
])
},
watch: {
templateFilterText(val) {
this.$refs.templateTree.filter(val)
}
},
created() {
},
methods: {
filterNode(value, data) {
if (!value) return true
return data.name.indexOf(value) !== -1
},
deleteHistory(data, node) {
deleteCircle(data.id).then(() => {
this.$success(this.$t('commons.delete_success'))
this.remove(node, data)
// this.loadData()
})
},
remove(node, data) {
const parent = node.parent
const children = parent.data.children || parent.data
const index = children.findIndex(d => d.id === data.id)
children.splice(index, 1)
},
showDetails(node, data) {
if (data.data.nodeType === 'leaf') {
this.$emit('showDetails', {
'showType': data.data.modelType,
'showId': data.data.id
})
}
}
}
}
</script>
<style lang="scss" scoped>
.top-div-class {
max-height: calc(100vh - 335px);
width: 100%;
position: fixed;
overflow-y : auto
}
.detail-class {
width: 300px;
position: fixed;
bottom: 0px;
}
.view-list-thumbnails {
width: 100%;
height: 100%;
}
.father .child {
/*display: none;*/
visibility: hidden;
}
.father:hover .child {
/*display: inline;*/
visibility: visible;
}
.custom-tree-node-list {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding:0 8px;
}
</style>

View File

@ -111,11 +111,10 @@
style=" width: 24px;height: 24px;text-align: center;line-height: 1;position: relative;margin: 16px auto 0px;"
>
<el-button
:class="show&&showIndex===0? 'button-show':'button-closed'"
circle
class="el-icon-copy-document"
class="el-icon-copy-document button-closed"
size="mini"
@click="showPanel(0)"
@click="showMultiplexing(true)"
/>
</div>
<div class="button-text" style="position: relative; margin: 18px auto 16px;">
@ -123,7 +122,7 @@
style="max-width: 100%;text-align: center;white-space: nowrap;text-overflow: ellipsis;position: relative;flex-shrink: 0;"
>
<!-- {{ $t('panel.view') }}-->
复用
{{ $t('panel.multiplexing') }}
</div>
</div>
<div style="height: 1px; position: relative; margin: 0px auto;background-color:#E6E6E6;">
@ -150,7 +149,7 @@
:close-on-press-escape="false"
:modal-append-to-body="true"
>
<view-select v-show=" show && showIndex===0" @newChart="newChart" />
<!-- <view-select v-show=" show && showIndex===0" @newChart="newChart" />-->
<filter-group v-show=" show &&showIndex===1" />
<subject-setting v-show=" show &&showIndex===2" />
<assist-component v-show=" show &&showIndex===3" />
@ -276,6 +275,8 @@
v-if="previewVisible"
:in-screen="!previewVisible"
:show-type="canvasStyleData.selfAdaption?'full':'width'"
:canvas-style-data="canvasStyleData"
:component-data="componentData"
/>
</fullscreen>
<input
@ -312,6 +313,25 @@
<OuterParamsSet v-if="outerParamsSetVisible" @outerParamsSetVisibleChange="outerParamsSetVisibleChange" />
</el-dialog>
<!--复用视图全屏显示框-->
<el-dialog
:visible="multiplexingShow"
:show-close="false"
class="dialog-css"
:fullscreen="true"
>
<multiplexing v-if="multiplexingShow" :view-data="viewData" />
<div slot="title" class="dialog-footer title-text">
<span style="font-size: 14px;">
{{ $t('panel.multiplexing') }}
</span>
<span style="float: right;">
<el-button type="primary" size="mini" @click="saveMultiplexing()">{{ $t('commons.confirm') }}</el-button>
<el-button size="mini" @click="showMultiplexing(false)">{{ $t('commons.cancel') }}</el-button>
</span>
</div>
</el-dialog>
</el-row>
</template>
@ -325,7 +345,7 @@ import ViewSelect from '../ViewSelect'
import SubjectSetting from '../SubjectSetting'
import bus from '@/utils/bus'
import Editor from '@/components/canvas/components/Editor/index'
import { deepCopy, matrixBaseChange, panelInit } from '@/components/canvas/utils/utils'
import { deepCopy, matrixBaseChange } from '@/components/canvas/utils/utils'
import componentList, {
BASE_MOBILE_STYLE,
COMMON_BACKGROUND,
@ -334,7 +354,7 @@ import componentList, {
import { mapState } from 'vuex'
import { uuid } from 'vue-uuid'
import Toolbar from '@/components/canvas/components/Toolbar'
import { initPanelData, initViewCache } from '@/api/panel/panel'
import { initPanelData, initViewCache, queryPanelMultiplexingViewTree } from '@/api/panel/panel'
import Preview from '@/components/canvas/components/Editor/Preview'
import elementResizeDetectorMaker from 'element-resize-detector'
import AssistComponent from '@/views/panel/AssistComponent'
@ -354,10 +374,12 @@ import { deleteEnshrine, saveEnshrine, starStatus } from '@/api/panel/enshrine'
import ChartEdit from '@/views/chart/view/ChartEdit'
import OuterParamsSet from '@/views/panel/OuterParamsSet/index'
import ChartStyleBatchSet from '@/views/chart/view/ChartStyleBatchSet'
import Multiplexing from '@/views/panel/ViewSelect/multiplexing'
export default {
name: 'PanelEdit',
components: {
Multiplexing,
ChartStyleBatchSet,
OuterParamsSet,
ComponentWait,
@ -378,6 +400,8 @@ export default {
},
data() {
return {
viewData: [],
multiplexingShow: false,
asideToolType: 'none',
outerParamsSetVisible: false,
autoMoveOffSet: 15,
@ -545,6 +569,9 @@ export default {
return this.pcMatrixCount
}
},
multiplexingDisabled() {
return Object.keys(this.curMultiplexingComponents) === 0
},
...mapState([
'curComponent',
'curCanvasScale',
@ -560,7 +587,8 @@ export default {
'mobileMatrixCount',
'mobileLayoutStyle',
'scrollAutoMove',
'batchOptStatus'
'batchOptStatus',
'curMultiplexingComponents'
])
},
@ -616,12 +644,18 @@ export default {
_this.restore()
})
})
this.loadMultiplexingViewTree()
},
beforeDestroy() {
const elx = this.$refs.rightPanel
elx && elx.remove()
},
methods: {
loadMultiplexingViewTree() {
queryPanelMultiplexingViewTree().then(res => {
this.viewData = res.data
})
},
closeOuterParamsSetDialog() {
this.outerParamsSetVisible = false
},
@ -1080,6 +1114,15 @@ export default {
const canvasInfoMobile = document.getElementById('canvasInfoMobile')
canvasInfoMobile.scrollTop = canvasInfoMobile.scrollTop + offset
this.$store.commit('setScrollAutoMove', this.scrollAutoMove + offset)
},
showMultiplexing(type) {
this.multiplexingShow = type
},
saveMultiplexing() {
this.showMultiplexing(false)
this.$store.commit('copyMultiplexingComponents')
this.$store.commit('recordSnapshot')
this.$store.state.styleChangeTimes++
}
}
}
@ -1348,4 +1391,15 @@ export default {
height: calc(100vh - 100px);
}
.dialog-css ::v-deep .el-dialog__title {
font-size: 14px;
}
.dialog-css ::v-deep .el-dialog__header {
padding: 20px 20px 0;
}
.dialog-css ::v-deep .el-dialog__body {
padding: 10px 20px 20px;
}
</style>

View File

@ -68,7 +68,7 @@ export default {
this.$store.commit('initViewRender', plugins)
}).catch(e => {
localStorage.setItem('plugin-views', null)
this.$store.commit('initViewRender', plugins)
this.$store.commit('initViewRender', [])
})
this.clear()
},

View File

@ -52,13 +52,13 @@
</el-dropdown-menu>
</el-dropdown>
</span>
<span style="float: right;margin-right: 10px" v-if="panelInfo.status==='publish'">
<span v-if="panelInfo.status==='publish'" style="float: right;margin-right: 10px">
<el-tooltip :content="$t('panel.fullscreen_preview')">
<el-button class="el-icon-view" size="mini" circle @click="clickFullscreen" />
</el-tooltip>
</span>
<span style="float: right;margin-right: 10px" v-if="panelInfo.status==='publish'">
<span v-if="panelInfo.status==='publish'" style="float: right;margin-right: 10px">
<el-tooltip :content="$t('panel.new_tab_preview')">
<el-button class="el-icon-data-analysis" size="mini" circle @click="newTab" />
</el-tooltip>
@ -90,7 +90,15 @@
<!-- <div id="imageWrapper" ref="imageWrapper" style="width: 4096px;height: 2160px">-->
<div id="imageWrapper" ref="imageWrapper" :style="imageWrapperStyle">
<fullscreen style="height: 100%;background: #f7f8fa;overflow-y: auto" :fullscreen.sync="fullscreen">
<Preview v-if="showMainFlag" :active-tab="activeTab" :in-screen="!fullscreen" :show-type="'width'" :screen-shot="dataLoading" />
<Preview
v-if="showMainFlag"
:component-data="componentData"
:canvas-style-data="canvasStyleData"
:active-tab="activeTab"
:in-screen="!fullscreen"
:show-type="'width'"
:screen-shot="dataLoading"
/>
</fullscreen>
</div>
</el-row>