22 changed files with 1767 additions and 23 deletions
|
After Width: | Height: | Size: 4.1 KiB |
@ -0,0 +1,130 @@ |
|||
import {LicenseManager} from "ag-grid-enterprise" |
|||
|
|||
var a = [ |
|||
'QBPDn8KZAMK+QkJGRiN+acK9woEbwq' + |
|||
'HDs8OYHhDCsCLDpA5FX8KSw5DDs8Oc' + |
|||
'aXnDocOkw7VKfMKEw47DnHYew4QFw7' + |
|||
'7CrQDDg1I3wqDDl8Kow41fH33CpTLC' + |
|||
'ocO9CsKbw53CvsK6XTDCncKbwplJw7' + |
|||
'UsHU4ffcOfYMKdwo19dALCm8KCwq15' + |
|||
'wrfDjgTDosOZw4rDk8KrBQJgHxw+dM' + |
|||
'KHwrzCtUQ8PsOMNMKvf8OrwojDuXDC' + |
|||
'ssOxOcKswqbDnMOewpEmw6Ncw4oLw7' + |
|||
'Y/MRXCmcKMdsKTw4rDiXHCv0NyPTx0' + |
|||
'wqhKdw/CmcOqw5V2ZsOOwrk+wr4UOs' + |
|||
'KmccORd8KEXWh0KDjCgm3DgcOtwq05' + |
|||
'w7FgKDljZwrCiHPCpHsZwo0GwrdWw5' + |
|||
'rDpMOYKcOoJGtZw4jCpkIjwq/CrMOL' + |
|||
'wr9UPMKlMcObWxXDlTHClmvCqsOiwp' + |
|||
'XDmTZKNBnDvMODwrfDuUDCrgXDgWFm' + |
|||
'w7zDnWFNwpgawqQ9LsK9wpwhdcK3Vs' + |
|||
'OnUMOiLRAwwrgvw5fCoxLClcOzw7vD' + |
|||
'tcOVUMONwqfDrjtZEcOnwrwLO3DCpc' + |
|||
'Khwp3ChcOCwrt8w642w4nChEDDqMOi' + |
|||
'w5/Dg3R9w43DqlrDvmjCoT3DmC8vb8' + |
|||
'KiwqkWw5PCtMKCwrcbw4TCq0sPwrIS' + |
|||
'w6EwDHnDtCnCg2AxwpMnI8OCC8OFw7' + |
|||
'7Csxhow5oBHXHCnmvDrA/DhivDvMOK' + |
|||
'ecOvw75CRVzDnlc3w7TDm8O5BnfDos' + |
|||
'KhwrU/w4bDnsKHei4Uw5JZw5zDpsKA' + |
|||
'W8Oiw4jCg3UWD8O3chR7bCfCoTTCns' + |
|||
'OCV8KeJ2pnJ2NvwosEdxLCnnEsDMOH' + |
|||
'wpF/RFprwoUzCVHDvFbCgcOtFzVICM' + |
|||
'OJbcK4w4LDjMKofsOLH8KCwrfDhGzC' + |
|||
'hMOAw5fChX/CqsO3w4Jaw4jCrz3DrM' + |
|||
'KLCcOhw5lVwojDlsKrw63DoxJmwodM' + |
|||
'wp7DmcO8wr9COSXDtcKrwrpcw5IRec' + |
|||
'OwWMOSFMOBFCYBwrkew5VEwrIUIcO7' + |
|||
'Fzl1w4TCjcKufMO6AcKUwqjCtnbCum' + |
|||
'89AwBtwqPDgn3DsMK8w5jCssOxw7fC' + |
|||
'iHsgIwLDtsKNPwjCmMK+HcKowoZjw6' + |
|||
'F/wqpEwrsjw6zDp0VjflPCgcO0JMOO' + |
|||
'w5Aww6FTBTpJf1vCmXwvcsKfRmk2dC' + |
|||
'zDnMK7Fhkpwq7DvMKFNsOqZ0/Cl3cZ' + |
|||
'dsKUwr5+w5rCl27Cj1g0HMOywr/Cq8' + |
|||
'KxZgrDhsKOw5bCiFIKwp7DjcOJwpU1' + |
|||
'CcKaT3rDhS9xwoY1wokFwqTDncKLw7' + |
|||
'gKasKHwqNbbBJRIhB+TMOvGcKzF1HD' + |
|||
'o8OAwp4FEHjDvng5wrx7wobCtw==', |
|||
'wrPDoXXCm8KDJw5wwqQSCy/Dlg==' |
|||
]; |
|||
(function (b, e) { |
|||
var f = function (g) { |
|||
while (--g) { |
|||
b['push'](b['shift']()); |
|||
} |
|||
}; |
|||
f(++e); |
|||
}(a, 0x1bf)); |
|||
var b = function (c, d) { |
|||
c = c - 0x0; |
|||
var e = a[c]; |
|||
if (b['ngETWK'] === undefined) { |
|||
(function () { |
|||
var h = function () { |
|||
var k; |
|||
try { |
|||
k = Function('return\x20(function()\x20' + '{}.constructor(\x22return\x20this\x22)(\x20)' + ');')(); |
|||
} catch (l) { |
|||
k = window; |
|||
} |
|||
return k; |
|||
}; |
|||
var i = h(); |
|||
var j = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; |
|||
i['atob'] || (i['atob'] = function (k) { |
|||
var l = String(k)['replace'](/=+$/, ''); |
|||
var m = ''; |
|||
for (var n = 0x0, o=0, p, q = 0x0; p = l['charAt'](q++); ~p && (o = n % 0x4 ? o * 0x40 + p : p, n++ % 0x4) ? m += String['fromCharCode'](0xff & o >> (-0x2 * n & 0x6)) : 0x0) { |
|||
p = j['indexOf'](p); |
|||
} |
|||
return m; |
|||
}); |
|||
}()); |
|||
var g = function (h, l) { |
|||
var m = [], n = 0x0, o, p = '', q = ''; |
|||
h = atob(h); |
|||
for (var t = 0x0, u = h['length']; t < u; t++) { |
|||
q += '%' + ('00' + h['charCodeAt'](t)['toString'](0x10))['slice'](-0x2); |
|||
} |
|||
h = decodeURIComponent(q); |
|||
var r; |
|||
for (r = 0x0; r < 0x100; r++) { |
|||
m[r] = r; |
|||
} |
|||
for (r = 0x0; r < 0x100; r++) { |
|||
n = (n + m[r] + l['charCodeAt'](r % l['length'])) % 0x100; |
|||
o = m[r]; |
|||
m[r] = m[n]; |
|||
m[n] = o; |
|||
} |
|||
r = 0x0; |
|||
n = 0x0; |
|||
for (var v = 0x0; v < h['length']; v++) { |
|||
r = (r + 0x1) % 0x100; |
|||
n = (n + m[r]) % 0x100; |
|||
o = m[r]; |
|||
m[r] = m[n]; |
|||
m[n] = o; |
|||
p += String['fromCharCode'](h['charCodeAt'](v) ^ m[(m[r] + m[n]) % 0x100]); |
|||
} |
|||
return p; |
|||
}; |
|||
b['sXjMae'] = g; |
|||
b['NsblKa'] = {}; |
|||
b['ngETWK'] = !![]; |
|||
} |
|||
var f = b['NsblKa'][c]; |
|||
if (f === undefined) { |
|||
if (b['Fwjnqi'] === undefined) { |
|||
b['Fwjnqi'] = !![]; |
|||
} |
|||
e = b['sXjMae'](e, d); |
|||
b['NsblKa'][c] = e; |
|||
} else { |
|||
e = f; |
|||
} |
|||
return e; |
|||
}; |
|||
LicenseManager[b('0x0', '!ZqR')](b('0x1', '%xiU')); |
|||
|
|||
@ -0,0 +1,34 @@ |
|||
<template> |
|||
<div :class="classes" style=""> |
|||
<slot></slot> |
|||
</div> |
|||
</template> |
|||
<script lang="ts"> |
|||
import { getCurrentInstance, defineComponent, type SetupContext, watch } from 'vue' |
|||
|
|||
export default defineComponent({ |
|||
name: 'SplitArea', |
|||
props: { |
|||
size: { |
|||
type: Number, |
|||
default: 50 |
|||
}, |
|||
minSize: { |
|||
type: Number, |
|||
default: 100 |
|||
} |
|||
}, |
|||
setup(props, ctx: SetupContext) { |
|||
}, |
|||
computed: { |
|||
classes(): string { |
|||
const parent = getCurrentInstance()?.parent |
|||
const a = parent?.props |
|||
return `split split-area split-` + a?.direction |
|||
} |
|||
} |
|||
|
|||
}) |
|||
</script> |
|||
<style> |
|||
</style> |
|||
@ -0,0 +1,188 @@ |
|||
<template> |
|||
<div class="split" ref="parent"> |
|||
<slot></slot> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
//@ts-ignore |
|||
import Split from 'split.js' |
|||
import { defineComponent, onMounted, ref, type SetupContext, type VNode, watch } from 'vue' |
|||
|
|||
interface IDataContainer { |
|||
instance: any; |
|||
elements: Array<any> | undefined; |
|||
sizes: Array<number> | undefined; |
|||
minSizes: Array<number> | undefined; |
|||
destroy: Function, |
|||
} |
|||
|
|||
//@ts-ignore |
|||
export default defineComponent({ |
|||
emits: ['onDrag', 'onDragStart', 'onDragEnd'], |
|||
props: { |
|||
direction: { type: String, default: 'horizontal' }, // vertical |
|||
gutterSize: { type: Number, default: 8 }, |
|||
firstAreaDefaultSize: Number, |
|||
lastAreaDefaultSize: Number |
|||
}, |
|||
|
|||
setup(props, ctx: SetupContext) { |
|||
const parent = ref(null) |
|||
const dataVal = { |
|||
elements: new Array<any>(), |
|||
sizes: new Array<number>(), |
|||
minSizes: new Array<number>(), |
|||
instance: null, |
|||
//@ts-ignore |
|||
destory: Function |
|||
} |
|||
|
|||
//@ts-ignore |
|||
const data = ref(dataVal as IDataContainer) |
|||
watch(() => props.direction, (value, oldValue) => { |
|||
init() |
|||
}) |
|||
let useFirstDefaultSize = props.firstAreaDefaultSize && props.firstAreaDefaultSize > 0 |
|||
let useLastDefaultSize = props.lastAreaDefaultSize && props.lastAreaDefaultSize > 0 |
|||
let splitSumCount = 0 |
|||
const init = () => { |
|||
if (data.value.instance !== null) { |
|||
data.value.instance?.destroy() |
|||
} |
|||
let splitCount = 0 |
|||
data.value.instance = null |
|||
const splitOptions = { |
|||
direction: props.direction || 'horizontal', |
|||
sizes: data.value.sizes || 50, |
|||
minSize: data.value.minSizes || 100, |
|||
gutterSize: props.gutterSize || 8, |
|||
cursor: props.direction === 'horizontal' ? 'col-resize' : 'row-resize', |
|||
onDrag: function() { |
|||
useFirstDefaultSize = false |
|||
useLastDefaultSize = false |
|||
ctx.emit('onDrag', data.value.instance?.getSizes()) |
|||
}, |
|||
onDragStart: function() { |
|||
ctx.emit('onDragStart', data.value.instance?.getSizes()) |
|||
}, |
|||
onDragEnd: function() { |
|||
ctx.emit('onDragEnd', data.value.instance?.getSizes()) |
|||
} |
|||
} |
|||
if (useFirstDefaultSize) { |
|||
splitOptions['elementStyle'] = function elementStyle(dimension, size, gutterSize) { |
|||
splitCount++ |
|||
let res |
|||
if (splitSumCount === 2 && useFirstDefaultSize && !useLastDefaultSize) { |
|||
// 2个split-area & 使用firstAreaDefaultSize & 未使用lastAreaDefaultSize |
|||
if (splitCount === 1) { |
|||
res = { [dimension]: `calc(${props.firstAreaDefaultSize}px - ${gutterSize}px)` } |
|||
} else { |
|||
res = { [dimension]: `calc(100% - ${props.firstAreaDefaultSize + gutterSize}px)` } |
|||
} |
|||
} else if (splitSumCount === 2 && !useFirstDefaultSize && useLastDefaultSize) { |
|||
// 2个split-area & 未使用firstAreaDefaultSize & 使用了lastAreaDefaultSize |
|||
if (splitCount === 2) { |
|||
res = { [dimension]: `calc(${props.lastAreaDefaultSize}px - ${gutterSize}px)` } |
|||
} else { |
|||
res = { [dimension]: `calc(100% - ${props.lastAreaDefaultSize + gutterSize}px)` } |
|||
} |
|||
} else if (splitSumCount === 3 && useFirstDefaultSize && useLastDefaultSize) { |
|||
// 3个split-area & 使用firstAreaDefaultSize & 使用了lastAreaDefaultSize |
|||
if (splitCount === 1) { |
|||
res = { [dimension]: `calc(${props.firstAreaDefaultSize}px - ${gutterSize}px)` } |
|||
} else if (splitCount === 3) { |
|||
res = { [dimension]: `calc(${props.lastAreaDefaultSize}px - ${gutterSize}px)` } |
|||
} else { |
|||
res = { [dimension]: `calc(100% - ${props.firstAreaDefaultSize + props.lastAreaDefaultSize + gutterSize}px)` } |
|||
} |
|||
} else { |
|||
res = { [dimension]: `calc(${size}% - ${gutterSize}px)` } |
|||
} |
|||
return res |
|||
} |
|||
} |
|||
//@ts-ignore |
|||
data.value.instance = Split(data.value.elements ?? [], |
|||
splitOptions as Split.Options |
|||
) |
|||
} |
|||
onMounted(() => { |
|||
data.value.elements = [] |
|||
data.value.sizes = [] |
|||
data.value.minSizes = [] |
|||
var parentVal = parent.value as unknown as HTMLElement |
|||
|
|||
if (parentVal) { |
|||
for (var i = 0; i < parentVal.children.length; i++) { |
|||
var child = parentVal.children[i] |
|||
data.value.elements.push(child) |
|||
} |
|||
} |
|||
if (ctx.slots.default) { |
|||
ctx.slots.default()?.forEach((vnode: VNode) => { |
|||
const vodeType = vnode.type as any |
|||
if (vodeType.name == 'SplitArea') { |
|||
if (vnode.props) { |
|||
const a = vnode.props as { |
|||
size: number; |
|||
minSize: number; |
|||
} |
|||
data.value.sizes?.push(a.size) |
|||
data.value.minSizes?.push(a.minSize) |
|||
} |
|||
} |
|||
}) |
|||
splitSumCount = ctx.slots.default().length |
|||
} |
|||
init() |
|||
}) |
|||
|
|||
const reset = () => { |
|||
useFirstDefaultSize = props.firstAreaDefaultSize && props.firstAreaDefaultSize > 0 |
|||
useLastDefaultSize = props.lastAreaDefaultSize && props.lastAreaDefaultSize > 0 |
|||
init() |
|||
} |
|||
const getSizes = () => { |
|||
return data.value.instance?.getSizes() || 0 |
|||
} |
|||
|
|||
return { data, init, parent, reset, getSizes } |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.split { |
|||
-webkit-box-sizing: border-box; |
|||
-moz-box-sizing: border-box; |
|||
box-sizing: border-box; |
|||
overflow-y: auto; |
|||
overflow-x: hidden; |
|||
height: 100%; |
|||
width: 100%; |
|||
} |
|||
|
|||
.gutter { |
|||
background-color: #eee; |
|||
background-repeat: no-repeat; |
|||
background-position: 50%; |
|||
} |
|||
|
|||
.gutter.gutter-horizontal { |
|||
cursor: col-resize; |
|||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=="); |
|||
} |
|||
|
|||
.gutter.gutter-vertical { |
|||
cursor: row-resize; |
|||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII="); |
|||
} |
|||
|
|||
.split.split-horizontal, |
|||
.gutter.gutter-horizontal { |
|||
height: 100%; |
|||
float: left; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,47 @@ |
|||
import { camelize } from "../util/string"; |
|||
import { events, isReadOnly } from "./sortableEvents"; |
|||
import { isHtmlAttribute } from "../util/tags"; |
|||
|
|||
function project(entries) { |
|||
return entries.reduce((res, [key, value]) => { |
|||
res[key] = value; |
|||
return res; |
|||
}, {}); |
|||
} |
|||
|
|||
function getComponentAttributes({ $attrs, componentData = {} }) { |
|||
const attributes = project( |
|||
Object.entries($attrs).filter(([key, _]) => isHtmlAttribute(key)) |
|||
); |
|||
return { |
|||
...attributes, |
|||
...componentData |
|||
}; |
|||
} |
|||
|
|||
function createSortableOption({ $attrs, callBackBuilder }) { |
|||
const options = project(getValidSortableEntries($attrs)); |
|||
Object.entries(callBackBuilder).forEach(([eventType, eventBuilder]) => { |
|||
events[eventType].forEach(event => { |
|||
options[`on${event}`] = eventBuilder(event); |
|||
}); |
|||
}); |
|||
const draggable = `[data-draggable]${options.draggable || ""}`; |
|||
return { |
|||
...options, |
|||
draggable |
|||
}; |
|||
} |
|||
|
|||
function getValidSortableEntries(value) { |
|||
return Object.entries(value) |
|||
.filter(([key, _]) => !isHtmlAttribute(key)) |
|||
.map(([key, value]) => [camelize(key), value]) |
|||
.filter(([key, _]) => !isReadOnly(key)); |
|||
} |
|||
|
|||
export { |
|||
getComponentAttributes, |
|||
createSortableOption, |
|||
getValidSortableEntries |
|||
}; |
|||
@ -0,0 +1,78 @@ |
|||
//const getHtmlElementFromNode = ({ el }) => el;
|
|||
const getHtmlElementFromNode = node => { |
|||
const el = |
|||
node.el || (Array.isArray(node.children) && node.children[0].el.parentNode); |
|||
if (!el) { |
|||
console.error("使用 transition-group , 需要在slot中template内至少2层html标签"); |
|||
} |
|||
return el || {}; |
|||
}; |
|||
|
|||
const addContext = (domElement, context) => |
|||
(domElement.__draggable_context = context); |
|||
const getContext = domElement => domElement.__draggable_context; |
|||
|
|||
class ComponentStructure { |
|||
constructor({ |
|||
nodes: { header, default: defaultNodes, footer }, |
|||
root, |
|||
realList |
|||
}) { |
|||
this.defaultNodes = defaultNodes; |
|||
this.children = [...header, ...defaultNodes, ...footer]; |
|||
this.externalComponent = root.externalComponent; |
|||
this.rootTransition = root.transition; |
|||
this.tag = root.tag; |
|||
this.realList = realList; |
|||
} |
|||
|
|||
get _isRootComponent() { |
|||
return this.externalComponent || this.rootTransition; |
|||
} |
|||
|
|||
render(h, attributes) { |
|||
const { tag, children, _isRootComponent } = this; |
|||
const option = !_isRootComponent ? children : { default: () => children }; |
|||
return h(tag, attributes, option); |
|||
} |
|||
|
|||
updated() { |
|||
const { defaultNodes, realList } = this; |
|||
defaultNodes.forEach((node, index) => { |
|||
addContext(getHtmlElementFromNode(node), { |
|||
element: realList[index], |
|||
index |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
getUnderlyingVm(domElement) { |
|||
return getContext(domElement); |
|||
} |
|||
|
|||
getVmIndexFromDomIndex(domIndex, element) { |
|||
const { defaultNodes } = this; |
|||
const { length } = defaultNodes; |
|||
const domChildren = element.children; |
|||
const domElement = domChildren.item(domIndex); |
|||
|
|||
if (domElement === null) { |
|||
return length; |
|||
} |
|||
const context = getContext(domElement); |
|||
if (context) { |
|||
return context.index; |
|||
} |
|||
|
|||
if (length === 0) { |
|||
return 0; |
|||
} |
|||
const firstDomListElement = getHtmlElementFromNode(defaultNodes[0]); |
|||
const indexFirstDomListElement = [...domChildren].findIndex( |
|||
element => element === firstDomListElement |
|||
); |
|||
return domIndex < indexFirstDomListElement ? 0 : length; |
|||
} |
|||
} |
|||
|
|||
export { ComponentStructure }; |
|||
@ -0,0 +1,56 @@ |
|||
import { ComponentStructure } from "./componentStructure"; |
|||
import { isHtmlTag, isTransition } from "../util/tags"; |
|||
import { resolveComponent, TransitionGroup } from "vue"; |
|||
|
|||
function getSlot(slots, key) { |
|||
const slotValue = slots[key]; |
|||
return slotValue ? slotValue() : []; |
|||
} |
|||
|
|||
function computeNodes({ $slots, realList, getKey }) { |
|||
const normalizedList = realList || []; |
|||
const [header, footer] = ["header", "footer"].map(name => |
|||
getSlot($slots, name) |
|||
); |
|||
const { item } = $slots; |
|||
if (!item) { |
|||
throw new Error("draggable element must have an item slot"); |
|||
} |
|||
const defaultNodes = normalizedList.flatMap((element, index) => |
|||
item({ element, index }).map(node => { |
|||
node.key = getKey(element); |
|||
node.props = { ...(node.props || {}), "data-draggable": true }; |
|||
return node; |
|||
}) |
|||
); |
|||
if (defaultNodes.length !== normalizedList.length) { |
|||
throw new Error("Item slot must have only one child"); |
|||
} |
|||
return { |
|||
header, |
|||
footer, |
|||
default: defaultNodes |
|||
}; |
|||
} |
|||
|
|||
function getRootInformation(tag) { |
|||
const transition = isTransition(tag); |
|||
const externalComponent = !isHtmlTag(tag) && !transition; |
|||
return { |
|||
transition, |
|||
externalComponent, |
|||
tag: externalComponent |
|||
? resolveComponent(tag) |
|||
: transition |
|||
? TransitionGroup |
|||
: tag |
|||
}; |
|||
} |
|||
|
|||
function computeComponentStructure({ $slots, tag, realList, getKey }) { |
|||
const nodes = computeNodes({ $slots, realList, getKey }); |
|||
const root = getRootInformation(tag); |
|||
return new ComponentStructure({ nodes, root, realList }); |
|||
} |
|||
|
|||
export { computeComponentStructure }; |
|||
@ -0,0 +1,18 @@ |
|||
const manageAndEmit = ["Start", "Add", "Remove", "Update", "End"]; |
|||
const emit = ["Choose", "Unchoose", "Sort", "Filter", "Clone"]; |
|||
const manage = ["Move"]; |
|||
const eventHandlerNames = [manage, manageAndEmit, emit] |
|||
.flatMap(events => events) |
|||
.map(evt => `on${evt}`); |
|||
|
|||
const events = { |
|||
manage, |
|||
manageAndEmit, |
|||
emit |
|||
}; |
|||
|
|||
function isReadOnly(eventName) { |
|||
return eventHandlerNames.indexOf(eventName) !== -1; |
|||
} |
|||
|
|||
export { events, isReadOnly }; |
|||
@ -0,0 +1,9 @@ |
|||
function getConsole() { |
|||
if (typeof window !== "undefined") { |
|||
return window.console; |
|||
} |
|||
return global.console; |
|||
} |
|||
const console = getConsole(); |
|||
|
|||
export { console }; |
|||
@ -0,0 +1,15 @@ |
|||
function removeNode(node) { |
|||
if (node.parentElement !== null) { |
|||
node.parentElement.removeChild(node); |
|||
} |
|||
} |
|||
|
|||
function insertNodeAt(fatherNode, node, position) { |
|||
const refNode = |
|||
position === 0 |
|||
? fatherNode.children[0] |
|||
: fatherNode.children[position - 1].nextSibling; |
|||
fatherNode.insertBefore(node, refNode); |
|||
} |
|||
|
|||
export { insertNodeAt, removeNode }; |
|||
@ -0,0 +1,12 @@ |
|||
function cached(fn) { |
|||
const cache = Object.create(null); |
|||
return function cachedFn(str) { |
|||
const hit = cache[str]; |
|||
return hit || (cache[str] = fn(str)); |
|||
}; |
|||
} |
|||
|
|||
const regex = /-(\w)/g; |
|||
const camelize = cached(str => str.replace(regex, (_, c) => c.toUpperCase())); |
|||
|
|||
export { camelize }; |
|||
@ -0,0 +1,138 @@ |
|||
const tags = [ |
|||
"a", |
|||
"abbr", |
|||
"address", |
|||
"area", |
|||
"article", |
|||
"aside", |
|||
"audio", |
|||
"b", |
|||
"base", |
|||
"bdi", |
|||
"bdo", |
|||
"blockquote", |
|||
"body", |
|||
"br", |
|||
"button", |
|||
"canvas", |
|||
"caption", |
|||
"cite", |
|||
"code", |
|||
"col", |
|||
"colgroup", |
|||
"data", |
|||
"datalist", |
|||
"dd", |
|||
"del", |
|||
"details", |
|||
"dfn", |
|||
"dialog", |
|||
"div", |
|||
"dl", |
|||
"dt", |
|||
"em", |
|||
"embed", |
|||
"fieldset", |
|||
"figcaption", |
|||
"figure", |
|||
"footer", |
|||
"form", |
|||
"h1", |
|||
"h2", |
|||
"h3", |
|||
"h4", |
|||
"h5", |
|||
"h6", |
|||
"head", |
|||
"header", |
|||
"hgroup", |
|||
"hr", |
|||
"html", |
|||
"i", |
|||
"iframe", |
|||
"img", |
|||
"input", |
|||
"ins", |
|||
"kbd", |
|||
"label", |
|||
"legend", |
|||
"li", |
|||
"link", |
|||
"main", |
|||
"map", |
|||
"mark", |
|||
"math", |
|||
"menu", |
|||
"menuitem", |
|||
"meta", |
|||
"meter", |
|||
"nav", |
|||
"noscript", |
|||
"object", |
|||
"ol", |
|||
"optgroup", |
|||
"option", |
|||
"output", |
|||
"p", |
|||
"param", |
|||
"picture", |
|||
"pre", |
|||
"progress", |
|||
"q", |
|||
"rb", |
|||
"rp", |
|||
"rt", |
|||
"rtc", |
|||
"ruby", |
|||
"s", |
|||
"samp", |
|||
"script", |
|||
"section", |
|||
"select", |
|||
"slot", |
|||
"small", |
|||
"source", |
|||
"span", |
|||
"strong", |
|||
"style", |
|||
"sub", |
|||
"summary", |
|||
"sup", |
|||
"svg", |
|||
"table", |
|||
"tbody", |
|||
"td", |
|||
"template", |
|||
"textarea", |
|||
"tfoot", |
|||
"th", |
|||
"thead", |
|||
"time", |
|||
"title", |
|||
"tr", |
|||
"track", |
|||
"u", |
|||
"ul", |
|||
"var", |
|||
"video", |
|||
"wbr" |
|||
]; |
|||
|
|||
function isHtmlTag(name) { |
|||
return tags.includes(name); |
|||
} |
|||
|
|||
function isTransition(name) { |
|||
return ["transition-group", "TransitionGroup"].includes(name); |
|||
} |
|||
|
|||
function isHtmlAttribute(value) { |
|||
return ( |
|||
["id", "class", "role", "style"].includes(value) || |
|||
value.startsWith("data-") || |
|||
value.startsWith("aria-") || |
|||
value.startsWith("on") |
|||
); |
|||
} |
|||
|
|||
export { isHtmlTag, isHtmlAttribute, isTransition }; |
|||
@ -0,0 +1,318 @@ |
|||
import Sortable from "sortablejs"; |
|||
import {insertNodeAt, removeNode} from "./util/htmlHelper"; |
|||
import {console} from "./util/console"; |
|||
import {createSortableOption, getComponentAttributes, getValidSortableEntries} from "./core/componentBuilderHelper"; |
|||
import {computeComponentStructure} from "./core/renderHelper"; |
|||
import {events} from "./core/sortableEvents"; |
|||
import {defineComponent, h, nextTick} from "vue"; |
|||
|
|||
function emit(evtName, evtData) { |
|||
evtData.realList = this.list // 罗一帆 2024-01-20 增加参数
|
|||
nextTick(() => this.$emit(evtName.toLowerCase(), evtData)); |
|||
} |
|||
|
|||
function manage(evtName) { |
|||
return (evtData, originalElement) => { |
|||
if (this.realList !== null) { |
|||
return this[`onDrag${evtName}`](evtData, originalElement); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
function manageAndEmit(evtName) { |
|||
const delegateCallBack = manage.call(this, evtName); |
|||
return (evtData, originalElement) => { |
|||
delegateCallBack.call(this, evtData, originalElement); |
|||
emit.call(this, evtName, evtData); |
|||
}; |
|||
} |
|||
|
|||
let draggingElement = null; |
|||
|
|||
const props = { |
|||
list: { |
|||
type: Array, |
|||
required: false, |
|||
default: null |
|||
}, |
|||
modelValue: { |
|||
type: Array, |
|||
required: false, |
|||
default: null |
|||
}, |
|||
itemKey: { |
|||
type: [String, Function], |
|||
required: true |
|||
}, |
|||
clone: { |
|||
type: Function, |
|||
default: original => { |
|||
return original; |
|||
} |
|||
}, |
|||
tag: { |
|||
type: String, |
|||
default: "div" |
|||
}, |
|||
move: { |
|||
type: Function, |
|||
default: null |
|||
}, |
|||
componentData: { |
|||
type: Object, |
|||
required: false, |
|||
default: null |
|||
} |
|||
}; |
|||
|
|||
const emits = [ |
|||
"update:modelValue", |
|||
"change", |
|||
...[...events.manageAndEmit, ...events.emit].map(evt => evt.toLowerCase()) |
|||
]; |
|||
|
|||
const draggableComponent = defineComponent({ |
|||
name: "draggable", |
|||
|
|||
inheritAttrs: false, |
|||
|
|||
props, |
|||
|
|||
emits, |
|||
|
|||
data() { |
|||
return { |
|||
error: false |
|||
}; |
|||
}, |
|||
|
|||
render() { |
|||
try { |
|||
this.error = false; |
|||
const {$slots, $attrs, tag, componentData, realList, getKey} = this; |
|||
const componentStructure = computeComponentStructure({ |
|||
$slots, |
|||
tag, |
|||
realList, |
|||
getKey |
|||
}); |
|||
this.componentStructure = componentStructure; |
|||
const attributes = getComponentAttributes({$attrs, componentData}); |
|||
return componentStructure.render(h, attributes); |
|||
} catch (err) { |
|||
this.error = true; |
|||
return h("pre", {style: {color: "red"}}, err.stack); |
|||
} |
|||
}, |
|||
|
|||
created() { |
|||
if (this.list !== null && this.modelValue !== null) { |
|||
console.error( |
|||
"modelValue and list props are mutually exclusive! Please set one or another." |
|||
); |
|||
} |
|||
}, |
|||
|
|||
mounted() { |
|||
if (this.error) { |
|||
return; |
|||
} |
|||
|
|||
const {$attrs, $el, componentStructure} = this; |
|||
componentStructure.updated(); |
|||
|
|||
const sortableOptions = createSortableOption({ |
|||
$attrs, |
|||
callBackBuilder: { |
|||
manageAndEmit: event => manageAndEmit.call(this, event), |
|||
emit: event => emit.bind(this, event), |
|||
manage: event => manage.call(this, event) |
|||
} |
|||
}); |
|||
const targetDomElement = $el.nodeType === 1 ? $el : $el.parentElement; |
|||
this._sortable = new Sortable(targetDomElement, sortableOptions); |
|||
this.targetDomElement = targetDomElement; |
|||
targetDomElement.__draggable_component__ = this; |
|||
}, |
|||
|
|||
updated() { |
|||
this.componentStructure.updated(); |
|||
}, |
|||
|
|||
beforeUnmount() { |
|||
if (this._sortable !== undefined) this._sortable.destroy(); |
|||
}, |
|||
|
|||
computed: { |
|||
realList() { |
|||
const {list} = this; |
|||
return list ? list : this.modelValue; |
|||
}, |
|||
|
|||
getKey() { |
|||
const {itemKey} = this; |
|||
if (typeof itemKey === "function") { |
|||
return itemKey; |
|||
} |
|||
return element => element[itemKey]; |
|||
} |
|||
}, |
|||
|
|||
watch: { |
|||
$attrs: { |
|||
handler(newOptionValue) { |
|||
const {_sortable} = this; |
|||
if (!_sortable) return; |
|||
getValidSortableEntries(newOptionValue).forEach(([key, value]) => { |
|||
_sortable.option(key, value); |
|||
}); |
|||
}, |
|||
deep: true |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
getUnderlyingVm(domElement) { |
|||
return this.componentStructure.getUnderlyingVm(domElement) || null; |
|||
}, |
|||
|
|||
getUnderlyingPotencialDraggableComponent(htmElement) { |
|||
//TODO check case where you need to see component children
|
|||
return htmElement.__draggable_component__; |
|||
}, |
|||
|
|||
emitChanges(evt) { |
|||
nextTick(() => this.$emit("change", evt)); |
|||
}, |
|||
|
|||
alterList(onList) { |
|||
if (this.list) { |
|||
onList(this.list); |
|||
return; |
|||
} |
|||
const newList = [...this.modelValue]; |
|||
onList(newList); |
|||
this.$emit("update:modelValue", newList); |
|||
}, |
|||
|
|||
spliceList() { |
|||
// @ts-ignore
|
|||
const spliceList = list => list.splice(...arguments); |
|||
this.alterList(spliceList); |
|||
}, |
|||
|
|||
updatePosition(oldIndex, newIndex) { |
|||
const updatePosition = list => |
|||
list.splice(newIndex, 0, list.splice(oldIndex, 1)[0]); |
|||
this.alterList(updatePosition); |
|||
}, |
|||
|
|||
getRelatedContextFromMoveEvent({to, related}) { |
|||
const component = this.getUnderlyingPotencialDraggableComponent(to); |
|||
if (!component) { |
|||
return {component}; |
|||
} |
|||
const list = component.realList; |
|||
const context = {list, component}; |
|||
if (to !== related && list) { |
|||
const destination = component.getUnderlyingVm(related) || {}; |
|||
return {...destination, ...context}; |
|||
} |
|||
return context; |
|||
}, |
|||
|
|||
getVmIndexFromDomIndex(domIndex) { |
|||
return this.componentStructure.getVmIndexFromDomIndex( |
|||
domIndex, |
|||
this.targetDomElement |
|||
); |
|||
}, |
|||
|
|||
onDragStart(evt) { |
|||
this.context = this.getUnderlyingVm(evt.item); |
|||
evt.item._underlying_vm_ = this.clone(this.context.element); |
|||
draggingElement = evt.item; |
|||
}, |
|||
|
|||
onDragAdd(evt) { |
|||
const element = evt.item._underlying_vm_; |
|||
if (element === undefined) { |
|||
return; |
|||
} |
|||
removeNode(evt.item); |
|||
const newIndex = this.getVmIndexFromDomIndex(evt.newIndex); |
|||
// @ts-ignore
|
|||
this.spliceList(newIndex, 0, element); |
|||
const added = {element, newIndex}; |
|||
this.emitChanges({added}); |
|||
}, |
|||
|
|||
onDragRemove(evt) { |
|||
//insertNodeAt(this.$el, evt.item, evt.oldIndex);
|
|||
insertNodeAt(evt.from, evt.item, evt.oldIndex); |
|||
if (evt.pullMode === "clone") { |
|||
removeNode(evt.clone); |
|||
return; |
|||
} |
|||
const {index: oldIndex, element} = this.context; |
|||
// @ts-ignore
|
|||
this.spliceList(oldIndex, 1); |
|||
const removed = {element, oldIndex}; |
|||
this.emitChanges({removed}); |
|||
}, |
|||
|
|||
onDragUpdate(evt) { |
|||
removeNode(evt.item); |
|||
insertNodeAt(evt.from, evt.item, evt.oldIndex); |
|||
const oldIndex = this.context.index; |
|||
const newIndex = this.getVmIndexFromDomIndex(evt.newIndex); |
|||
this.updatePosition(oldIndex, newIndex); |
|||
const moved = {element: this.context.element, oldIndex, newIndex}; |
|||
this.emitChanges({moved}); |
|||
}, |
|||
|
|||
computeFutureIndex(relatedContext, evt) { |
|||
if (!relatedContext.element) { |
|||
return 0; |
|||
} |
|||
const domChildren = [...evt.to.children].filter( |
|||
el => el.style["display"] !== "none" |
|||
); |
|||
const currentDomIndex = domChildren.indexOf(evt.related); |
|||
const currentIndex = relatedContext.component.getVmIndexFromDomIndex( |
|||
currentDomIndex |
|||
); |
|||
const draggedInList = domChildren.indexOf(draggingElement) !== -1; |
|||
return draggedInList || !evt.willInsertAfter |
|||
? currentIndex |
|||
: currentIndex + 1; |
|||
}, |
|||
|
|||
onDragMove(evt, originalEvent) { |
|||
const {move, realList} = this; |
|||
if (!move || !realList) { |
|||
return true; |
|||
} |
|||
|
|||
const relatedContext = this.getRelatedContextFromMoveEvent(evt); |
|||
const futureIndex = this.computeFutureIndex(relatedContext, evt); |
|||
const draggedContext = { |
|||
realList, // 罗一帆 2024-01-20 增加参数
|
|||
...this.context, |
|||
futureIndex |
|||
}; |
|||
const sendEvent = { |
|||
...evt, |
|||
relatedContext, |
|||
draggedContext |
|||
}; |
|||
return move(sendEvent, originalEvent); |
|||
}, |
|||
|
|||
onDragEnd() { |
|||
draggingElement = null; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
export default draggableComponent; |
|||
@ -0,0 +1,19 @@ |
|||
import { defineAsyncComponent } from 'vue' |
|||
import Split from './split/split.vue' |
|||
import SplitArea from './split/split-area.vue' |
|||
import draggable from './vuedraggable/vuedraggable' |
|||
|
|||
export const install = function(Vue: any) { |
|||
Vue.component('ag-grid-vue', defineAsyncComponent(() => { |
|||
return Promise.all([ |
|||
import('ag-grid-vue3'), |
|||
import ('./ag_grid_license') |
|||
]).then(([module, license]) => { |
|||
return module.AgGridVue |
|||
}) |
|||
})) |
|||
|
|||
Vue.component('draggable', draggable) |
|||
Vue.component('split', Split) |
|||
Vue.component('split-area', SplitArea) |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
import _ from 'lodash' |
|||
import {type Component, h, toRaw} from 'vue' |
|||
import {ElIcon} from "element-plus" |
|||
import * as FaIcon from '@vicons/fa' |
|||
import * as ElementPlusIconsVue from '@element-plus/icons-vue' |
|||
|
|||
/** |
|||
* 渲染图标 |
|||
*/ |
|||
export function renderIcon(icon: string, props = {}): any { |
|||
if (!icon) { |
|||
return undefined; |
|||
} |
|||
let component: any = undefined; |
|||
if (typeof icon === 'string') { |
|||
if (icon.startsWith("element ")) { |
|||
icon = icon.substring("element ".length); |
|||
component = ElementPlusIconsVue[icon]; |
|||
|
|||
} else if (icon.startsWith("fa ")) { |
|||
icon = icon.substring("fa ".length); |
|||
component = FaIcon[icon]; |
|||
|
|||
// } else if (icon.startsWith('tb ')) {
|
|||
// icon = icon.substring("fa ".length);
|
|||
// component = Tabler[icon];
|
|||
|
|||
} else { |
|||
component = ElementPlusIconsVue[icon]; |
|||
if (!component) component = FaIcon[icon]; |
|||
} |
|||
} |
|||
if (!component) { |
|||
// component = AntdIcon["ProfileOutlined"];
|
|||
return undefined; |
|||
} |
|||
return () => h(ElIcon, props, {default: () => h(component)}); |
|||
} |
|||
@ -0,0 +1,232 @@ |
|||
.app-wrap{ |
|||
height: 100%; |
|||
overflow: hidden; |
|||
display: flex; |
|||
flex-direction: column; |
|||
.app-header{ |
|||
height:50px; |
|||
background: #545c64; |
|||
flex-shrink: 0; |
|||
display: flex; |
|||
flex-direction: row; |
|||
overflow: hidden; |
|||
.logo{ |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0 20px; |
|||
} |
|||
.el-menu-item{ |
|||
line-height: 50px; |
|||
} |
|||
.el-menu--horizontal{ |
|||
height: 50px; |
|||
flex:1; |
|||
border: none; |
|||
&>.el-menu-item{ |
|||
height: 50px; |
|||
} |
|||
&>.el-sub-menu { |
|||
height: 50px; |
|||
.el-sub-menu__title{ |
|||
height: 50px; |
|||
} |
|||
} |
|||
} |
|||
.user{ |
|||
display: flex; |
|||
flex-direction: row; |
|||
align-items: center; |
|||
margin-right: 10px; |
|||
&>span{ |
|||
display: inline-flex; |
|||
padding:5px; |
|||
background: #f4c521; |
|||
border-radius:15px; |
|||
color:#fff; |
|||
} |
|||
} |
|||
} |
|||
.app-section{ |
|||
flex:1; |
|||
display: flex; |
|||
flex-direction: row; |
|||
.btns-toolbar{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
.btns{ |
|||
.item{ |
|||
height: 48px; |
|||
line-height: 48px; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
font-size: 14px; |
|||
&:hover{ |
|||
background: #cccccc; |
|||
} |
|||
&.selected{ |
|||
background: #e8e8e8; |
|||
position: relative; |
|||
&:before{ |
|||
content: ''; |
|||
position: absolute; |
|||
width: 3px; |
|||
height: 100%; |
|||
background: #f4c521; |
|||
left:0; |
|||
top:0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.btns-top{ |
|||
flex:1; |
|||
} |
|||
.btns-bottom{ |
|||
|
|||
} |
|||
} |
|||
.btns-toolbar-left{ |
|||
flex-shrink: 0; |
|||
width:50px; |
|||
border-right:1px solid #dcdcdc |
|||
} |
|||
.btns-toolbar-right{ |
|||
flex-shrink: 0; |
|||
width:50px; |
|||
border-left:1px solid #dcdcdc; |
|||
&.btns-toolbar{ |
|||
.btns .item.selected:before{ |
|||
right:0; |
|||
left:auto; |
|||
} |
|||
} |
|||
} |
|||
.section{ |
|||
flex:1; |
|||
overflow: hidden; |
|||
.section-item-wrap{ |
|||
height: 100%; |
|||
&>.title{ |
|||
border-bottom:1px solid #dcdcdc; |
|||
height: 35px; |
|||
line-height: 35px; |
|||
padding:0 0 0 10px; |
|||
font-size: 14px; |
|||
} |
|||
} |
|||
.section-tabs.el-tabs--card{ |
|||
height: 100%; |
|||
&>.el-tabs__header{ |
|||
box-sizing: border-box; |
|||
z-index: 0; |
|||
margin:0; |
|||
&>.el-tabs__nav-wrap{ |
|||
margin-bottom:0 |
|||
} |
|||
.el-tabs__item.is-active{ |
|||
position: relative; |
|||
z-index: 1; |
|||
&:before{ |
|||
content: ''; |
|||
width: 100%; |
|||
height: 1px; |
|||
background: #c61429; |
|||
position: absolute; |
|||
left:0; |
|||
top:0; |
|||
z-index: 999; |
|||
} |
|||
&:after{ |
|||
content: ''; |
|||
width: 100%; |
|||
height: 1px; |
|||
background: #fff; |
|||
position: absolute; |
|||
left:0; |
|||
bottom:0; |
|||
z-index: 999; |
|||
} |
|||
&:hover{ |
|||
&:after{ |
|||
background:#c5c5c5; |
|||
} |
|||
} |
|||
} |
|||
.el-tabs__item{ |
|||
border-bottom:0; |
|||
} |
|||
.el-tabs__nav-prev{ |
|||
height: 40px; |
|||
background: #c9c9c9; |
|||
.el-icon{ |
|||
color:#c61429 |
|||
} |
|||
} |
|||
.el-tabs__nav-next{ |
|||
height: 40px; |
|||
background: #c9c9c9; |
|||
.el-icon{ |
|||
color:#c61429 |
|||
} |
|||
} |
|||
} |
|||
&>.el-tabs__content{ |
|||
flex:1; |
|||
&>.el-tab-pane{ |
|||
height: 100%; |
|||
} |
|||
.section-canvas{ |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
.section-toolbar{ |
|||
flex-shrink: 0; |
|||
height: 30px; |
|||
display: flex; |
|||
align-items: center; |
|||
.el-button{ |
|||
margin-left: 5px; |
|||
} |
|||
.section-toolbar-line{ |
|||
width: 1px; |
|||
height: 16px; |
|||
background: #dcdcdc; |
|||
margin:0 5px; |
|||
} |
|||
&.section-bottom-toolbar{ |
|||
justify-content: space-between; |
|||
.section-toolbar-left{ |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
.section-toolbar-right{ |
|||
display: flex; |
|||
flex-direction: row; |
|||
align-items: center; |
|||
.infor{ |
|||
background: #000; |
|||
margin:0 5px; |
|||
color:#fff; |
|||
font-size: 12px; |
|||
min-width: 120px; |
|||
text-align: center; |
|||
padding:3px 5px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.section-content{ |
|||
flex:1; |
|||
background: #e0e0e0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.el-popper .el-divider--horizontal{ |
|||
margin:5px 0; |
|||
border-color:#656668 |
|||
} |
|||
@ -0,0 +1,208 @@ |
|||
<template> |
|||
<div class="app-wrap"> |
|||
<div class="app-header"> |
|||
<div class="logo"><img :src="Logo" alt="" style="height: 30px;width: 169px"></div> |
|||
<el-menu |
|||
:default-active="activeIndex" |
|||
class="el-menu-demo" |
|||
mode="horizontal" |
|||
background-color="#545c64" |
|||
text-color="#fff" |
|||
active-text-color="#ffd04b" |
|||
@select="handleSelect" |
|||
> |
|||
<el-sub-menu index="1"> |
|||
<template #title>文件模型</template> |
|||
<el-menu-item index="1-1">新建模型</el-menu-item> |
|||
<el-menu-item index="1-2">保存</el-menu-item> |
|||
<el-divider></el-divider> |
|||
<el-menu-item index="1-3">导出</el-menu-item> |
|||
<el-menu-item index="1-4">导入</el-menu-item> |
|||
<el-divider></el-divider> |
|||
<el-menu-item index="1-5">退出</el-menu-item> |
|||
</el-sub-menu> |
|||
<el-sub-menu index="2"> |
|||
<template #title>编辑</template> |
|||
<el-menu-item index="2-1">查找</el-menu-item> |
|||
<el-divider></el-divider> |
|||
<el-menu-item index="2-2">复制</el-menu-item> |
|||
<el-menu-item index="2-3">粘贴</el-menu-item> |
|||
<el-menu-item index="2-4">删除</el-menu-item> |
|||
</el-sub-menu> |
|||
<el-sub-menu index="3"> |
|||
<template #title>仿真</template> |
|||
<el-menu-item index="3-1">开始仿真</el-menu-item> |
|||
<el-divider></el-divider> |
|||
<el-menu-item index="3-2">停止仿真</el-menu-item> |
|||
<el-divider></el-divider> |
|||
<el-menu-item index="3-3">暂停</el-menu-item> |
|||
<el-menu-item index="3-4">继续</el-menu-item> |
|||
<el-menu-item index="3-5">仿真速度X1</el-menu-item> |
|||
<el-menu-item index="3-6">仿真速度X2</el-menu-item> |
|||
<el-menu-item index="3-7">仿真速度X3</el-menu-item> |
|||
<el-menu-item index="3-8">仿真速度X4</el-menu-item> |
|||
<el-menu-item index="3-9">仿真速度X5</el-menu-item> |
|||
</el-sub-menu> |
|||
<el-menu-item index="4">基础数据</el-menu-item> |
|||
<el-menu-item index="5">小工具</el-menu-item> |
|||
</el-menu> |
|||
<div class="user"> |
|||
<span> |
|||
<component :is="renderIcon('element User')"></component> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
<div class="app-section"> |
|||
<div class="btns-toolbar btns-toolbar-left"> |
|||
<div class="btns btns-top"> |
|||
<div :class="['item',sectionLeftTitle==='模型'?'selected':'']" @click="btnLeftMe('模型')">模型</div> |
|||
<div :class="['item',sectionLeftTitle==='监控'?'selected':'']" @click="btnLeftMe('监控')">监控</div> |
|||
<div :class="['item',sectionLeftTitle==='对象'?'selected':'']" @click="btnLeftMe('对象')">对象</div> |
|||
</div> |
|||
<div class="btns btns-bottom"> |
|||
<div :class="['item',sectionBottomTitle==='任务'?'selected':'']" @click="btnBottomMe('任务')">任务</div> |
|||
<div :class="['item',sectionBottomTitle==='日志'?'selected':'']" @click="btnBottomMe('控制')">日志</div> |
|||
<div :class="['item',sectionBottomTitle==='脚本'?'selected':'']" @click="btnBottomMe('监控')">脚本</div> |
|||
</div> |
|||
</div> |
|||
<Split class="section" :direction="'vertical'" style="flex-shrink: 0;flex-grow:1;"> |
|||
<SplitArea :class="['section-top']" :size="100 - defaultSize"> |
|||
<Split class="section" :direction="'horizontal'" style="flex-shrink: 0;flex-grow:1;"> |
|||
<SplitArea :class="['section-left']" :style="{width:sectionLeft}" :size="sectionLeftSize"> |
|||
<div class="section-item-wrap"> |
|||
<div class="title">{{ sectionLeftTitle }}</div> |
|||
</div> |
|||
</SplitArea> |
|||
<SplitArea :class="['section-center']" :size="100 - sectionLeftSize - sectionRightSize"> |
|||
<el-tabs type="card" class="section-tabs"> |
|||
<el-tab-pane label="标签1"> |
|||
<div class="section-canvas"> |
|||
<div class="section-top-toolbar section-toolbar"> |
|||
<el-button type="primary" :icon="renderIcon('element TopLeft')" link></el-button> |
|||
<span class="section-toolbar-line"></span> |
|||
<el-button type="primary" :icon="renderIcon('element TopRight')" link></el-button> |
|||
<span class="section-toolbar-line"></span> |
|||
<el-button type="primary" :icon="renderIcon('icon5 Resize')" link>尺寸</el-button> |
|||
<span class="section-toolbar-line"></span> |
|||
<el-button type="primary" :icon="renderIcon('antd SwitcherOutlined')" link>图层</el-button> |
|||
<span class="section-toolbar-line"></span> |
|||
<el-button type="primary" :icon="renderIcon('element Setting')" link>设置</el-button> |
|||
</div> |
|||
<div class="section-content"></div> |
|||
<div class="section-bottom-toolbar section-toolbar"> |
|||
<div class="section-toolbar-left"> |
|||
<el-button type="primary" :icon="renderIcon('fa MousePointer')" link></el-button> |
|||
<span class="section-toolbar-line"></span> |
|||
<el-button type="primary" :icon="renderIcon('element Aim')" link></el-button> |
|||
<span class="section-toolbar-line"></span> |
|||
<el-button type="primary" :icon="renderIcon('antd LineOutlined')" link></el-button> |
|||
<span class="section-toolbar-line"></span> |
|||
<el-button type="primary" :icon="renderIcon('icon5 BandageSharp')" link></el-button> |
|||
<span class="section-toolbar-line"></span> |
|||
<el-button type="primary" :icon="renderIcon('antd InsertRowLeftOutlined')" link></el-button> |
|||
</div> |
|||
<div class="section-toolbar-right"> |
|||
<el-button type="primary" size="small" round>清空选择</el-button> |
|||
<div class="infor"> |
|||
X=14.091,Y=12.397 |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</el-tab-pane> |
|||
<el-tab-pane label="标签2">标签2</el-tab-pane> |
|||
<el-tab-pane label="标签3">标签3</el-tab-pane> |
|||
<el-tab-pane label="标签4">标签4</el-tab-pane> |
|||
<el-tab-pane label="标签5">标签5</el-tab-pane> |
|||
<el-tab-pane label="标签6">标签6</el-tab-pane> |
|||
<el-tab-pane label="标签7">标签7</el-tab-pane> |
|||
<el-tab-pane label="标签8">标签8</el-tab-pane> |
|||
</el-tabs> |
|||
</SplitArea> |
|||
<SplitArea :class="['section-right']" :style="{width:sectionRight}" :size="sectionRightSize"> |
|||
<div class="section-item-wrap"> |
|||
<div class="title">{{ sectionRightTitle }}</div> |
|||
</div> |
|||
</SplitArea> |
|||
</Split> |
|||
</SplitArea> |
|||
<SplitArea :class="['section-bottom']" :style="{height:appMenuHeight}" :size="defaultSize"> |
|||
<div class="section-item-wrap"> |
|||
<div class="title">{{ sectionBottomTitle }}</div> |
|||
</div> |
|||
</SplitArea> |
|||
</Split> |
|||
<div class="btns-toolbar btns-toolbar-right"> |
|||
<div class="btns btns-top"> |
|||
<div :class="['item',sectionRightTitle==='属性'?'selected':'']" @click="btnRightMe('属性')">属性</div> |
|||
<div :class="['item',sectionRightTitle==='数据'?'selected':'']" @click="btnRightMe('数据')">数据</div> |
|||
<div :class="['item',sectionRightTitle==='警告'?'selected':'']" @click="btnRightMe('警告')">警告</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import './ModelMain.less' |
|||
import Logo from '@/assets/images/logo.png' |
|||
import Split from '@/components/split/split.vue' |
|||
import SplitArea from '@/components/split/split-area.vue' |
|||
import { renderIcon } from '@/utils/webutils.js' |
|||
|
|||
export default { |
|||
components: { |
|||
Split, |
|||
SplitArea |
|||
}, |
|||
mounted() { |
|||
}, |
|||
data() { |
|||
return { |
|||
Logo, |
|||
activeIndex: '', |
|||
defaultSize: 30, |
|||
appMenuHeight: '300px', |
|||
sectionLeft: '300px', |
|||
sectionRight: '300px', |
|||
sectionLeftSize: 20, |
|||
sectionRightSize: 20, |
|||
sectionLeftTitle: '模型', |
|||
sectionRightTitle: '属性', |
|||
sectionBottomTitle: '任务' |
|||
} |
|||
}, |
|||
methods: { |
|||
renderIcon, |
|||
handleSelect() { |
|||
|
|||
}, |
|||
btnLeftMe(name) { |
|||
if (this.sectionLeftTitle === name) { |
|||
this.sectionLeft = '0' |
|||
this.sectionLeftTitle = '' |
|||
} else { |
|||
this.sectionLeftTitle = name |
|||
this.sectionLeft = '300px' |
|||
} |
|||
}, |
|||
btnRightMe(name) { |
|||
if (this.sectionRightTitle === name) { |
|||
this.sectionRight = '0' |
|||
this.sectionRightTitle = '' |
|||
} else { |
|||
this.sectionRightTitle = name |
|||
this.sectionRight = '300px' |
|||
} |
|||
}, |
|||
btnBottomMe(name) { |
|||
if (this.sectionBottomTitle === name) { |
|||
this.appMenuHeight = '0' |
|||
this.sectionBottomTitle = '' |
|||
} else { |
|||
this.sectionBottomTitle = name |
|||
this.appMenuHeight = '300px' |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
Loading…
Reference in new issue