mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
refactor: dashboard add item
This commit is contained in:
Vendored
-26
@@ -8,32 +8,6 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElStep: typeof import('element-plus/es')['ElStep']
|
||||
ElSteps: typeof import('element-plus/es')['ElSteps']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
Icon: typeof import('./src/components/icon-custom/src/Icon.vue')['default']
|
||||
Layout: typeof import('./src/components/layout/index.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.21",
|
||||
"snowflake-id": "^1.1.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0",
|
||||
"web-storage-cache": "^1.1.1"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747819208465" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5002" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M948.560332 281.179984c-13.765515-13.833053-36.127825-13.833053-49.89334 0L511.991302 668.591431 125.313565 281.179984c-13.763468-13.798261-36.093033-13.798261-49.856501 0-13.799284 13.798261-13.799284 36.161594 0 49.993624l410.857439 411.674037c7.067976 7.085372 16.402575 10.521634 25.675776 10.331299 9.274224 0.191358 18.608823-3.245927 25.677822-10.331299l410.891208-411.708829c6.863315-6.89913 10.331299-15.940041 10.331299-24.979928S955.423647 288.078091 948.560332 281.179984z" p-id="5003"></path></svg>
|
||||
|
After Width: | Height: | Size: 844 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="16px" height="16.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M393.390114 512.023536l347.948667-336.348468c20.50808-19.85828 20.50808-51.997258 0-71.792093-20.507056-19.826558-53.778834-19.826558-74.28589 0L281.990954 476.135164c-20.476357 19.826558-20.476357 51.981908 0 71.746044l385.061936 372.236839c10.285251 9.91379 23.728424 14.869662 37.173644 14.869662 13.446243 0 26.889417-4.956895 37.112246-14.901385 20.50808-19.826558 20.50808-51.919487 0-71.746044L393.390114 512.023536" /></svg>
|
||||
|
After Width: | Height: | Size: 697 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.833984 2.49935C0.833984 2.03911 1.20708 1.66602 1.66732 1.66602H4.16732V6.66602H19.1673V17.4993C19.1673 17.9596 18.7942 18.3327 18.334 18.3327H1.66732C1.20708 18.3327 0.833984 17.9596 0.833984 17.4993V2.49935ZM19.1673 4.99935V2.49935C19.1673 2.03911 18.7942 1.66602 18.334 1.66602H13.334V4.99935H19.1673ZM11.6673 1.66602H5.83398V4.99935H11.6673V1.66602Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 500 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.0893 1.91058C17.933 1.7543 17.721 1.6665 17.5 1.6665H2.50002C2.27901 1.6665 2.06705 1.7543 1.91076 1.91058C1.75448 2.06686 1.66669 2.27882 1.66669 2.49984V17.4998C1.66669 17.7209 1.75448 17.9328 1.91076 18.0891C2.06705 18.2454 2.27901 18.3332 2.50002 18.3332H17.5C17.721 18.3332 17.933 18.2454 18.0893 18.0891C18.2456 17.9328 18.3334 17.7209 18.3334 17.4998V2.49984C18.3334 2.27882 18.2456 2.06686 18.0893 1.91058ZM10.8334 5.83323H13.75C13.8605 5.83323 13.9665 5.87713 14.0446 5.95527C14.1228 6.03341 14.1667 6.13939 14.1667 6.2499V7.08323C14.1667 7.19374 14.1228 7.29972 14.0446 7.37786C13.9665 7.456 13.8605 7.4999 13.75 7.4999H10.8334V13.7499C10.8334 13.8046 10.8226 13.8588 10.8016 13.9094C10.7807 13.9599 10.75 14.0058 10.7113 14.0445C10.6726 14.0832 10.6267 14.1139 10.5761 14.1348C10.5256 14.1558 10.4714 14.1666 10.4167 14.1666H9.58335C9.52864 14.1666 9.47446 14.1558 9.4239 14.1348C9.37335 14.1139 9.32742 14.0832 9.28873 14.0445C9.25004 14.0058 9.21934 13.9599 9.1984 13.9094C9.17747 13.8588 9.16669 13.8046 9.16669 13.7499V7.4999H6.25002C6.13951 7.4999 6.03353 7.456 5.95539 7.37786C5.87725 7.29972 5.83335 7.19374 5.83335 7.08323V6.2499C5.83335 6.13939 5.87725 6.03341 5.95539 5.95527C6.03353 5.87713 6.13951 5.83323 6.25002 5.83323H9.16669C9.16669 5.83323 10.8334 5.85657 10.8334 5.83323Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.71952 18.0526C13.8471 18.0526 17.2237 14.8374 17.4815 10.7749C17.499 10.4994 17.2734 10.2748 16.9973 10.2748C14.5714 10.2748 12.1454 10.2748 9.71952 10.2748C9.71952 7.40872 9.71952 4.98267 9.71952 2.99669C9.71952 2.72055 9.49501 2.4954 9.21942 2.51289C5.15692 2.77069 1.94174 6.1473 1.94174 10.2748C1.94174 14.5704 5.42397 18.0526 9.71952 18.0526Z" fill="#3370FF"/>
|
||||
<path d="M12.1306 8.60807C11.7192 8.60807 11.3857 8.2746 11.3857 7.86325V2.49351C11.3857 2.19784 11.6417 1.96535 11.9329 2.01629C15.011 2.55462 17.4392 4.9828 17.9775 8.0609C18.0285 8.35215 17.796 8.60807 17.5003 8.60807H12.1306Z" fill="#00D6B9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 729 B |
@@ -4,7 +4,8 @@ import Layout from '@/components/layout/index.vue'
|
||||
import login from '@/views/login/index.vue'
|
||||
import chat from '@/views/chat/index.vue'
|
||||
import ds from '@/views/ds/index.vue'
|
||||
import DashboardEditor from '@/views/dashboard/DashboardEditor.vue'
|
||||
import DashboardEditor from '@/views/dashboard/editor/index.vue'
|
||||
import Dashboard from '@/views/dashboard/index.vue'
|
||||
import setting from '@/views/setting/index.vue'
|
||||
import { watchRouter } from './watch'
|
||||
const router = createRouter({
|
||||
@@ -55,11 +56,24 @@ const router = createRouter({
|
||||
{
|
||||
path: 'index',
|
||||
name: 'dashboard',
|
||||
component: DashboardEditor,
|
||||
component: Dashboard,
|
||||
meta: { title: 'Dashboard', icon: 'dashboard' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/dashboard-edit',
|
||||
redirect: '/dashboard-edit/index',
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: 'dashboard-edit',
|
||||
component: DashboardEditor,
|
||||
meta: { title: 'dashboard-edit', icon: 'dashboard' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/setting',
|
||||
component: Layout,
|
||||
|
||||
@@ -4,7 +4,19 @@ import {store} from "@/stores";
|
||||
export const dashboardStore = defineStore('dashboard', {
|
||||
state: () => {
|
||||
return {
|
||||
curComponent: null
|
||||
curComponent: null,
|
||||
canvasStyle: {},
|
||||
componentData: [],
|
||||
dashboardInfo: {
|
||||
id: null,
|
||||
name: 'New Dashboard',
|
||||
pid: null,
|
||||
dataState: null,
|
||||
optType: null,
|
||||
status: null,
|
||||
type: null,
|
||||
mobileLayout: false
|
||||
}
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
@@ -15,7 +27,14 @@ export const dashboardStore = defineStore('dashboard', {
|
||||
actions: {
|
||||
setCurComponent(value: any) {
|
||||
this.curComponent = value
|
||||
},
|
||||
setComponentData(value: any) {
|
||||
this.componentData = value
|
||||
},
|
||||
setCanvasStyle(value: any) {
|
||||
this.canvasStyle = value
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// @ts-ignore
|
||||
import SnowflakeID from 'snowflake-id';
|
||||
|
||||
const snowflake = new SnowflakeID({
|
||||
mid: 42,
|
||||
offset: (2010 - 1970) * 365 * 24 * 3600 * 1000
|
||||
});
|
||||
|
||||
export const guid = () => {
|
||||
return snowflake.generate();
|
||||
}
|
||||
|
||||
export interface CanvasItem {
|
||||
_dragId: string | number
|
||||
x: number
|
||||
y: number
|
||||
sizeX: number
|
||||
sizeY: number
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
|
||||
export type CanvasCoord = {
|
||||
x1: number
|
||||
y1: number
|
||||
x2: number
|
||||
y2: number
|
||||
c1: number
|
||||
c2: number
|
||||
el: {
|
||||
x: number
|
||||
y: number
|
||||
sizeX: number
|
||||
sizeY: number
|
||||
_dragId: string | number
|
||||
[key: string]: any
|
||||
}
|
||||
}
|
||||
|
||||
export type DashboardInfo = {
|
||||
dataState: string,
|
||||
optType: string,
|
||||
id: number,
|
||||
name: string,
|
||||
pid: number,
|
||||
status: number,
|
||||
type: string,
|
||||
mobileLayout: boolean,
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import DsCanvasCore from '@/views/dashboard/canvas/DsCanvasCore.vue'
|
||||
import CanvasCore from '@/views/dashboard/canvas/CanvasCore.vue'
|
||||
import { nextTick, onMounted, ref } from 'vue'
|
||||
const cyGridster = ref(null)
|
||||
const baseWidth = ref(0)
|
||||
@@ -56,14 +56,14 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DsCanvasCore
|
||||
<CanvasCore
|
||||
ref="cyGridster"
|
||||
:base-width="baseWidth"
|
||||
:base-height="baseHeight"
|
||||
:base-margin-left="baseMarginLeft"
|
||||
:base-margin-top="baseMarginTop"
|
||||
:canvas-component-data="componentData"
|
||||
></DsCanvasCore>
|
||||
></CanvasCore>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less"></style>
|
||||
|
||||
+25
-8
@@ -2,8 +2,9 @@
|
||||
import {ref, nextTick, toRefs, type PropType} from 'vue'
|
||||
import _ from 'lodash'
|
||||
import {dashboardStoreWithOut} from '@/stores/dashboard/dashboard'
|
||||
import {type CanvasCoord, type CanvasItem} from '../utils/CanvasUtils'
|
||||
import {type CanvasCoord, type CanvasItem} from '@/utils/canvas.ts'
|
||||
import CanvasShape from './CanvasShape.vue'
|
||||
import {findComponent} from "@/views/dashboard/components/component-list.ts";
|
||||
|
||||
const dashboardStore = dashboardStoreWithOut()
|
||||
|
||||
@@ -218,9 +219,19 @@ function recomputeCellWidth() {
|
||||
maxCell.value = Math.round(containerRef.value.offsetWidth / cellWidth.value)
|
||||
}
|
||||
|
||||
function init() {
|
||||
function sizeInit() {
|
||||
cellsInit()
|
||||
recomputeCellWidth()
|
||||
itemMaxX = maxCell.value
|
||||
}
|
||||
|
||||
function cellsInit() {
|
||||
cellWidth.value = baseWidth.value + baseMarginLeft.value
|
||||
cellHeight.value = baseHeight.value + baseMarginTop.value
|
||||
}
|
||||
|
||||
function init() {
|
||||
cellsInit()
|
||||
|
||||
positionBox.value = []
|
||||
coordinates.value = []
|
||||
@@ -790,7 +801,7 @@ function startMove(e: MouseEvent, item: CanvasItem, index: number) {
|
||||
moveYSize % cellHeight.value > cellHeight.value / 4
|
||||
? parseInt(String(moveYSize / cellHeight.value + 1))
|
||||
: parseInt(String(moveYSize / cellHeight.value))
|
||||
// 根据坐标点 判断resize方向
|
||||
// Determine the resizing direction based on the coordinate points
|
||||
const {
|
||||
nowSizeX,
|
||||
nowSizeY,
|
||||
@@ -943,6 +954,7 @@ function moving() {
|
||||
defineExpose({
|
||||
getRenderState,
|
||||
init,
|
||||
sizeInit,
|
||||
afterInitOk,
|
||||
addItemBox,
|
||||
getMaxCell,
|
||||
@@ -959,14 +971,19 @@ defineExpose({
|
||||
<template>
|
||||
<div class="dragAndResize" ref="containerRef" @mousedown="containerMouseDown($event)" @mouseup="endMove()"
|
||||
@mousemove="moving()">
|
||||
<div v-if="renderOk">
|
||||
<CanvasShape v-for="(item, index) in canvasComponentData" :config-item="item" :draggable="draggable"
|
||||
<template v-if="renderOk">
|
||||
<CanvasShape v-for="(item, index) in canvasComponentData"
|
||||
:config-item="item"
|
||||
:draggable="draggable"
|
||||
:item-index="index"
|
||||
:move-animate="moveAnimate" :start-move="startMove" :start-resize="startResize" :key="'item' + index"
|
||||
:move-animate="moveAnimate"
|
||||
:start-move="startMove"
|
||||
:start-resize="startResize"
|
||||
:key="'item' + index"
|
||||
:style="nowItemStyle(item)">
|
||||
<!-- {{ item }}-->
|
||||
<component class="slot-component" :is="findComponent(item.component)" :config-item="item"></component>
|
||||
</CanvasShape>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,104 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import { type CanvasItem } from '../utils/CanvasUtils'
|
||||
import { ref, toRefs, type PropType } from 'vue'
|
||||
import {type CanvasItem} from '@/utils/canvas.ts'
|
||||
import {ref, toRefs, type PropType} from 'vue'
|
||||
import ResizeHandle from "@/views/dashboard/canvas/ResizeHandle.vue";
|
||||
|
||||
const shapeRef = ref(null)
|
||||
// Props
|
||||
const props = defineProps({
|
||||
configItem: {
|
||||
type: Object as PropType<CanvasItem>,
|
||||
required: true
|
||||
},
|
||||
itemIndex: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
moveAnimate: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
startMove: {
|
||||
type: Function,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
startResize: {
|
||||
type: Function,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
configItem: {
|
||||
type: Object as PropType<CanvasItem>,
|
||||
required: true
|
||||
},
|
||||
itemIndex: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
moveAnimate: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
startMove: {
|
||||
type: Function,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
startResize: {
|
||||
type: Function,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const {
|
||||
draggable
|
||||
} = toRefs(props)
|
||||
|
||||
const cursors = {
|
||||
lt: 'nw',
|
||||
t: 'n',
|
||||
rt: 'ne',
|
||||
r: 'e',
|
||||
rb: 'se',
|
||||
b: 's',
|
||||
lb: 'sw',
|
||||
l: 'w'
|
||||
}
|
||||
|
||||
function getPointStyle(point: string) {
|
||||
const hasT = /t/.test(point)
|
||||
const hasB = /b/.test(point)
|
||||
const hasL = /l/.test(point)
|
||||
const hasR = /r/.test(point)
|
||||
let newLeft = '0px'
|
||||
let newTop = '0px'
|
||||
|
||||
// Points at the four corners
|
||||
if (point.length === 2) {
|
||||
newLeft = hasL ? '0px' : '100%'
|
||||
newTop = hasT ? '0px' : '100%'
|
||||
} else {
|
||||
// The point between the upper and lower points, with a width centered
|
||||
if (hasT || hasB) {
|
||||
newLeft = '50%'
|
||||
newTop = hasT ? '0px' : '100%'
|
||||
}
|
||||
|
||||
// The points on both sides are centered in height
|
||||
if (hasL || hasR) {
|
||||
newLeft = hasL ? '0px' : '100%'
|
||||
newTop ='50%'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
marginLeft: '-4px',
|
||||
marginTop: '-4px',
|
||||
left: `${newLeft}`,
|
||||
top: `${newTop}`,
|
||||
// @ts-expect-error
|
||||
cursor: `${cursors[point]}-resize`
|
||||
}
|
||||
}
|
||||
|
||||
const pointList = ['lt', 't', 'rt', 'r', 'rb', 'b', 'lb', 'l']
|
||||
const { draggable } = toRefs(props)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="{
|
||||
<div :class="{
|
||||
item: true,
|
||||
moveAnimation: moveAnimate,
|
||||
movingItem: configItem.isPlayer,
|
||||
canNotDrag: !draggable
|
||||
}" @mousedown="startMove($event, configItem, itemIndex)" ref="shapeRef">
|
||||
<slot></slot>
|
||||
<div v-for="point in pointList" :key="point" class="resizeHandle" :style="getPointStyle(point)"
|
||||
@mousedown="startResize($event, point, configItem, itemIndex)"></div>
|
||||
</div>
|
||||
<slot></slot>
|
||||
<resize-handle
|
||||
:start-resize="(event : MouseEvent, point: string) => startResize(event, point, configItem, itemIndex)">
|
||||
</resize-handle>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<script setup lang="ts">
|
||||
import type {PropType} from "vue";
|
||||
|
||||
defineProps({
|
||||
sizeList: {
|
||||
type: Array as PropType<number[]>,
|
||||
required: false,
|
||||
default: [12, 12, 12, 12]
|
||||
}
|
||||
})
|
||||
|
||||
const shadowStyle = (size: number, index: number) => {
|
||||
if (index === 0) {
|
||||
return {
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: `${size}px`
|
||||
}
|
||||
} else if (index === 1) {
|
||||
return {
|
||||
top: 0,
|
||||
right: 0,
|
||||
width: `${size}px`,
|
||||
height: '100%'
|
||||
}
|
||||
} else if (index === 2) {
|
||||
return {
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: `${size}px`
|
||||
}
|
||||
} else if (index === 3) {
|
||||
return {
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: `${size}px`,
|
||||
height: '100%'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dragHandle" v-for="(size,index) in sizeList" :style="shadowStyle(size,index)"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.dragHandle {
|
||||
background: #c1e2e8;
|
||||
position: absolute;
|
||||
cursor: move;
|
||||
z-index: 3;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,69 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
startResize: {
|
||||
type: Function,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
})
|
||||
const cursors = {
|
||||
lt: 'nw',
|
||||
t: 'n',
|
||||
rt: 'ne',
|
||||
r: 'e',
|
||||
rb: 'se',
|
||||
b: 's',
|
||||
lb: 'sw',
|
||||
l: 'w'
|
||||
}
|
||||
|
||||
function getPointStyle(point: string) {
|
||||
const hasT = /t/.test(point)
|
||||
const hasB = /b/.test(point)
|
||||
const hasL = /l/.test(point)
|
||||
const hasR = /r/.test(point)
|
||||
let newLeft = '0px'
|
||||
let newTop = '0px'
|
||||
|
||||
// Points at the four corners
|
||||
if (point.length === 2) {
|
||||
newLeft = hasL ? '0px' : '100%'
|
||||
newTop = hasT ? '0px' : '100%'
|
||||
} else {
|
||||
// The point between the upper and lower points, with a width centered
|
||||
if (hasT || hasB) {
|
||||
newLeft = '50%'
|
||||
newTop = hasT ? '0px' : '100%'
|
||||
}
|
||||
|
||||
// The points on both sides are centered in height
|
||||
if (hasL || hasR) {
|
||||
newLeft = hasL ? '0px' : '100%'
|
||||
newTop ='50%'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
marginLeft: '-4px',
|
||||
marginTop: '-4px',
|
||||
left: `${newLeft}`,
|
||||
top: `${newTop}`,
|
||||
// @ts-expect-error
|
||||
cursor: `${cursors[point]}-resize`
|
||||
}
|
||||
}
|
||||
|
||||
const pointList = ['lt', 't', 'rt', 'r', 'rb', 'b', 'lb', 'l']
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-for="point in pointList"
|
||||
:key="point" class="resizeHandle"
|
||||
:style="getPointStyle(point)"
|
||||
@mousedown="startResize($event, point)"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
@import '../css/CanvasStyle.less';
|
||||
</style>
|
||||
@@ -0,0 +1,77 @@
|
||||
<script setup lang="ts">
|
||||
import {toRefs} from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
title: {type: String, required: false},
|
||||
tips: {type: String, required: false},
|
||||
iconName: {type: String, required: false},
|
||||
showSplitLine: {type: Boolean, required: false, default: false},
|
||||
active: {type: Boolean, required: false, default: false},
|
||||
})
|
||||
|
||||
const {title, tips, iconName, showSplitLine} = toRefs(props)
|
||||
const emits = defineEmits(['customClick'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-align-center">
|
||||
<el-row class="group_icon" :title="tips" @click="emits('customClick')">
|
||||
<el-col :span="24" class="group_inner" :class="{ 'inner-active': active }">
|
||||
<component class="svg-icon toolbar-icon" :is="iconName"></component>
|
||||
<span>{{ title }}</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-divider class="group-right-border" v-if="showSplitLine" direction="vertical"/>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="less" scoped>
|
||||
.flex-align-center {
|
||||
& + & {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.group_inner {
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
color: #a6a6a6;
|
||||
|
||||
span {
|
||||
float: left;
|
||||
font-size: 12px;
|
||||
margin-top: 8px;
|
||||
line-height: 12px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(235, 235, 235, 0.1);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: #fff;
|
||||
background: rgba(235, 235, 235, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.group-right-border {
|
||||
border-color: rgba(255, 255, 255, 0.15);
|
||||
margin: 0 2px 0 6px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.inner-active {
|
||||
border: 1px solid var(--ed-color-primary);
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.toolbar-icon {
|
||||
float: left;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,67 @@
|
||||
import SQTab from '@/views/dashboard/components/sq-tab/index.vue'
|
||||
import SQText from '@/views/dashboard/components/sq-text/index.vue'
|
||||
import SQView from '@/views/dashboard/components/sq-view/index.vue'
|
||||
import SQEmpty from '@/views/dashboard/components/sq-empty/index.vue'
|
||||
|
||||
const COMPONENT_LIST = [
|
||||
{
|
||||
id: 1001,
|
||||
component: 'SQView',
|
||||
name: 'new-view',
|
||||
propValue: ' ',
|
||||
icon: 'icon_graphical',
|
||||
innerType: 'bar',
|
||||
x: 1,
|
||||
y: 1,
|
||||
sizeX: 36,
|
||||
sizeY: 14,
|
||||
style: {}
|
||||
},
|
||||
{
|
||||
id: 1002,
|
||||
component: 'SQTab',
|
||||
name: 'new-tabs',
|
||||
propValue: [
|
||||
{
|
||||
name: 'tab',
|
||||
title: 'new_tab',
|
||||
componentData: [],
|
||||
closable: true
|
||||
}
|
||||
],
|
||||
canvasActive: false,
|
||||
x: 1,
|
||||
y: 1,
|
||||
sizeX: 36,
|
||||
sizeY: 14,
|
||||
style: {}
|
||||
},
|
||||
{
|
||||
id: 1003,
|
||||
component: 'SQText',
|
||||
name: 'new text',
|
||||
propValue: ' ',
|
||||
x: 1,
|
||||
y: 1,
|
||||
sizeX: 36,
|
||||
sizeY: 14,
|
||||
style: {}
|
||||
}
|
||||
]
|
||||
|
||||
export function findNewComponentFromList(component: string) {
|
||||
return COMPONENT_LIST.find(item => item.component === component) || null;
|
||||
}
|
||||
|
||||
export const componentsMap = {
|
||||
SQTab: SQTab,
|
||||
SQText: SQText,
|
||||
SQView: SQView
|
||||
}
|
||||
|
||||
export function findComponent(key = 'SQEmpty') {
|
||||
//@ts-ignore
|
||||
return componentsMap[key] ? componentsMap[key] : SQEmpty
|
||||
}
|
||||
|
||||
export default COMPONENT_LIST
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div> no component can be find </div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<el-tabs :class="['de-tabs', ...tabClassName]" :style="tabStyle" v-bind="$attrs">
|
||||
<slot></slot>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
const props = defineProps({
|
||||
hideTitle: Boolean,
|
||||
/* 颜色可以单词,如red;也可以是颜色值 */
|
||||
// 字体颜色
|
||||
fontColor: String,
|
||||
// 激活字体颜色
|
||||
activeColor: String,
|
||||
// 边框颜色 如果是none就无边框 如果是none Card类型激活的下滑线也消失
|
||||
borderColor: String,
|
||||
// 激活边框颜色 目前只针对card类型
|
||||
borderActiveColor: String,
|
||||
// 样式类型 radioGroup只在Card类型有效, 同时必须给borderColor borderActiveColor
|
||||
styleType: {
|
||||
type: String,
|
||||
default: '',
|
||||
validator: (val: string) => ['', 'radioGroup'].includes(val)
|
||||
}
|
||||
})
|
||||
|
||||
const tabStyle = computed(() => [
|
||||
{ '--de-font-color': props.fontColor },
|
||||
{ '--de-active-color': props.activeColor },
|
||||
{ '--de-border-color': props.borderColor },
|
||||
{ '--de-border-active-color': props.borderActiveColor }
|
||||
])
|
||||
const tabClassName = computed(() =>
|
||||
props.styleType
|
||||
? [props.styleType, props.fontColor && 'fontColor', props.activeColor && 'activeColor']
|
||||
: [
|
||||
props.fontColor && 'fontColor',
|
||||
props.activeColor && 'activeColor',
|
||||
noBorder.value ? 'noBorder' : props.borderColor && 'borderColor',
|
||||
props.borderActiveColor && 'borderActiveColor',
|
||||
props.hideTitle && 'no-header'
|
||||
]
|
||||
)
|
||||
|
||||
const noBorder = computed(() => props.borderColor === 'none')
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.de-tabs {
|
||||
height: 100%;
|
||||
&.no-header {
|
||||
.ed-tabs__header {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.ed-tabs--card {
|
||||
> .ed-tabs__header {
|
||||
height: auto !important;
|
||||
}
|
||||
}
|
||||
&.fontColor {
|
||||
.ed-tabs__item {
|
||||
color: var(--de-font-color);
|
||||
|
||||
&.is-active {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.activeColor {
|
||||
.ed-tabs__item {
|
||||
&.is-active {
|
||||
color: var(--de-active-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--de-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
.ed-tabs__active-bar {
|
||||
height: 0px;
|
||||
background-color: var(--de-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
// card样式的边框
|
||||
&.noBorder.ed-tabs--card {
|
||||
> .ed-tabs__header {
|
||||
border-bottom: none;
|
||||
|
||||
.ed-tabs__nav {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ed-tabs__item {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.ed-tabs__item.is-active {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.borderActiveColor.ed-tabs--card {
|
||||
> .ed-tabs__header .ed-tabs__item.is-active {
|
||||
border-bottom-color: var(--de-border-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.borderColor.ed-tabs--card {
|
||||
> .ed-tabs__header {
|
||||
border-bottom-color: var(--de-border-color);
|
||||
|
||||
.ed-tabs__nav {
|
||||
border-color: var(--de-border-color);
|
||||
}
|
||||
|
||||
.ed-tabs__item {
|
||||
border-left-color: var(--de-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
.ed-tabs__item {
|
||||
&.is-active {
|
||||
color: var(--de-active-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--de-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
.ed-tabs__active-bar {
|
||||
height: 0px;
|
||||
background-color: var(--de-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
// 简洁样式的边框
|
||||
&.noBorder {
|
||||
.ed-tabs__nav-wrap::after {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.borderColor {
|
||||
.ed-tabs__nav-wrap::after {
|
||||
background: var(--de-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
// radioGroup 类型
|
||||
&.radioGroup.ed-tabs--card {
|
||||
> .ed-tabs__header {
|
||||
border-bottom: none;
|
||||
|
||||
.ed-tabs__nav {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ed-tabs__item {
|
||||
border: 1px solid var(--de-border-color);
|
||||
border-right: 0;
|
||||
|
||||
&:first-child {
|
||||
border-left: 1px solid var(--de-border-color);
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-right: 1px solid var(--de-border-color);
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
border: 1px solid var(--de-border-active-color);
|
||||
|
||||
& + .ed-tabs__item {
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,167 @@
|
||||
<script setup lang="ts">
|
||||
import {computed, type PropType, reactive, ref, toRefs, nextTick} from 'vue'
|
||||
import CustomTab from "@/views/dashboard/components/sq-tab/CustomTab.vue";
|
||||
import {guid, type CanvasItem,} from "@/utils/canvas.ts";
|
||||
import DragHandle from "@/views/dashboard/canvas/DragHandle.vue";
|
||||
import {ArrowDown} from "@element-plus/icons-vue";
|
||||
|
||||
const editableTabsValue = ref(null)
|
||||
const showTabTitleFlag = ref(true)
|
||||
const props = defineProps({
|
||||
configItem: {
|
||||
type: Object as PropType<CanvasItem>,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const {configItem} = toRefs(props)
|
||||
|
||||
const state = reactive({
|
||||
activeTabName: '',
|
||||
curItem: {},
|
||||
textarea: '',
|
||||
dialogVisible: false,
|
||||
tabShow: true,
|
||||
hoverFlag: false,
|
||||
headFontColor: '#OOOOOO',
|
||||
headFontActiveColor: '#OOOOOO',
|
||||
headBorderColor: '#OOOOOO',
|
||||
headBorderActiveColor: '#OOOOOO'
|
||||
})
|
||||
|
||||
function addTab() {
|
||||
const newName = guid()
|
||||
|
||||
const newTab = {
|
||||
name: newName,
|
||||
title: 'New Tab',
|
||||
componentData: [],
|
||||
closable: true
|
||||
}
|
||||
configItem.value.propValue.push(newTab)
|
||||
editableTabsValue.value = newTab.name
|
||||
}
|
||||
|
||||
function deleteCur(param:any) {
|
||||
state.curItem = param
|
||||
let len = configItem.value.propValue.length
|
||||
while (len--) {
|
||||
if (configItem.value.propValue[len].name === param.name) {
|
||||
configItem.value.propValue.splice(len, 1)
|
||||
const activeIndex =
|
||||
(len - 1 + configItem.value.propValue.length) % configItem.value.propValue.length
|
||||
editableTabsValue.value = configItem.value.propValue[activeIndex].name
|
||||
state.tabShow = false
|
||||
nextTick(() => {
|
||||
state.tabShow = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function editCurTitle(param:any) {
|
||||
state.activeTabName = param.name
|
||||
state.curItem = param
|
||||
state.textarea = param.title
|
||||
state.dialogVisible = true
|
||||
}
|
||||
|
||||
function handleCommand(command:any) {
|
||||
switch (command.command) {
|
||||
case 'editTitle':
|
||||
editCurTitle(command.param)
|
||||
break
|
||||
case 'deleteCur':
|
||||
deleteCur(command.param)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const beforeHandleCommand = (item : any, param : any) => {
|
||||
return {
|
||||
command: item,
|
||||
param: param
|
||||
}
|
||||
}
|
||||
|
||||
const titleStyle = (itemName: string) => {
|
||||
if (editableTabsValue.value === itemName) {
|
||||
return {}
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
const isEditMode = computed(() => true)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<drag-handle></drag-handle>
|
||||
<custom-tab
|
||||
v-model="editableTabsValue"
|
||||
@tab-add="addTab"
|
||||
:addable="isEditMode"
|
||||
:font-color="state.headFontColor"
|
||||
:active-color="state.headFontActiveColor"
|
||||
:border-color="state.headBorderColor"
|
||||
:border-active-color="state.headBorderActiveColor"
|
||||
:hide-title="!showTabTitleFlag"
|
||||
>
|
||||
<template :key="tabItem.name" v-for="tabItem in configItem.propValue">
|
||||
<el-tab-pane
|
||||
class="el-tab-pane-custom"
|
||||
:lazy="isEditMode"
|
||||
:label="tabItem.title"
|
||||
:name="tabItem.name"
|
||||
>
|
||||
<template #label>
|
||||
<div class="custom-tab-title" @mousedown.stop>
|
||||
<span class="title-inner" :style="titleStyle(tabItem.name)"
|
||||
>{{ tabItem.title }}
|
||||
<span v-if="isEditMode">
|
||||
<el-dropdown
|
||||
popper-class="custom-de-tab-dropdown"
|
||||
trigger="click"
|
||||
@command="handleCommand"
|
||||
>
|
||||
<span class="el-dropdown-link">
|
||||
<el-icon v-if="isEditMode"><ArrowDown/></el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item :command="beforeHandleCommand('editTitle', tabItem)">
|
||||
edit
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item :command="beforeHandleCommand('copyCur', tabItem)">
|
||||
copy
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="configItem.propValue.length > 1"
|
||||
:command="beforeHandleCommand('deleteCur', tabItem)"
|
||||
>
|
||||
delete
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</template>
|
||||
<div>
|
||||
this is a tab
|
||||
</div>
|
||||
</custom-tab>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.el-dropdown-link{
|
||||
margin-top: 3px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
@@ -2,6 +2,7 @@
|
||||
{
|
||||
position: relative;
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
*
|
||||
{
|
||||
box-sizing: border-box;
|
||||
@@ -24,7 +25,7 @@
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
z-index: 0;
|
||||
z-index: 5;
|
||||
}
|
||||
}
|
||||
.moveAnimation
|
||||
@@ -65,6 +66,9 @@
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
.slot-component {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.positionBox
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<script setup lang="ts">
|
||||
import CanvasCore from '@/views/dashboard/canvas/CanvasCore.vue'
|
||||
import {nextTick, onMounted, ref} from 'vue'
|
||||
import type {CanvasItem} from "@/utils/canvas.ts";
|
||||
|
||||
const canvasCoreRef = ref(null)
|
||||
const dashboardEditorRef = ref(null)
|
||||
const baseWidth = ref(0)
|
||||
const baseHeight = ref(0)
|
||||
const baseMarginLeft = ref(0)
|
||||
const baseMarginTop = ref(0)
|
||||
const baseMatrixCount = {
|
||||
x: 72,
|
||||
y: 36
|
||||
}
|
||||
const componentData = ref([
|
||||
{
|
||||
id: 4,
|
||||
x: 1,
|
||||
y: 1,
|
||||
sizeX: 20,
|
||||
sizeY: 10,
|
||||
_dragId: 0
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
x: 2,
|
||||
y: 1,
|
||||
sizeX: 20,
|
||||
sizeY: 10,
|
||||
_dragId: 1
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
x: 1,
|
||||
y: 2,
|
||||
sizeX: 20,
|
||||
sizeY: 10,
|
||||
_dragId: 2
|
||||
}
|
||||
])
|
||||
|
||||
const canvasSizeInit = () => {
|
||||
sizeInit()
|
||||
if (canvasCoreRef.value) {
|
||||
//@ts-ignore
|
||||
canvasCoreRef.value.sizeInit()
|
||||
}
|
||||
}
|
||||
|
||||
const sizeInit = () => {
|
||||
if (dashboardEditorRef.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) / baseMatrixCount.x - baseMarginLeft.value
|
||||
baseHeight.value = (screenHeight - baseMarginTop.value) / baseMatrixCount.y - baseMarginTop.value
|
||||
}
|
||||
}
|
||||
|
||||
const addItemToBox = (item: CanvasItem) => {
|
||||
// @ts-ignore
|
||||
console.log(componentData.value.length + '===' + JSON.stringify(componentData.value))
|
||||
// @ts-ignore
|
||||
canvasCoreRef.value.addItemBox(item)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
canvasSizeInit,
|
||||
addItemToBox
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', canvasSizeInit)
|
||||
nextTick(() => {
|
||||
if (dashboardEditorRef.value) {
|
||||
sizeInit()
|
||||
// @ts-ignore
|
||||
nextTick(() => {
|
||||
if (canvasCoreRef.value) {
|
||||
// @ts-ignore
|
||||
canvasCoreRef.value.init()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class='dashboard-editor-main' ref="dashboardEditorRef">
|
||||
<CanvasCore
|
||||
ref="canvasCoreRef"
|
||||
:base-width="baseWidth"
|
||||
:base-height="baseHeight"
|
||||
:base-margin-left="baseMarginLeft"
|
||||
:base-margin-top="baseMarginTop"
|
||||
:canvas-component-data="componentData"
|
||||
></CanvasCore>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.dashboard-editor-main {
|
||||
width: 100%;
|
||||
height: calc(100% - 56px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,68 @@
|
||||
<script setup lang="ts">
|
||||
import {dashboardStoreWithOut} from "@/stores/dashboard/dashboard.ts";
|
||||
import {storeToRefs} from 'pinia'
|
||||
import IconBack from '@/assets/svg/common-back.svg'
|
||||
import ComponentButtonLabel from "@/views/dashboard/components/button-label/ComponentButtonLabel.vue";
|
||||
import dvTab from '@/assets/svg/dv-tab.svg'
|
||||
import dvText from '@/assets/svg/dv-text.svg'
|
||||
import dvView from '@/assets/svg/dv-view.svg'
|
||||
|
||||
const dashboardStore = dashboardStoreWithOut()
|
||||
const {dashboardInfo} = storeToRefs(dashboardStore)
|
||||
const emits = defineEmits(['addComponent'])
|
||||
|
||||
const openViewDialog = () => {
|
||||
// do addComponent
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="toolbar-main">
|
||||
<span>
|
||||
<el-icon><IconBack/></el-icon>
|
||||
</span>
|
||||
<span>{{ dashboardInfo.name }}</span>
|
||||
<div class="core-toolbar">
|
||||
<component-button-label
|
||||
:icon-name="dvView"
|
||||
title="Add View"
|
||||
themes="light"
|
||||
is-label
|
||||
@customClick="openViewDialog"
|
||||
></component-button-label>
|
||||
<component-button-label
|
||||
:icon-name="dvText"
|
||||
title="Text"
|
||||
themes="light"
|
||||
is-label
|
||||
@customClick="() =>emits('addComponent', 'SQText')"
|
||||
></component-button-label>
|
||||
<component-button-label
|
||||
:icon-name="dvTab"
|
||||
title="Tab Item"
|
||||
themes="light"
|
||||
is-label
|
||||
@customClick="() =>emits('addComponent', 'SQTab')"
|
||||
>
|
||||
</component-button-label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.toolbar-main {
|
||||
width: 100%;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #050e21;
|
||||
padding-left: 8px;
|
||||
.core-toolbar {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import {ref} from 'vue'
|
||||
import Toolbar from "@/views/dashboard/editor/Toolbar.vue";
|
||||
import DashboardEditor from "@/views/dashboard/editor/DashboardEditor.vue";
|
||||
import {findNewComponentFromList} from "@/views/dashboard/components/component-list.ts";
|
||||
import {guid} from "@/utils/canvas.ts";
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
|
||||
|
||||
const dashboardEditorRef = ref(null);
|
||||
const addComponent = (componentType : string) => {
|
||||
const component = cloneDeep(findNewComponentFromList(componentType))
|
||||
if (component && dashboardEditorRef.value) {
|
||||
component.id = guid()
|
||||
//@ts-ignore
|
||||
dashboardEditorRef.value.addItemToBox(component)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="editor-main">
|
||||
<Toolbar @add-component="addComponent"></Toolbar>
|
||||
<DashboardEditor ref="dashboardEditorRef"></DashboardEditor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.editor-main {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: calc(100vh - 61px);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
@@ -1,26 +0,0 @@
|
||||
export interface CanvasItem {
|
||||
_dragId: string | number
|
||||
x: number
|
||||
y: number
|
||||
sizeX: number
|
||||
sizeY: number
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
|
||||
export type CanvasCoord = {
|
||||
x1: number
|
||||
y1: number
|
||||
x2: number
|
||||
y2: number
|
||||
c1: number
|
||||
c2: number
|
||||
el: {
|
||||
x: number
|
||||
y: number
|
||||
sizeX: number
|
||||
sizeY: number
|
||||
_dragId: string | number
|
||||
[key: string]: any
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user