forked from github/dataease
feat(仪表板): 前端增加导出分页功能
This commit is contained in:
parent
ff3883cd59
commit
84ae4dbb78
@ -165,6 +165,44 @@ public class XEmailTaskServer {
|
||||
return xpackEmailCreate;
|
||||
}
|
||||
|
||||
@DeRateLimiter
|
||||
@PostMapping(value = "/screenpdf", produces = {MediaType.APPLICATION_PDF_VALUE})
|
||||
public ResponseEntity<ByteArrayResource> screenpdf(@RequestBody XpackEmailViewRequest request) {
|
||||
EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class);
|
||||
String url = ServletUtils.domain() + "/#/previewScreenShot/" + request.getPanelId() + "/true";
|
||||
byte[] bytes = null;
|
||||
try {
|
||||
String currentToken = ServletUtils.getToken();
|
||||
Future<?> future = priorityExecutor.submit(() -> {
|
||||
try {
|
||||
return emailXpackService.printPdf(url, currentToken, buildPixel(request.getPixel()));
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
DEException.throwException("预览失败,请联系管理员");
|
||||
}
|
||||
return null;
|
||||
}, 0);
|
||||
Object object = future.get();
|
||||
if (ObjectUtils.isNotEmpty(object)) {
|
||||
bytes = (byte[]) object;
|
||||
if (ArrayUtil.isNotEmpty(bytes)) {
|
||||
String fileName = request.getPanelId() + ".pdf";
|
||||
ByteArrayResource bar = new ByteArrayResource(bytes);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_PDF);
|
||||
ContentDisposition contentDisposition = ContentDisposition.parse("attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
|
||||
headers.setContentDisposition(contentDisposition);
|
||||
return new ResponseEntity(bar, headers, HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
DEException.throwException("预览失败,请联系管理员");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@DeRateLimiter
|
||||
@PostMapping(value = "/screenshot", produces = {MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE})
|
||||
public ResponseEntity<ByteArrayResource> screenshot(@RequestBody XpackEmailViewRequest request) {
|
||||
|
@ -297,6 +297,9 @@ export default {
|
||||
// this.$emit('handleDrop', e)
|
||||
// }
|
||||
handleDrop(e) {
|
||||
if (!this.dragComponentInfo) {
|
||||
return
|
||||
}
|
||||
this.dragComponentInfo.moveStatus = 'drop'
|
||||
// 记录拖拽信息
|
||||
this.dropComponentInfo = deepCopy(this.dragComponentInfo)
|
||||
|
@ -153,6 +153,25 @@
|
||||
@change="styleChange"
|
||||
/>
|
||||
</el-dropdown-item>
|
||||
|
||||
<el-dropdown-item>
|
||||
<span class="icon iconfont el-icon-reading icon16" />
|
||||
<el-tooltip
|
||||
class="item"
|
||||
:content="$t('panel.export_pdf_page_remark')"
|
||||
placement="top-start"
|
||||
>
|
||||
|
||||
<span class="text14 margin-left8">{{ $t('panel.export_pdf_page') }}</span>
|
||||
|
||||
</el-tooltip>
|
||||
<el-switch
|
||||
v-model="showPageLine"
|
||||
:class="[{['grid-active']: showPageLine},'margin-left8']"
|
||||
size="mini"
|
||||
@change="showPageLineChange"
|
||||
/>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
@ -247,6 +266,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showPageLine: false,
|
||||
showGridSwitch: false,
|
||||
mobileLayoutInitStatus: false,
|
||||
isShowPreview: false,
|
||||
@ -305,6 +325,7 @@ export default {
|
||||
this.scale = this.canvasStyleData.scale
|
||||
this.mobileLayoutInitStatus = this.mobileLayoutStatus
|
||||
this.showGridSwitch = this.canvasStyleData.aidedDesign.showGrid
|
||||
this.showPageLine = this.canvasStyleData.pdfPageLine?.showPageLine
|
||||
this.autoCache()
|
||||
},
|
||||
beforeDestroy() {
|
||||
@ -323,6 +344,7 @@ export default {
|
||||
},
|
||||
editPanelInit() {
|
||||
this.showGridSwitch = this.canvasStyleData.aidedDesign.showGrid
|
||||
this.showPageLine = this.canvasStyleData.pdfPageLine?.showPageLine
|
||||
},
|
||||
close() {
|
||||
// 关闭页面清理缓存
|
||||
@ -589,6 +611,10 @@ export default {
|
||||
this.$store.commit('canvasChange')
|
||||
this.canvasStyleData.aidedDesign.showGrid = !this.canvasStyleData.aidedDesign.showGrid
|
||||
},
|
||||
showPageLineChange() {
|
||||
this.$store.commit('canvasChange')
|
||||
this.canvasStyleData.pdfPageLine.showPageLine = !this.canvasStyleData.pdfPageLine.showPageLine
|
||||
},
|
||||
// batch option
|
||||
batchOption() {
|
||||
bus.$emit('change_panel_right_draw', !this.batchOptStatus)
|
||||
|
@ -12,6 +12,11 @@
|
||||
@mousedown="handleMouseDown"
|
||||
@scroll="canvasScroll"
|
||||
>
|
||||
<page-line-editor
|
||||
v-if="showPageLine"
|
||||
ref="main-page-line"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
/>
|
||||
<!-- 网格线 -->
|
||||
<Grid
|
||||
v-if="showGrid"
|
||||
@ -121,7 +126,7 @@
|
||||
:canvas-id="canvasId"
|
||||
/>
|
||||
<!-- 右击菜单 -->
|
||||
<ContextMenu/>
|
||||
<ContextMenu />
|
||||
|
||||
<!-- 对齐标线 -->
|
||||
<span
|
||||
@ -157,6 +162,7 @@ import MarkLine from './MarkLine'
|
||||
import Area from './Area'
|
||||
import eventBus from '@/components/canvas/utils/eventBus'
|
||||
import Grid from './Grid'
|
||||
import PageLineEditor from './PageLineEditor'
|
||||
import PGrid from './PGrid'
|
||||
import { changeStyleWithScale } from '@/components/canvas/utils/translate'
|
||||
import UserViewDialog from '@/components/canvas/customComponent/UserViewDialog'
|
||||
@ -763,7 +769,8 @@ export default {
|
||||
UserViewDialog,
|
||||
DeOutWidget,
|
||||
DragShadow,
|
||||
LinkJumpSet
|
||||
LinkJumpSet,
|
||||
PageLineEditor
|
||||
},
|
||||
props: {
|
||||
parentForbid: {
|
||||
@ -944,11 +951,26 @@ export default {
|
||||
return false
|
||||
}
|
||||
},
|
||||
showPageLine() {
|
||||
if (this.canvasStyleData && this.canvasStyleData.pdfPageLine) {
|
||||
return this.canvasStyleData.pdfPageLine.showPageLine
|
||||
}
|
||||
return false
|
||||
},
|
||||
editStyle() {
|
||||
return {
|
||||
height: this.outStyle.height + this.scrollTop + 'px !important'
|
||||
}
|
||||
},
|
||||
scrollHeight() {
|
||||
let baseHeight = 0
|
||||
this.componentData.forEach(item => {
|
||||
const top = this.getShapeStyleIntDeDrag(item.style, 'top')
|
||||
const height = this.getShapeStyleIntDeDrag(item.style, 'height')
|
||||
baseHeight = Math.max(baseHeight, top + height)
|
||||
})
|
||||
return baseHeight
|
||||
},
|
||||
customStyle() {
|
||||
let style = {
|
||||
width: '100%',
|
||||
@ -1024,6 +1046,20 @@ export default {
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
scrollHeight: {
|
||||
handler(newVal, oldVla) {
|
||||
this.$nextTick(() => {
|
||||
if (newVal !== oldVla && this.showPageLine) {
|
||||
const lineRef = this.$refs['main-page-line']
|
||||
if (lineRef?.init) {
|
||||
lineRef.init(newVal)
|
||||
}
|
||||
}
|
||||
console.log(newVal)
|
||||
})
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
outStyle: {
|
||||
handler(newVal, oldVla) {
|
||||
this.resizeParentBoundsRef()
|
||||
@ -1251,6 +1287,9 @@ export default {
|
||||
},
|
||||
changeStyleWithScale,
|
||||
handleMouseDown(e) {
|
||||
if (this.isPageLineTarget(e)) {
|
||||
return
|
||||
}
|
||||
// 如果没有选中组件 在画布上点击时需要调用 e.preventDefault() 防止触发 drop 事件
|
||||
if (!this.curComponent || (this.curComponent.component !== 'v-text' && this.curComponent.component !== 'rect-shape')) {
|
||||
e.preventDefault()
|
||||
@ -1259,6 +1298,9 @@ export default {
|
||||
// 挤占式画布设计
|
||||
this.containerMouseDown(e)
|
||||
},
|
||||
isPageLineTarget(e) {
|
||||
return e.target.classList && [...e.target.classList].includes('page-line-item')
|
||||
},
|
||||
|
||||
hideArea() {
|
||||
this.isShowArea = 0
|
||||
@ -1517,6 +1559,9 @@ export default {
|
||||
}
|
||||
},
|
||||
handleDragOver(e) {
|
||||
if (!this.dragComponentInfo?.shadowStyle) {
|
||||
return
|
||||
}
|
||||
this.dragComponentInfo.shadowStyle.x = e.pageX - 220
|
||||
this.dragComponentInfo.shadowStyle.y = e.pageY - 90 + this.scrollTop
|
||||
this.dragComponentInfo.style.left = this.dragComponentInfo.shadowStyle.x / this.scalePointWidth
|
||||
|
@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="page-line-container">
|
||||
<div
|
||||
v-for="(line, index) in lineLocations"
|
||||
:key="index"
|
||||
:ref="baseLineKey + index"
|
||||
class="page-line-item"
|
||||
:style="{'top': line + 'px', 'background': panelBg}"
|
||||
@mousedown="handleMouseDown"
|
||||
>
|
||||
<span class="top-span" />
|
||||
<span class="bottom-span" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reverseColor } from '@/views/chart/chart/common/common'
|
||||
export default {
|
||||
name: 'PageLineEditor',
|
||||
props: {
|
||||
|
||||
canvasStyleData: {
|
||||
type: Object,
|
||||
require: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
baseLineKey: 'page-line-',
|
||||
lineLocations: [],
|
||||
curLineHieght: 0,
|
||||
clientStartY: 0,
|
||||
startTop: 0,
|
||||
movingLineHeight: 0,
|
||||
scrollHeight: 0,
|
||||
baseLineColor: '#1F2329'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
windowHeight() {
|
||||
return window.innerHeight - 56
|
||||
},
|
||||
panelBg() {
|
||||
if (this.canvasStyleData.panel.backgroundType === 'color') {
|
||||
return reverseColor(this.canvasStyleData.panel.color)
|
||||
}
|
||||
return this.baseLineColor
|
||||
},
|
||||
pdfPageLine() {
|
||||
return this.$store.state.canvasStyleData.pdfPageLine
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
created() {
|
||||
},
|
||||
|
||||
methods: {
|
||||
resize() {
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
init(scrollHeight) {
|
||||
this.lineLocations = []
|
||||
this.scrollHeight = scrollHeight || document.getElementById('canvas-id-canvas-main').scrollHeight
|
||||
|
||||
if (this.pdfPageLine?.proportion) {
|
||||
this.curLineHieght = this.pdfPageLine.proportion * this.scrollHeight
|
||||
} else {
|
||||
this.curLineHieght = this.windowHeight
|
||||
this.saveLineHeight()
|
||||
}
|
||||
let curLineLocation = this.curLineHieght
|
||||
while (curLineLocation < this.scrollHeight) {
|
||||
this.lineLocations.push(curLineLocation)
|
||||
curLineLocation += this.curLineHieght
|
||||
}
|
||||
},
|
||||
handleMouseDown(e) {
|
||||
this.clientStartY = e.clientY
|
||||
this.startTop = parseInt(e.target.style.top)
|
||||
document.onmousemove = ev => this.handleMouseMove(e, ev)
|
||||
document.onmouseup = () => {
|
||||
this.curLineHieght = this.movingLineHeight
|
||||
this.saveLineHeight()
|
||||
this.init()
|
||||
document.onmousemove = document.onmouseup = null
|
||||
}
|
||||
},
|
||||
handleMouseMove(e, ev) {
|
||||
const moveInstance = ev.clientY - this.clientStartY
|
||||
this.movingLineHeight = this.curLineHieght + moveInstance
|
||||
e.target.style.top = this.startTop + moveInstance + 'px'
|
||||
},
|
||||
saveLineHeight() {
|
||||
this.$store.commit('canvasChange')
|
||||
this.canvasStyleData.pdfPageLine.proportion = this.curLineHieght / this.scrollHeight
|
||||
this.pdfPageLine.proportion = this.curLineHieght / this.scrollHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-line-container {
|
||||
/* width: 100%;
|
||||
height: 100%; */
|
||||
}
|
||||
.page-line-item {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
margin: 2px 0;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
cursor: row-resize;
|
||||
span {
|
||||
width: 20px;
|
||||
background: #bbb;
|
||||
left: calc(50% - 5px);
|
||||
height: 2px;
|
||||
position: absolute;
|
||||
}
|
||||
.top-span {
|
||||
top: -3px !important;
|
||||
}
|
||||
.bottom-span {
|
||||
top: 3px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -8,7 +8,7 @@ import {
|
||||
import { ApplicationContext } from '@/utils/ApplicationContext'
|
||||
import { uuid } from 'vue-uuid'
|
||||
import store from '@/store'
|
||||
import { AIDED_DESIGN, MOBILE_SETTING, PANEL_CHART_INFO, TAB_COMMON_STYLE } from '@/views/panel/panel'
|
||||
import { AIDED_DESIGN, MOBILE_SETTING, PANEL_CHART_INFO, TAB_COMMON_STYLE, PAGE_LINE_DESIGN } from '@/views/panel/panel'
|
||||
import html2canvas from 'html2canvasde'
|
||||
|
||||
export function deepCopy(target) {
|
||||
@ -83,6 +83,7 @@ export function panelDataPrepare(componentData, componentStyle, callback) {
|
||||
componentStyle.refreshUnit = (componentStyle.refreshUnit || 'minute')
|
||||
componentStyle.refreshViewEnable = (componentStyle.refreshViewEnable === undefined ? true : componentStyle.refreshViewEnable)
|
||||
componentStyle.aidedDesign = (componentStyle.aidedDesign || deepCopy(AIDED_DESIGN))
|
||||
componentStyle.pdfPageLine = (componentStyle.pdfPageLine || deepCopy(PAGE_LINE_DESIGN))
|
||||
componentStyle.chartInfo = (componentStyle.chartInfo || deepCopy(PANEL_CHART_INFO))
|
||||
componentStyle.chartInfo.tabStyle = (componentStyle.chartInfo.tabStyle || deepCopy(TAB_COMMON_STYLE))
|
||||
componentStyle.themeId = (componentStyle.themeId || 'NO_THEME')
|
||||
|
@ -2244,6 +2244,8 @@ export default {
|
||||
aided_grid: 'Aided Grid',
|
||||
aided_grid_open: 'Open',
|
||||
aided_grid_close: 'Close',
|
||||
export_pdf_page: 'Pagination Line',
|
||||
export_pdf_page_remark: 'Only valid for API export dashboard PDF pagination',
|
||||
subject_no_edit: 'System Subject Can Not Edit',
|
||||
subject_name_not_null: 'Subject Name Can Not Be Null And Less Than 20 charts',
|
||||
is_enable: 'Enable',
|
||||
|
@ -2238,6 +2238,8 @@ export default {
|
||||
aided_grid: '輔助設計網格',
|
||||
aided_grid_open: '打開',
|
||||
aided_grid_close: '關閉',
|
||||
export_pdf_page: '分頁線',
|
||||
export_pdf_page_remark: '僅對API導出儀表板PDF分頁有效',
|
||||
subject_no_edit: '繫統主題不能修改',
|
||||
subject_name_not_null: '主題名稱需要1~20字符',
|
||||
is_enable: '是否啟用',
|
||||
|
@ -2238,6 +2238,8 @@ export default {
|
||||
aided_grid: '辅助设计网格',
|
||||
aided_grid_open: '打开',
|
||||
aided_grid_close: '关闭',
|
||||
export_pdf_page: '分页线',
|
||||
export_pdf_page_remark: '仅对API导出仪表板PDF分页有效',
|
||||
subject_no_edit: '系统主题不能修改',
|
||||
subject_name_not_null: '主题名称需要1~20字符',
|
||||
is_enable: '是否启用',
|
||||
|
@ -69,6 +69,10 @@ export const CANVAS_STYLE = {
|
||||
showGrid: false,
|
||||
matrixBase: 4 // 当前matrix的基数 (是pcMatrixCount的几倍)
|
||||
}, // 辅助设计
|
||||
pdfPageLine: {
|
||||
showPageLine: false,
|
||||
proportion: null
|
||||
},
|
||||
refreshViewEnable: true, // 开启视图刷新(默认开启)
|
||||
refreshViewLoading: true, // 仪表板视图loading提示
|
||||
refreshUnit: 'minute', // 仪表板刷新时间带外 默认 分钟
|
||||
@ -82,6 +86,11 @@ export const AIDED_DESIGN = {
|
||||
matrixBase: 1 // 当前matrix的基数 (是pcMatrixCount的几倍)
|
||||
}
|
||||
|
||||
export const PAGE_LINE_DESIGN = {
|
||||
showPageLine: false,
|
||||
proportion: null
|
||||
}
|
||||
|
||||
export const DEFAULT_COMMON_CANVAS_STYLE_STRING = {
|
||||
...CANVAS_STYLE
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user