refactor: preview head

This commit is contained in:
wangjiahao
2025-06-11 17:00:18 +08:00
parent 67c0d8aa73
commit f46b7212f5
13 changed files with 325 additions and 72 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ from fastapi import APIRouter, File, UploadFile, HTTPException
from apps.dashboard.crud.dashboard_service import list_resource, load_resource, \
create_resource, create_canvas, validate_name, delete_resource, update_resource, update_canvas
from apps.dashboard.models.dashboard_model import CreateDashboard, BaseDashboard, QueryDashboard
from apps.dashboard.models.dashboard_model import CreateDashboard, BaseDashboard, QueryDashboard,DashboardResponse
from common.core.deps import SessionDep, CurrentUser
router = APIRouter(tags=["dashboard"], prefix="/dashboard")
@@ -24,8 +24,19 @@ def list_resource(session: SessionDep, dashboard: QueryDashboard):
return tree
def load_resource(session: SessionDep,dashboard: QueryDashboard):
return session.query(CoreDashboard).filter(CoreDashboard.id == dashboard.id).first()
def load_resource(session: SessionDep, dashboard: QueryDashboard):
sql = text("""
SELECT cd.*,
creator.name AS create_name,
updator.name AS update_name
FROM core_dashboard cd
LEFT JOIN sys_user creator ON cd.create_by = creator.id::varchar
LEFT JOIN sys_user updator
ON cd.update_by = updator.id:: varchar
WHERE cd.id = :dashboard_id
""")
result = session.execute(sql, {"dashboard_id": dashboard.id}).mappings().first()
return result
def get_create_base_info(user: CurrentUser, dashboard: CreateDashboard):
@@ -133,6 +133,10 @@ class DashboardBaseResponse(BaseModel):
update_time: Optional[int] = None
children: List['DashboardBaseResponse'] = []
class DashboardResponse(CoreDashboard):
update_name: Optional[str] = None
create_name: Optional[str] = None
class BaseDashboard(BaseModel):
id: str = ''
name: str = ''
+2
View File
@@ -16,6 +16,7 @@
"dayjs": "^1.11.13",
"element-plus": "^2.10.1",
"element-plus-secondary": "^1.0.0",
"element-resize-detector": "^1.2.4",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"snowflake-id": "^1.1.0",
@@ -28,6 +29,7 @@
"devDependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@types/crypto-js": "^4.2.2",
"@types/element-resize-detector": "^1.1.6",
"@types/node": "^22.14.1",
"@vitejs/plugin-vue": "^5.2.2",
"@vue/tsconfig": "^0.7.0",
+3 -3
View File
@@ -20,12 +20,12 @@ export const dashboardStore = defineStore('dashboard', {
workspaceId: null,
status: null,
dataState: null,
type: null,
creatorName: null,
createName: null,
updateName: null,
createTime: null,
updateTime: null,
contentId: null
contentId: null,
type: null
}
}
},
@@ -4,12 +4,12 @@
Dashboard ID
</div>
<div class="info-content">{{ dashboardInfo.id }}</div>
<div v-if="dashboardInfo.creatorName" class="info-title">Creator</div>
<div v-if="dashboardInfo.creatorName" class="info-content">Creator Name</div>
<div v-if="dashboardInfo.createName" class="info-title">Creator</div>
<div v-if="dashboardInfo.createName" class="info-content">{{ dashboardInfo.createName }}</div>
<div class="info-title">Create Time</div>
<div class="info-content">{{ timestampFormatDate(dashboardInfo.createTime) }}</div>
<div v-if="dashboardInfo.updateName" class="info-title">Updator</div>
<div v-if="dashboardInfo.updateName" class="info-content">Updator Name</div>
<div v-if="dashboardInfo.updateName" class="info-content">{{ dashboardInfo.updateName }}</div>
<div class="info-title">Update Time</div>
<div v-if="dashboardInfo.updateTime" class="info-content">
{{ timestampFormatDate(dashboardInfo.updateTime) }}
@@ -19,17 +19,19 @@
</template>
<script lang="ts" setup>
import {dashboardStoreWithOut} from "@/stores/dashboard/dashboard.ts";
import {storeToRefs} from "pinia";
const dashboardStore = dashboardStoreWithOut()
const {dashboardInfo} = storeToRefs(dashboardStore)
defineProps({
dashboardInfo: {
type: Object,
required: true
}
})
const timestampFormatDate = (value:any) => {
const timestampFormatDate = (value: any) => {
if (!value) {
return '-'
}
return new Date(value).toLocaleString()
return new Date(value * 1000).toLocaleString()
}
</script>
@@ -45,6 +47,7 @@ const timestampFormatDate = (value:any) => {
font-size: 14px;
margin-bottom: 4px;
}
.info-content {
color: #1f2329;
font-size: 14px;
@@ -23,6 +23,19 @@ const props = defineProps({
configItem: {
type: Object as PropType<CanvasItem>,
required: true
},
canvasViewInfo: {
type: Object,
required: true
},
showPosition: {
required: false,
type: String,
default: 'preview'
},
canvasId: {
type: String,
default: 'canvas-main'
}
})
@@ -220,11 +233,11 @@ defineExpose({
position: absolute;
width: 100%;
height: 100%;
margin: 2px!important;// border size
margin: 2px !important; // border size
}
.tab-dashboard-editor-main{
height: 100%!important;
.tab-dashboard-editor-main {
height: 100% !important;
}
.tab-moveout {
@@ -8,7 +8,6 @@ import cloneDeep from 'lodash/cloneDeep';
import {storeToRefs} from "pinia";
import {dashboardStoreWithOut} from "@/stores/dashboard/dashboard.ts";
import router from '@/router'
import {dashboardApi} from "@/api/dashboard.ts";
import {initCanvasData} from "@/views/dashboard/utils/canvasUtils.ts";
const dashboardStore = dashboardStoreWithOut()
@@ -0,0 +1,73 @@
<script setup lang="ts">
import {ref, toRefs, computed} from 'vue'
import {findComponent} from "@/views/dashboard/components/component-list.ts";
const componentWrapperInnerRef = ref(null)
const props = defineProps({
active: {
type: Boolean,
default: false
},
configItem: {
type: Object,
required: true
},
canvasViewInfo: {
type: Object,
required: true
},
showPosition: {
required: false,
type: String,
default: 'preview'
},
canvasId: {
type: String,
default: 'canvas-main'
}
})
const {configItem, showPosition} = toRefs(props)
const component = ref(null)
const wrapperId = 'wrapper-outer-id-' + configItem.value.id
const viewDemoInnerId = computed(() => 'enlarge-inner-content-' + configItem.value.id)
</script>
<template>
<div class="wrapper-outer" :id="wrapperId">
<div class="wrapper-inner" ref="componentWrapperInnerRef" :id="viewDemoInnerId">
<div class="wrapper-inner-adaptor">
<component
ref="component"
class="component"
:is="findComponent(configItem['component'])"
:canvas-view-info="canvasViewInfo"
:view="canvasViewInfo[configItem.id]"
:config-item="configItem"
:show-position="showPosition"
:active="active"
/>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.wrapper-outer {
position: absolute;
.wrapper-inner {
width: 100%;
height: 100%;
position: relative;
background-size: 100% 100% !important;
.wrapper-inner-adaptor {
position: relative;
transform-style: preserve-3d;
width: 100%;
height: 100%;
}
}
}
</style>
@@ -1,11 +1,168 @@
<script setup lang="ts">
import elementResizeDetectorMaker from 'element-resize-detector'
const dashboardStore = dashboardStoreWithOut()
const {curComponent} = storeToRefs(dashboardStore)
import {onMounted, toRefs, ref, computed, reactive} from 'vue'
import {dashboardStoreWithOut} from "@/stores/dashboard/dashboard.ts";
import {storeToRefs} from "pinia";
import SQComponentWrapper from "@/views/dashboard/preview/SQComponentWrapper.vue";
import type {CanvasItem} from "@/utils/canvas.ts";
const props = defineProps({
canvasStyleData: {
type: Object,
required: true
},
componentData: {
type: Object,
required: true
},
canvasViewInfo: {
type: Object,
required: true
},
dashboardInfo: {
type: Object,
required: true
},
baseMatrixCount: {
type: Object,
default: {
x: 72,
y: 36
}
},
canvasId: {
type: String,
required: false,
default: 'canvas-main'
},
showPosition: {
required: false,
type: String,
default: 'preview'
}
})
const { canvasStyleData, componentData, showPosition,
canvasId
} = toRefs(props)
const domId = 'preview-' + canvasId.value
const previewCanvas = ref(null)
const renderReady = ref(false)
const state = reactive({
initState: true,
scrollMain: 0
})
const cellWidth = ref(0)
const cellHeight = ref(0)
const baseWidth = ref(0)
const baseHeight = ref(0)
const baseMarginLeft = ref(0)
const baseMarginTop = ref(0)
const canvasStyle = computed(() => {
return {}
})
const restore = () => {
}
function nowItemStyle(item: CanvasItem) {
return {
width: cellWidth.value * item.sizeX - baseMarginLeft.value + 'px',
height: cellHeight.value * item.sizeY - baseMarginTop.value + 'px',
left: cellWidth.value * (item.x - 1) + baseMarginLeft.value + 'px',
top: cellHeight.value * (item.y - 1) + baseMarginTop.value + 'px'
}
}
const sizeInit = () => {
if (previewCanvas.value) {
//@ts-ignore
const screenWidth = dashboardEditorRef.value.offsetWidth
//@ts-ignore
const screenHeight = dashboardEditorRef.value.offsetHeight
baseMarginLeft.value = 10
baseMarginTop.value = 10
baseWidth.value = (screenWidth - baseMarginLeft.value) / props.baseMatrixCount.x - baseMarginLeft.value
baseHeight.value = (screenHeight - baseMarginTop.value) / props.baseMatrixCount.y - baseMarginTop.value
cellWidth.value = baseWidth.value + baseMarginLeft.value
cellHeight.value = baseHeight.value + baseMarginTop.value
}
}
onMounted(() => {
window.addEventListener('resize', sizeInit)
const erd = elementResizeDetectorMaker()
//@ts-ignore
erd.listenTo(document.getElementById(domId), () => {
restore()
})
})
defineExpose({
restore
})
</script>
<template>
<div
:id="domId"
class="canvas-container"
:style="canvasStyle"
ref="previewCanvas"
v-if="state.initState"
>
<template v-if="renderReady">
<SQComponentWrapper
v-for="(item, index) in componentData"
:active="!!curComponent && (item.id === curComponent['id'])"
:config-item="item"
:canvas-view-info="canvasStyleData"
:show-position="showPosition"
:canvas-id="canvasId"
:key="index"
:style="nowItemStyle(item)"
:index="index"
/>
</template>
</div>
</template>
<style scoped lang="less">
<style lang="less" scoped>
.canvas-container {
background-size: 100% 100% !important;
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
position: relative;
</style>
div::-webkit-scrollbar {
width: 0 !important;
height: 0 !important;
}
div {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
}
.fix-button {
position: fixed !important;
}
.datav-preview {
overflow-y: hidden !important;
}
.datav-preview-unpublish {
background-color: inherit !important;
}
</style>
@@ -3,28 +3,31 @@ import dashboardInfoSvg from '@/assets/svg/dashboard-info.svg'
import icon_pc_outlined from '@/assets/svg/icon_pc_outlined.svg'
import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg'
import DashboardDetailInfo from "@/views/dashboard/common/DashboardDetailInfo.vue";
import {dashboardStoreWithOut} from "@/stores/dashboard/dashboard.ts";
import {storeToRefs} from "pinia";
const emit = defineEmits(['reload', 'download', 'downloadAsAppTemplate'])
const dashboardStore = dashboardStoreWithOut()
const {dashboardInfo} = storeToRefs(dashboardStore)
const preview = () => {}
const edit = () =>{}
defineProps({
dashboardInfo: {
type: Object,
required: true
}
})
</script>
<template>
<div class="preview-head flex-align-center">
<div class="canvas-name ellipsis">{{ dashboardInfo.name }}</div>
<el-divider style="margin: 0 16px 0 7px" direction="vertical" />
<div class="create-area flex-align-center">
<span style="line-height: 22px"
>Creator:{{ dashboardInfo.creatorName }}</span
>
<el-divider style="margin: 5px 10px 0 17px" direction="vertical" />
<span class="create-area" style="line-height: 22px">Creator:{{ dashboardInfo.createName }}</span>
<div style="padding-top: 4px" class="create-area flex-align-center">
<el-popover show-arrow :offset="8" placement="bottom" width="400" trigger="hover">
<template #reference>
<el-icon class="info-tips"><dashboardInfoSvg class="svg-icon" /></el-icon>
</template>
<DashboardDetailInfo></DashboardDetailInfo>
<DashboardDetailInfo :dashboard-info="dashboardInfo"></DashboardDetailInfo>
</el-popover>
</div>
<div class="canvas-opt-button">
@@ -36,7 +39,7 @@ const edit = () =>{}
</el-button>
<el-button class="custom-button" type="primary" @click="edit">
<template #icon>
<icon name="icon_edit_outlined"><icon_edit_outlined class="svg-icon" /></icon>
<Icon name="icon_edit_outlined"><icon_edit_outlined class="svg-icon" /></Icon>
</template>
Edit</el-button
>
@@ -64,6 +67,7 @@ const edit = () =>{}
}
}
.preview-head {
display: flex;
width: 100%;
min-width: 300px;
height: 56px;
@@ -129,4 +133,10 @@ const edit = () =>{}
.custom-button {
margin-left: 12px;
}
.flex-align-center {
& + & {
margin-left: 4px;
}
}
</style>
@@ -1,7 +1,7 @@
<script setup lang="ts">
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
import {reactive, ref, toRefs, onBeforeMount, computed} from 'vue'
import {initCanvasData, load_resource_prepare} from '@/views/dashboard/utils/canvasUtils'
import {load_resource_prepare} from '@/views/dashboard/utils/canvasUtils'
import {Icon} from '@/components/icon-custom'
import ResourceTree from "@/views/dashboard/common/ResourceTree.vue";
import SQPreview from "@/views/dashboard/preview/SQPreview.vue";
@@ -16,10 +16,10 @@ const slideShow = ref(true)
const dataInitState = ref(true)
const downloadStatus = ref(false)
const state = reactive({
canvasDataPreview: null,
canvasStylePreview: null,
canvasViewInfoPreview: null,
dashboardInfo: null,
canvasDataPreview: [],
canvasStylePreview: {},
canvasViewInfoPreview: {},
dashboardInfo: {},
showOffset: {
top: 110,
left: 280
@@ -61,8 +61,9 @@ function createNew() {
const loadCanvasData = (params: any) => {
dataInitState.value = false
//@ts-ignore
load_resource_prepare({id:params.id}, function ({dashboardInfo, canvasDataResult, canvasStyleResult, canvasViewInfoPreview}) {
load_resource_prepare({id: params.id},
//@ts-ignore
function ({dashboardInfo, canvasDataResult, canvasStyleResult, canvasViewInfoPreview}) {
state.canvasDataPreview = canvasDataResult
state.canvasStylePreview = canvasStyleResult
state.canvasViewInfoPreview = canvasViewInfoPreview
@@ -71,12 +72,6 @@ const loadCanvasData = (params: any) => {
}
)
}
// @ts-ignore
const slideOpenChange = () => {
slideShow.value = !slideShow.value
}
const getPreviewStateInfo = () => {
return state
}
@@ -89,7 +84,7 @@ const resourceNodeClick = (prams: any) => {
loadCanvasData(prams)
}
const previewShowFlag = computed(() => !!dashboardStore.dashboardInfo?.name)
const previewShowFlag = computed(() => !!state.dashboardInfo?.name)
onBeforeMount(() => {
if (showPosition.value === 'preview') {
@@ -97,23 +92,13 @@ onBeforeMount(() => {
}
})
const sideTreeStatus = ref(true)
// @ts-ignore
const changeSideTreeStatus = val => {
sideTreeStatus.value = val
}
const freezeStyle = computed(() => [
{'--top-show-offset': state.showOffset.top},
{'--left-show-offset': state.showOffset.left}
])
defineExpose({
getPreviewStateInfo
})
</script>
<template>
<div class="dv-preview dv-teleport-query" :style="freezeStyle">
<div class="dv-preview dv-teleport-query">
<el-aside
class="resource-area"
:class="{ 'close-side': !slideShow, retract: !sideTreeStatus }"
@@ -133,16 +118,12 @@ defineExpose({
v-loading="!dataInitState"
>
<template v-if="previewShowFlag">
<SQPreviewHead @reload="reload"/>
<div
ref="previewCanvasContainer"
class="content"
id="sq-preview-content"
>
<SQPreviewHead :dashboard-info="state.dashboardInfo" @reload="reload"/>
<div ref="previewCanvasContainer" class="content" id="sq-preview-content">
<SQPreview
ref="dashboardPreview"
v-if="state.canvasStylePreview && dataInitState"
:dv-info="state.dashboardInfo"
:dashboard-info="state.dashboardInfo"
:component-data="state.canvasDataPreview"
:canvas-style-data="state.canvasStylePreview"
:canvas-view-info="state.canvasViewInfoPreview"
@@ -12,18 +12,18 @@ export const load_resource_prepare = (params: any, callBack: Function) => {
id: canvasInfo.id,
name: canvasInfo.name,
pid: canvasInfo.pid,
workspaceId: canvasInfo.workspaceId,
workspaceId: canvasInfo.workspace_id,
status: canvasInfo.status,
type: canvasInfo.type,
creatorName: canvasInfo.creatorName,
updateName: canvasInfo.updateName,
createTime: canvasInfo.createTime,
updateTime: canvasInfo.updateTime,
contentId: canvasInfo.contentId
createName: canvasInfo.create_name,
updateName: canvasInfo.update_name,
createTime: canvasInfo.create_time,
updateTime: canvasInfo.update_time,
contentId: canvasInfo.content_id
}
const canvasDataResult = JSON.parse(canvasInfo.component_data)
const canvasStyleResult = JSON.parse(canvasInfo.canvas_style_data)
const canvasViewInfoPreview = canvasInfo.canvasViewInfo
const canvasViewInfoPreview = canvasInfo.canvas_view_Info
callBack({dashboardInfo, canvasDataResult, canvasStyleResult, canvasViewInfoPreview})
})
}