Files
daohangye/src/components/deskModule/SystemMonitor/index.vue
T
2024-01-06 12:41:38 +08:00

277 lines
7.6 KiB
Vue

<script setup lang="ts">
import { nextTick, onMounted, ref } from 'vue'
import { VueDraggable } from 'vue-draggable-plus'
import { NButton, NDropdown, useDialog } from 'naive-ui'
import AppIconSystemMonitor from './AppIconSystemMonitor/index.vue'
import type { CardStyle, MonitorData } from './typings'
import Edit from './Edit/index.vue'
import { deleteByIndex, getAll, saveAll } from './common'
import { usePanelState } from '@/store'
import { PanelPanelConfigStyleEnum } from '@/enums'
import { SvgIcon } from '@/components/common'
interface MonitorGroup extends Panel.ItemIconGroup {
sortStatus?: boolean
hoverStatus: boolean
items?: Panel.ItemInfo[]
}
const props = defineProps<{
allowEdit?: boolean
showTitle?: boolean
}>()
const panelState = usePanelState()
const dialog = useDialog()
const dropdownMenuX = ref(0)
const dropdownMenuY = ref(0)
const dropdownShow = ref(false)
const currentRightSelectIndex = ref<number | null>(null)
const monitorGroup = ref<MonitorGroup>({
hoverStatus: false,
sortStatus: false,
})
const editShowStatus = ref<boolean>(false)
const editData = ref<MonitorData | null>(null)
const editIndex = ref<number | null>(null)
function handleAddItem() {
editShowStatus.value = true
editData.value = null
editIndex.value = null
}
function handleSetSortStatus(sortStatus: boolean) {
monitorGroup.value.sortStatus = sortStatus
// 并未保存排序重新更新数据
if (!sortStatus)
getData()
}
function handleSetHoverStatus(hoverStatus: boolean) {
monitorGroup.value.hoverStatus = hoverStatus
}
const cardStyle: CardStyle = {
background: '#2a2a2a6b',
}
const monitorDatas = ref<MonitorData[]>([])
function handleClick(index: number, item: MonitorData) {
if (!props.allowEdit)
return
editShowStatus.value = true
editData.value = item
editIndex.value = index
}
async function getData() {
monitorDatas.value = await getAll()
}
onMounted(() => {
getData()
})
function handleSaveDone() {
getData()
}
async function handleSaveSort() {
const { code } = await saveAll(monitorDatas.value)
if (code === 0)
monitorGroup.value.sortStatus = false
}
function handleContextMenu(e: MouseEvent, index: number | null, item: MonitorData) {
if (index !== null) {
e.preventDefault()
currentRightSelectIndex.value = index
}
nextTick().then(() => {
dropdownShow.value = true
dropdownMenuX.value = e.clientX
dropdownMenuY.value = e.clientY
})
}
function getDropdownMenuOptions() {
const dropdownMenuOptions = [
{
label: '删除',
key: 'delete',
},
]
return dropdownMenuOptions
}
function onClickoutside() {
// message.info('clickoutside')
dropdownShow.value = false
}
async function deleteOneByIndex(index: number) {
const res = await deleteByIndex(index)
if (res)
getData()
}
function handleRightMenuSelect(key: string | number) {
dropdownShow.value = false
switch (key) {
case 'delete':
dialog.warning({
title: '警告',
content: '你确定要删除吗?',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
if (currentRightSelectIndex.value !== null)
deleteOneByIndex(currentRightSelectIndex.value)
},
})
break
default:
break
}
}
</script>
<template>
<div class="w-full">
<div
class="mt-[50px]"
:class="monitorGroup.sortStatus ? 'shadow-2xl border shadow-[0_0_30px_10px_rgba(0,0,0,0.3)] p-[10px] rounded-2xl' : ''"
@mouseenter="handleSetHoverStatus(true)"
@mouseleave="handleSetHoverStatus(false)"
>
<!-- 分组标题 -->
<div class="text-white text-xl font-extrabold mb-[20px] ml-[10px] flex items-center">
<span v-if="showTitle" class="text-shadow">
系统状态
</span>
<div
v-if="allowEdit"
class="ml-2 delay-100 transition-opacity flex"
:class="monitorGroup.hoverStatus ? 'opacity-100' : 'opacity-0'"
>
<span class="mr-2 cursor-pointer" title="添加快捷图标" @click="handleAddItem()">
<SvgIcon class="text-white font-xl" icon="typcn:plus" />
</span>
<span class="mr-2 cursor-pointer " title="排序组快捷图标" @click="handleSetSortStatus(!monitorGroup.sortStatus)">
<SvgIcon class="text-white font-xl" icon="ri:drag-drop-line" />
</span>
</div>
</div>
<!-- 详情图标 -->
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.info">
<VueDraggable
v-model="monitorDatas" item-key="sort" :animation="300"
class="icon-info-box"
filter=".not-drag"
:disabled="!monitorGroup.sortStatus"
>
<div
v-for="item, index in monitorDatas" :key="index"
:title="item.description"
@click="handleClick(index, item)"
@contextmenu="(e) => handleContextMenu(e, index, item)"
>
<AppIconSystemMonitor
:extend-param="item.extendParam"
:icon-text-icon-hide-title="false"
:card-type-style="panelState.panelConfig.iconStyle"
:monitor-type="item.monitorType"
:card-style="cardStyle"
:icon-text-color="panelState.panelConfig.iconTextColor"
/>
</div>
</VueDraggable>
</div>
<!-- APP图标宫型盒子 -->
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.icon">
<div v-if="monitorDatas">
<VueDraggable
v-model="monitorDatas" item-key="sort" :animation="300"
class="icon-small-box"
filter=".not-drag"
:disabled="!monitorGroup.sortStatus"
>
<div
v-for="item, index in monitorDatas" :key="index"
:title="item.description"
@click="handleClick(index, item)"
@contextmenu="(e) => handleContextMenu(e, index, item)"
>
<AppIconSystemMonitor
:extend-param="item.extendParam"
:icon-text-icon-hide-title="false"
:card-type-style="panelState.panelConfig.iconStyle"
:monitor-type="item.monitorType"
:card-style="cardStyle"
:icon-text-color="panelState.panelConfig.iconTextColor"
/>
</div>
</vuedraggable>
</div>
</div>
<!-- 编辑栏 -->
<div v-if="monitorGroup.sortStatus && allowEdit" class="flex mt-[10px]">
<div>
<NButton color="#2a2a2a6b" @click="handleSaveSort()">
<template #icon>
<SvgIcon class="text-white font-xl" icon="material-symbols:save" />
</template>
<div>
保存排序
</div>
</NButton>
</div>
</div>
</div>
<Edit v-model:visible="editShowStatus" :monitor-data="editData" :index="editIndex" @done="handleSaveDone" />
<NDropdown
placement="bottom-start" trigger="manual" :x="dropdownMenuX" :y="dropdownMenuY"
:options="getDropdownMenuOptions()" :show="dropdownShow" :on-clickoutside="onClickoutside" @select="handleRightMenuSelect"
/>
</div>
</template>
<style>
.icon-info-box {
width: 100%;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 18px;
}
.icon-small-box {
width: 100%;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(75px, 1fr));
gap: 18px;
}
@media (max-width: 500px) {
.icon-info-box{
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
}
</style>