forked from github/dataease
feat(数据大屏): 支持跑马灯组件
This commit is contained in:
parent
36c7b30996
commit
0b6e577165
1
core/core-frontend/src/assets/svg/dv-scroll-text.svg
Normal file
1
core/core-frontend/src/assets/svg/dv-scroll-text.svg
Normal file
@ -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="1716529317390" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1706" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M810.666667 128H213.333333c-46.933333 0-85.333333 38.4-85.333333 85.333333v597.333334c0 46.933333 38.4 85.333333 85.333333 85.333333h597.333334c46.933333 0 85.333333-38.4 85.333333-85.333333V213.333333c0-46.933333-38.4-85.333333-85.333333-85.333333z m0 640c0 23.466667-19.2 42.666667-42.666667 42.666667H256c-23.466667 0-42.666667-19.2-42.666667-42.666667V256c0-23.466667 19.2-42.666667 42.666667-42.666667h512c23.466667 0 42.666667 19.2 42.666667 42.666667v512z" fill="#297AFF" p-id="1707"></path><path d="M725.333333 317.866667c0-12.8-8.533333-21.333333-21.333333-21.333334H320c-12.8 0-21.333333 8.533333-21.333333 21.333334v42.666666c0 12.8 8.533333 21.333333 21.333333 21.333334h149.333333v234.666666c0 12.8 8.533333 21.333333 21.333334 21.333334h42.666666c12.8 0 21.333333-8.533333 21.333334-21.333334v-234.666666h149.333333c12.8 0 21.333333-8.533333 21.333333-21.333334v-42.666666zM714.666667 682.666667H358.4v-32c0-2.133333-4.266667-4.266667-6.4-2.133334l-40.533333 40.533334c-8.533333 8.533333-8.533333 21.333333 0 29.866666l40.533333 40.533334c2.133333 2.133333 6.4 0 6.4-2.133334V725.333333h356.266667c6.4 0 10.666667-4.266667 10.666666-10.666666v-21.333334c0-6.4-4.266667-10.666667-10.666666-10.666666z" fill="#297AFF" p-id="1708"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
1
core/core-frontend/src/assets/svg/scroll-text.svg
Normal file
1
core/core-frontend/src/assets/svg/scroll-text.svg
Normal file
@ -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="1716529317390" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1706" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M810.666667 128H213.333333c-46.933333 0-85.333333 38.4-85.333333 85.333333v597.333334c0 46.933333 38.4 85.333333 85.333333 85.333333h597.333334c46.933333 0 85.333333-38.4 85.333333-85.333333V213.333333c0-46.933333-38.4-85.333333-85.333333-85.333333z m0 640c0 23.466667-19.2 42.666667-42.666667 42.666667H256c-23.466667 0-42.666667-19.2-42.666667-42.666667V256c0-23.466667 19.2-42.666667 42.666667-42.666667h512c23.466667 0 42.666667 19.2 42.666667 42.666667v512z" p-id="1707"></path><path d="M725.333333 317.866667c0-12.8-8.533333-21.333333-21.333333-21.333334H320c-12.8 0-21.333333 8.533333-21.333333 21.333334v42.666666c0 12.8 8.533333 21.333333 21.333333 21.333334h149.333333v234.666666c0 12.8 8.533333 21.333333 21.333334 21.333334h42.666666c12.8 0 21.333333-8.533333 21.333334-21.333334v-234.666666h149.333333c12.8 0 21.333333-8.533333 21.333333-21.333334v-42.666666zM714.666667 682.666667H358.4v-32c0-2.133333-4.266667-4.266667-6.4-2.133334l-40.533333 40.533334c-8.533333 8.533333-8.533333 21.333333 0 29.866666l40.533333 40.533334c2.133333 2.133333 6.4 0 6.4-2.133334V725.333333h356.266667c6.4 0 10.666667-4.266667 10.666666-10.666666v-21.333334c0-6.4-4.266667-10.666667-10.666666-10.666666z" p-id="1708"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -227,7 +227,7 @@ eventBus.on('clearCanvas', clearCanvas)
|
|||||||
>
|
>
|
||||||
<query-group :dv-model="dvModel"></query-group>
|
<query-group :dv-model="dvModel"></query-group>
|
||||||
</component-group>
|
</component-group>
|
||||||
<component-group is-label :base-width="115" icon-name="dv-text" title="文本">
|
<component-group is-label :base-width="215" icon-name="dv-text" title="文本">
|
||||||
<text-group></text-group>
|
<text-group></text-group>
|
||||||
</component-group>
|
</component-group>
|
||||||
<component-group
|
<component-group
|
||||||
|
@ -37,23 +37,26 @@ const handleDragEnd = e => {
|
|||||||
commonHandleDragEnd(e, dvModel.value)
|
commonHandleDragEnd(e, dvModel.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const newComponent = () => {
|
const newComponent = (componentName, innerType) => {
|
||||||
eventBus.emit('handleNew', { componentName: 'UserView', innerType: 'rich-text' })
|
eventBus.emit('handleNew', { componentName: componentName, innerType: innerType })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="group" @dragstart="handleDragStart" @dragend="handleDragEnd">
|
||||||
class="group"
|
|
||||||
@dragstart="handleDragStart"
|
|
||||||
@dragend="handleDragEnd"
|
|
||||||
v-on:click="newComponent"
|
|
||||||
>
|
|
||||||
<drag-component
|
<drag-component
|
||||||
:themes="themes"
|
:themes="themes"
|
||||||
icon="dv-richText"
|
icon="dv-richText"
|
||||||
label="富文本"
|
label="富文本"
|
||||||
drag-info="UserView&rich-text"
|
drag-info="UserView&rich-text"
|
||||||
|
v-on:click="newComponent('UserView', 'rich-text')"
|
||||||
|
></drag-component>
|
||||||
|
<drag-component
|
||||||
|
:themes="themes"
|
||||||
|
icon="dv-scroll-text"
|
||||||
|
label="跑马灯"
|
||||||
|
drag-info="ScrollText&ScrollText"
|
||||||
|
v-on:click="newComponent('ScrollText', 'ScrollText')"
|
||||||
></drag-component>
|
></drag-component>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -61,10 +64,6 @@ const newComponent = () => {
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.group {
|
.group {
|
||||||
padding: 12px 8px;
|
padding: 12px 8px;
|
||||||
}
|
display: inline-flex;
|
||||||
.custom_img {
|
|
||||||
width: 100px;
|
|
||||||
height: 70px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -477,6 +477,28 @@ const list = [
|
|||||||
headFontColor: '#000000',
|
headFontColor: '#000000',
|
||||||
headFontActiveColor: '#000000'
|
headFontActiveColor: '#000000'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'ScrollText',
|
||||||
|
name: '跑马灯',
|
||||||
|
label: '跑马灯',
|
||||||
|
propValue: '双击编辑文字',
|
||||||
|
innerType: 'ScrollText',
|
||||||
|
icon: 'scroll-text',
|
||||||
|
x: 1,
|
||||||
|
y: 1,
|
||||||
|
sizeX: 36,
|
||||||
|
sizeY: 14,
|
||||||
|
style: {
|
||||||
|
width: 400,
|
||||||
|
height: 80,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: 400,
|
||||||
|
letterSpacing: 0,
|
||||||
|
color: '',
|
||||||
|
padding: 4,
|
||||||
|
verticalAlign: 'middle'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
56
core/core-frontend/src/custom-component/scroll-text/Attr.vue
Normal file
56
core/core-frontend/src/custom-component/scroll-text/Attr.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import CommonAttr from '@/custom-component/common/CommonAttr.vue'
|
||||||
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { toRefs } from 'vue'
|
||||||
|
|
||||||
|
const dvMainStore = dvMainStoreWithOut()
|
||||||
|
const { curComponent } = storeToRefs(dvMainStore)
|
||||||
|
const props = defineProps({
|
||||||
|
themes: {
|
||||||
|
type: String,
|
||||||
|
default: 'dark'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const { themes } = toRefs(props)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="attr-list de-collapse-style">
|
||||||
|
<CommonAttr :themes="themes" :element="curComponent"></CommonAttr>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.de-collapse-style {
|
||||||
|
:deep(.ed-collapse-item__header) {
|
||||||
|
height: 34px !important;
|
||||||
|
line-height: 34px !important;
|
||||||
|
padding: 0 0 0 6px !important;
|
||||||
|
font-size: 12px !important;
|
||||||
|
font-weight: 400 !important;
|
||||||
|
}
|
||||||
|
:deep(.ed-collapse-item__content) {
|
||||||
|
padding: 16px !important;
|
||||||
|
}
|
||||||
|
:deep(.ed-form-item) {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
:deep(.ed-form-item__label) {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ed-textarea__inner) {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,188 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { keycodes } from '@/utils/DeShortcutKey.js'
|
||||||
|
import eventBus from '@/utils/eventBus'
|
||||||
|
import { nextTick, onBeforeUnmount, ref } from 'vue'
|
||||||
|
import { toRefs } from 'vue'
|
||||||
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
|
||||||
|
const canEdit = ref(false)
|
||||||
|
const ctrlKey = ref(17)
|
||||||
|
const isCtrlDown = ref(false)
|
||||||
|
|
||||||
|
const emit = defineEmits(['input'])
|
||||||
|
const text = ref(null)
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
propValue: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
element: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {
|
||||||
|
id: null,
|
||||||
|
propValue: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const { element } = toRefs(props)
|
||||||
|
const dvMainStore = dvMainStoreWithOut()
|
||||||
|
const { editMode, curComponent } = storeToRefs(dvMainStore)
|
||||||
|
|
||||||
|
const onComponentClick = () => {
|
||||||
|
if (curComponent.value.id !== element.value.id) {
|
||||||
|
canEdit.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleInput = e => {
|
||||||
|
emit('input', element.value, e.target.innerHTML)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeydown = e => {
|
||||||
|
// 阻止冒泡,防止触发复制、粘贴组件操作
|
||||||
|
canEdit.value && e.stopPropagation()
|
||||||
|
if (e.keyCode == ctrlKey.value) {
|
||||||
|
isCtrlDown.value = true
|
||||||
|
} else if (isCtrlDown.value && canEdit.value && keycodes.includes(e.keyCode)) {
|
||||||
|
e.stopPropagation()
|
||||||
|
} else if (e.keyCode == 46) {
|
||||||
|
// deleteKey
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeyup = e => {
|
||||||
|
// 阻止冒泡,防止触发复制、粘贴组件操作
|
||||||
|
canEdit.value && e.stopPropagation()
|
||||||
|
if (e.keyCode == ctrlKey.value) {
|
||||||
|
isCtrlDown.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMousedown = e => {
|
||||||
|
if (canEdit.value) {
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearStyle = e => {
|
||||||
|
e.preventDefault()
|
||||||
|
const clp = e.clipboardData
|
||||||
|
const text = clp.getData('text/plain') || ''
|
||||||
|
if (text !== '') {
|
||||||
|
document.execCommand('insertText', false, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('input', element.value, e.target.innerHTML)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBlur = e => {
|
||||||
|
element.value.propValue = e.target.innerHTML || ' '
|
||||||
|
const html = e.target.innerHTML
|
||||||
|
if (html !== '') {
|
||||||
|
element.value.propValue = e.target.innerHTML
|
||||||
|
} else {
|
||||||
|
element.value.propValue = ''
|
||||||
|
nextTick(function () {
|
||||||
|
element.value.propValue = ' '
|
||||||
|
})
|
||||||
|
}
|
||||||
|
canEdit.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const setEdit = () => {
|
||||||
|
if (element.value['isLock']) return
|
||||||
|
canEdit.value = true
|
||||||
|
// 全选
|
||||||
|
selectText(text.value)
|
||||||
|
}
|
||||||
|
const selectText = element => {
|
||||||
|
const selection = window.getSelection()
|
||||||
|
const range = document.createRange()
|
||||||
|
range.selectNodeContents(element)
|
||||||
|
selection.removeAllRanges()
|
||||||
|
selection.addRange(range)
|
||||||
|
}
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
eventBus.off('componentClick', onComponentClick)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="editMode == 'edit'" class="v-text" @keydown="handleKeydown" @keyup="handleKeyup">
|
||||||
|
<div
|
||||||
|
ref="text"
|
||||||
|
class="marquee-txt"
|
||||||
|
:contenteditable="canEdit"
|
||||||
|
:class="{ 'can-edit': canEdit }"
|
||||||
|
tabindex="0"
|
||||||
|
:style="{ verticalAlign: element['style'].verticalAlign }"
|
||||||
|
@dblclick="setEdit"
|
||||||
|
@paste="clearStyle"
|
||||||
|
@mousedown="handleMousedown"
|
||||||
|
@blur="handleBlur"
|
||||||
|
@input="handleInput"
|
||||||
|
v-html="element['propValue']"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="v-text preview">
|
||||||
|
<div
|
||||||
|
class="marquee-txt"
|
||||||
|
:style="{ verticalAlign: element['style'].verticalAlign }"
|
||||||
|
v-html="element['propValue']"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.v-text {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: table;
|
||||||
|
div {
|
||||||
|
display: table-cell;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
outline: none;
|
||||||
|
word-break: break-all;
|
||||||
|
padding: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.can-edit {
|
||||||
|
cursor: text;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.marquee {
|
||||||
|
margin-left: 100px;
|
||||||
|
width: 300px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #4c7cee;
|
||||||
|
}
|
||||||
|
.marquee-txt {
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 100%; /* 从右至左开始滚动 */
|
||||||
|
animation: marqueeAnimation 10s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes marqueeAnimation {
|
||||||
|
0% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate(-100%, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -31,6 +31,8 @@ import DeVideo from '@/custom-component/de-video/Component.vue'
|
|||||||
import DeVideoAttr from '@/custom-component/de-video/Attr.vue'
|
import DeVideoAttr from '@/custom-component/de-video/Attr.vue'
|
||||||
import DeStreamMedia from '@/custom-component/de-stream-media/Component.vue'
|
import DeStreamMedia from '@/custom-component/de-stream-media/Component.vue'
|
||||||
import DeStreamMediaAttr from '@/custom-component/de-stream-media/Attr.vue'
|
import DeStreamMediaAttr from '@/custom-component/de-stream-media/Attr.vue'
|
||||||
|
import ScrollText from '@/custom-component/scroll-text/Component.vue'
|
||||||
|
import ScrollTextAttr from '@/custom-component/scroll-text/Attr.vue'
|
||||||
export const componentsMap = {
|
export const componentsMap = {
|
||||||
VText: VText,
|
VText: VText,
|
||||||
VQuery,
|
VQuery,
|
||||||
@ -64,7 +66,9 @@ export const componentsMap = {
|
|||||||
DeVideo: DeVideo,
|
DeVideo: DeVideo,
|
||||||
DeVideoAttr: DeVideoAttr,
|
DeVideoAttr: DeVideoAttr,
|
||||||
DeStreamMedia: DeStreamMedia,
|
DeStreamMedia: DeStreamMedia,
|
||||||
DeStreamMediaAttr: DeStreamMediaAttr
|
DeStreamMediaAttr: DeStreamMediaAttr,
|
||||||
|
ScrollText: ScrollText,
|
||||||
|
ScrollTextAttr: ScrollTextAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function findComponent(key) {
|
export default function findComponent(key) {
|
||||||
|
Loading…
Reference in New Issue
Block a user