Add File
This commit is contained in:
342
frontend/src/views/dashboard/components/sq-tab/index.vue
Normal file
342
frontend/src/views/dashboard/components/sq-tab/index.vue
Normal file
@@ -0,0 +1,342 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
computed,
|
||||
type PropType,
|
||||
reactive,
|
||||
ref,
|
||||
toRefs,
|
||||
nextTick,
|
||||
getCurrentInstance,
|
||||
onMounted,
|
||||
} 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'
|
||||
import DashboardEditor from '@/views/dashboard/editor/DashboardEditor.vue'
|
||||
|
||||
const showTabTitleFlag = ref(true)
|
||||
// @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
let currentInstance
|
||||
import _ from 'lodash'
|
||||
import SQPreview from '@/views/dashboard/preview/SQPreview.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
|
||||
const emits = defineEmits(['parentAddItemBox'])
|
||||
|
||||
const tabBaseMatrixCount = {
|
||||
x: 36,
|
||||
y: 12,
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
configItem: {
|
||||
type: Object as PropType<CanvasItem>,
|
||||
required: true,
|
||||
},
|
||||
canvasViewInfo: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
showPosition: {
|
||||
required: false,
|
||||
type: String,
|
||||
default: 'preview',
|
||||
},
|
||||
canvasId: {
|
||||
type: String,
|
||||
default: 'canvas-main',
|
||||
},
|
||||
})
|
||||
|
||||
const { configItem } = toRefs(props)
|
||||
|
||||
const state = reactive({
|
||||
curItem: { title: '' },
|
||||
textarea: '',
|
||||
dialogVisible: false,
|
||||
tabShow: true,
|
||||
hoverFlag: false,
|
||||
headFontColor: '#OOOOOO',
|
||||
headFontActiveColor: '#OOOOOO',
|
||||
headBorderColor: '#OOOOOO',
|
||||
headBorderActiveColor: '#OOOOOO',
|
||||
})
|
||||
|
||||
function addTab() {
|
||||
const newTab = {
|
||||
name: guid('tab'),
|
||||
title: t('dashboard.new_tab'),
|
||||
componentData: [],
|
||||
closable: true,
|
||||
}
|
||||
configItem.value.propValue.push(newTab)
|
||||
configItem.value.activeSubTabIndex = configItem.value.propValue.length - 1
|
||||
configItem.value.activeTabName = 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
|
||||
configItem.value.activeTabName = configItem.value.propValue[activeIndex].name
|
||||
configItem.value.activeSubTabIndex = configItem.value.propValue.length - 1
|
||||
state.tabShow = false
|
||||
nextTick(() => {
|
||||
state.tabShow = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function editCurTitle(param: any) {
|
||||
configItem.value.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 isEditMode = computed(() => props.showPosition === 'canvas')
|
||||
const outResizeEnd = () => {
|
||||
state.tabShow = false
|
||||
nextTick(() => {
|
||||
state.tabShow = true
|
||||
})
|
||||
}
|
||||
const addTabItem = (item: CanvasItem) => {
|
||||
// do addTabItem
|
||||
const index = configItem.value.propValue.findIndex(
|
||||
// @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
(tabItem) => configItem.value.activeTabName === tabItem.name
|
||||
)
|
||||
// @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
const refInstance = currentInstance.refs['tabEditorRef_' + index][0]
|
||||
const newTabItem = _.cloneDeep(item)
|
||||
newTabItem.sizeX = 10
|
||||
newTabItem.sizeY = 10
|
||||
newTabItem.x = 1
|
||||
newTabItem.y = 1
|
||||
refInstance.addItemToBox(newTabItem)
|
||||
}
|
||||
|
||||
function sureCurTitle() {
|
||||
state.curItem.title = state.textarea
|
||||
state.dialogVisible = false
|
||||
}
|
||||
|
||||
const titleValid = computed(() => {
|
||||
return !!state.textarea && !!state.textarea.trim()
|
||||
})
|
||||
|
||||
const titleStyle = (itemName: string) => {
|
||||
let style = {}
|
||||
if (configItem.value.activeTabName === itemName) {
|
||||
style = {
|
||||
fontSize: '16px',
|
||||
}
|
||||
} else {
|
||||
style = {
|
||||
fontSize: '14px',
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
currentInstance = getCurrentInstance()
|
||||
if (configItem.value.propValue.length > 0 && !configItem.value.activeTabName) {
|
||||
configItem.value.activeTabName = configItem.value.propValue[0].name
|
||||
}
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
addTabItem,
|
||||
outResizeEnd,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="{ 'tab-moveout': configItem.moveOutActive }">
|
||||
<drag-handle></drag-handle>
|
||||
<custom-tab
|
||||
v-model="configItem.activeTabName"
|
||||
:addable="isEditMode"
|
||||
:font-color="state.headFontColor"
|
||||
:active-color="state.headFontActiveColor"
|
||||
:border-color="state.headBorderColor"
|
||||
:border-active-color="state.headBorderActiveColor"
|
||||
:hide-title="!showTabTitleFlag"
|
||||
@tab-add="addTab"
|
||||
>
|
||||
<template v-for="tabItem in configItem.propValue" :key="tabItem.name">
|
||||
<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" style="margin-top: 5px"><ArrowDown /></el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item :command="beforeHandleCommand('editTitle', tabItem)">
|
||||
{{ t('dashboard.edit') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="configItem.propValue.length > 1"
|
||||
:command="beforeHandleCommand('deleteCur', tabItem)"
|
||||
>
|
||||
{{ t('dashboard.delete') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</template>
|
||||
<template v-if="state.tabShow">
|
||||
<div
|
||||
v-for="(tabItem, index) in configItem.propValue"
|
||||
:key="tabItem.name + '-content'"
|
||||
class="tab-content-custom"
|
||||
:class="{ 'switch-hidden': configItem.activeTabName !== tabItem.name }"
|
||||
>
|
||||
<SQPreview
|
||||
v-if="showPosition === 'preview'"
|
||||
:ref="'tabPreviewRef_' + index"
|
||||
class="tab-dashboard-preview"
|
||||
:component-data="tabItem.componentData"
|
||||
:canvas-view-info="canvasViewInfo"
|
||||
:base-matrix-count="tabBaseMatrixCount"
|
||||
:canvas-id="tabItem.name"
|
||||
></SQPreview>
|
||||
<DashboardEditor
|
||||
v-else
|
||||
:ref="'tabEditorRef_' + index"
|
||||
class="tab-dashboard-editor-main"
|
||||
:canvas-component-data="tabItem.componentData"
|
||||
:canvas-view-info="canvasViewInfo"
|
||||
:move-in-active="configItem.moveInActive"
|
||||
:base-matrix-count="tabBaseMatrixCount"
|
||||
:canvas-id="tabItem.name"
|
||||
:parent-config-item="configItem"
|
||||
@parent-add-item-box="(item) => emits('parentAddItemBox', item)"
|
||||
>
|
||||
</DashboardEditor>
|
||||
</div>
|
||||
</template>
|
||||
</custom-tab>
|
||||
<el-dialog
|
||||
v-model="state.dialogVisible"
|
||||
:title="t('dashboard.edit_title')"
|
||||
:append-to-body="true"
|
||||
width="30%"
|
||||
:show-close="false"
|
||||
:close-on-click-modal="false"
|
||||
center
|
||||
>
|
||||
<el-input
|
||||
v-model="state.textarea"
|
||||
maxlength="50"
|
||||
clearable
|
||||
:placeholder="t('common.input_content')"
|
||||
/>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button secondary @click="state.dialogVisible = false">{{
|
||||
t('common.cancel')
|
||||
}}</el-button>
|
||||
<el-button :disabled="!titleValid" type="primary" @click="sureCurTitle">{{
|
||||
t('common.confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
::v-deep(.ed-tabs__header) {
|
||||
margin: 0 40px 0 12px !important;
|
||||
}
|
||||
::v-deep(.ed-tabs__nav-scroll) {
|
||||
margin: 0 12px !important;
|
||||
}
|
||||
.ed-dropdown-link {
|
||||
margin-top: 3px !important;
|
||||
}
|
||||
|
||||
.tab-content-custom {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 2px !important; // border size
|
||||
div::-webkit-scrollbar {
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-dashboard-preview {
|
||||
background: #ffffff !important;
|
||||
}
|
||||
|
||||
.tab-dashboard-editor-main {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.tab-moveout {
|
||||
::v-deep(.ed-tabs__content) {
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
::v-deep(.dashboard-editor-main) {
|
||||
overflow: visible !important;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-tab-title {
|
||||
padding: 0 8px 0 4px !important;
|
||||
}
|
||||
|
||||
.switch-hidden {
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user