feat
This commit is contained in:
@@ -3,10 +3,11 @@
|
||||
<!-- 机柜选择卡片 -->
|
||||
<a-card class="rack-select-card">
|
||||
<template #title>
|
||||
<icon-storage /> 选择机柜
|
||||
<icon-storage />
|
||||
选择机柜
|
||||
</template>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
<a-col :span="6">
|
||||
<a-select
|
||||
v-model="selectedDatacenterId"
|
||||
placeholder="请选择数据中心"
|
||||
@@ -16,16 +17,12 @@
|
||||
@change="handleDatacenterChange"
|
||||
style="width: 100%"
|
||||
>
|
||||
<a-option
|
||||
v-for="datacenter in datacenterList"
|
||||
:key="datacenter.value"
|
||||
:value="datacenter.value"
|
||||
>
|
||||
<a-option v-for="datacenter in datacenterList" :key="datacenter.value" :value="datacenter.value">
|
||||
{{ datacenter.label }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-col :span="6">
|
||||
<a-select
|
||||
v-model="selectedFloorId"
|
||||
placeholder="请选择楼层"
|
||||
@@ -36,49 +33,47 @@
|
||||
@change="handleFloorChange"
|
||||
style="width: 100%"
|
||||
>
|
||||
<a-option
|
||||
v-for="floor in floorList"
|
||||
:key="floor.value"
|
||||
:value="floor.value"
|
||||
>
|
||||
<a-option v-for="floor in floorList" :key="floor.value" :value="floor.value">
|
||||
{{ floor.label }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-col :span="6">
|
||||
<a-select
|
||||
v-model="selectedRoomId"
|
||||
placeholder="请选择机房"
|
||||
:loading="roomListLoading"
|
||||
:disabled="!selectedFloorId"
|
||||
allow-search
|
||||
@search="handleRoomSearch"
|
||||
@change="handleRoomChange"
|
||||
style="width: 100%"
|
||||
>
|
||||
<a-option v-for="room in roomList" :key="room.id" :value="room.id">{{ room.name }} ({{ room.code }})</a-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-select
|
||||
v-model="selectedRackId"
|
||||
placeholder="请选择机柜"
|
||||
:loading="rackListLoading"
|
||||
:disabled="!selectedFloorId"
|
||||
:disabled="!selectedRoomId"
|
||||
allow-search
|
||||
@search="handleRackSearch"
|
||||
@change="handleRackChange"
|
||||
style="width: 100%"
|
||||
>
|
||||
<a-option
|
||||
v-for="rack in rackList"
|
||||
:key="rack.id"
|
||||
:value="rack.id"
|
||||
>
|
||||
{{ rack.name }} ({{ rack.code }})
|
||||
</a-option>
|
||||
<a-option v-for="rack in rackList" :key="rack.id" :value="rack.id">{{ rack.name }} ({{ rack.code }})</a-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
<a-col :span="16">
|
||||
</a-row>
|
||||
<a-row :gutter="16" style="margin-top: 16px">
|
||||
<a-col :span="24">
|
||||
<a-space>
|
||||
<a-tag v-if="rackInfo.height">
|
||||
总U位: {{ rackInfo.height }}
|
||||
</a-tag>
|
||||
<a-tag v-if="usedUnits" color="blue">
|
||||
已使用: {{ usedUnits }}
|
||||
</a-tag>
|
||||
<a-tag v-if="availableUnits" color="green">
|
||||
空余: {{ availableUnits }}
|
||||
</a-tag>
|
||||
<a-tag v-if="usagePercentage" :color="usagePercentage > 80 ? 'red' : 'orange'">
|
||||
使用率: {{ usagePercentage }}%
|
||||
</a-tag>
|
||||
<a-tag v-if="rackInfo.height">总U位: {{ rackInfo.height }}</a-tag>
|
||||
<a-tag v-if="usedUnits" color="blue">已使用: {{ usedUnits }}</a-tag>
|
||||
<a-tag v-if="availableUnits" color="green">空余: {{ availableUnits }}</a-tag>
|
||||
<a-tag v-if="usagePercentage" :color="usagePercentage > 80 ? 'red' : 'orange'">使用率: {{ usagePercentage }}%</a-tag>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
@@ -111,17 +106,11 @@
|
||||
<!-- U位列表 -->
|
||||
<a-card class="u-position-card" :loading="loading">
|
||||
<template #title>
|
||||
<icon-apps /> U位列表
|
||||
<icon-apps />
|
||||
U位列表
|
||||
</template>
|
||||
|
||||
<a-table
|
||||
:data="unitList"
|
||||
:pagination="false"
|
||||
:bordered="{ cell: true }"
|
||||
:scroll="{ x: 1400 }"
|
||||
:loading="loading"
|
||||
size="small"
|
||||
>
|
||||
|
||||
<a-table :data="unitList" :pagination="false" :bordered="{ cell: true }" :scroll="{ x: 1400 }" :loading="loading" size="small">
|
||||
<template #columns>
|
||||
<!-- <a-table-column title="序号" :width="80">
|
||||
<template #cell="{ rowIndex }">
|
||||
@@ -146,34 +135,14 @@
|
||||
<template #cell="{ record }">
|
||||
<a-space size="small">
|
||||
<!-- 禁用/启用按钮(所有状态都显示) -->
|
||||
<a-button
|
||||
v-if="record.status !== 'disabled'"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="handleDisable(record)"
|
||||
>
|
||||
禁用
|
||||
</a-button>
|
||||
<a-button
|
||||
v-else
|
||||
type="text"
|
||||
size="small"
|
||||
@click="handleEnable(record)"
|
||||
>
|
||||
启用
|
||||
</a-button>
|
||||
|
||||
<a-button v-if="record.status !== 'disabled'" type="text" size="small" @click="handleDisable(record)">禁用</a-button>
|
||||
<a-button v-else type="text" size="small" @click="handleEnable(record)">启用</a-button>
|
||||
|
||||
<!-- 已占用状态:显示释放按钮 -->
|
||||
<a-button
|
||||
v-if="record.status === 'occupied'"
|
||||
type="text"
|
||||
size="small"
|
||||
status="danger"
|
||||
@click="handleRelease(record)"
|
||||
>
|
||||
<a-button v-if="record.status === 'occupied'" type="text" size="small" status="danger" @click="handleRelease(record)">
|
||||
释放
|
||||
</a-button>
|
||||
|
||||
|
||||
<!-- 已预留状态:显示取消预留按钮 -->
|
||||
<a-button
|
||||
v-if="record.status === 'reserved'"
|
||||
@@ -213,19 +182,10 @@
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { Message, Modal } from '@arco-design/web-vue'
|
||||
import { IconStorage, IconApps, IconPlus, IconLock, IconRefresh } from '@arco-design/web-vue/es/icon'
|
||||
import {
|
||||
fetchUnitList,
|
||||
allocateUnit,
|
||||
reserveUnit,
|
||||
cancelReservation,
|
||||
releaseUnit,
|
||||
updateUnitStatus,
|
||||
} from '@/api/ops/unit'
|
||||
import {
|
||||
fetchDatacenterList,
|
||||
fetchRackListByFloor,
|
||||
} from '@/api/ops/rack'
|
||||
import { fetchUnitList, allocateUnit, reserveUnit, cancelReservation, releaseUnit, updateUnitStatus } from '@/api/ops/unit'
|
||||
import { fetchDatacenterList, fetchRackListByRoom } from '@/api/ops/rack'
|
||||
import { fetchFloorListByDatacenter } from '@/api/ops/floor'
|
||||
import { fetchRoomListByFloor } from '@/api/ops/room'
|
||||
import { normalizeUnitList } from './utils/unitFallback'
|
||||
import AllocateUnitDialog from './components/AllocateUnitDialog.vue'
|
||||
import ReserveUnitDialog from './components/ReserveUnitDialog.vue'
|
||||
@@ -235,16 +195,20 @@ const loading = ref(false)
|
||||
const rackListLoading = ref(false)
|
||||
const datacenterListLoading = ref(false)
|
||||
const floorListLoading = ref(false)
|
||||
const roomListLoading = ref(false)
|
||||
const selectedDatacenterId = ref<number | undefined>(undefined)
|
||||
const selectedFloorId = ref<number | undefined>(undefined)
|
||||
const selectedRoomId = ref<number | undefined>(undefined)
|
||||
const selectedRackId = ref<number | undefined>(undefined)
|
||||
const rackInfo = ref<any>({})
|
||||
const datacenterList = ref<{ label: string; value: number }[]>([])
|
||||
const floorList = ref<{ label: string; value: number }[]>([])
|
||||
const roomList = ref<any[]>([])
|
||||
const rackList = ref<any[]>([])
|
||||
const unitList = ref<any[]>([])
|
||||
let datacenterSearchTimer: number | undefined
|
||||
let floorSearchTimer: number | undefined
|
||||
let roomSearchTimer: number | undefined
|
||||
let rackSearchTimer: number | undefined
|
||||
|
||||
// 对话框可见性
|
||||
@@ -253,9 +217,7 @@ const reserveVisible = ref(false)
|
||||
|
||||
// 已使用U位
|
||||
const usedUnits = computed(() => {
|
||||
return unitList.value.filter(
|
||||
(unit) => unit.status === 'occupied' || unit.status === 'reserved'
|
||||
).length
|
||||
return unitList.value.filter((unit) => unit.status === 'occupied' || unit.status === 'reserved').length
|
||||
})
|
||||
|
||||
// 空余U位
|
||||
@@ -270,12 +232,7 @@ const usagePercentage = computed(() => {
|
||||
})
|
||||
|
||||
const extractList = (res: any): any[] => {
|
||||
const candidate =
|
||||
res?.data?.data ??
|
||||
res?.details?.data ??
|
||||
res?.data ??
|
||||
res?.details ??
|
||||
[]
|
||||
const candidate = res?.data?.data ?? res?.details?.data ?? res?.data ?? res?.details ?? []
|
||||
return Array.isArray(candidate) ? candidate : []
|
||||
}
|
||||
|
||||
@@ -303,14 +260,14 @@ const getUnitStatusText = (status?: string) => {
|
||||
|
||||
// 获取机柜列表
|
||||
const fetchRacks = async (keyword?: string) => {
|
||||
if (!selectedFloorId.value) {
|
||||
if (!selectedRoomId.value) {
|
||||
rackList.value = []
|
||||
return
|
||||
}
|
||||
rackListLoading.value = true
|
||||
|
||||
|
||||
try {
|
||||
const res: any = await fetchRackListByFloor(selectedFloorId.value, { name: keyword })
|
||||
const res: any = await fetchRackListByRoom(selectedRoomId.value, { name: keyword })
|
||||
rackList.value = extractList(res)
|
||||
} catch (error) {
|
||||
console.error('获取机柜列表失败:', error)
|
||||
@@ -363,6 +320,26 @@ const fetchFloors = async (keyword?: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
const fetchRooms = async (keyword?: string) => {
|
||||
if (!selectedFloorId.value) {
|
||||
roomList.value = []
|
||||
return
|
||||
}
|
||||
roomListLoading.value = true
|
||||
try {
|
||||
const res: any = await fetchRoomListByFloor(selectedFloorId.value, {
|
||||
name: keyword || undefined,
|
||||
})
|
||||
roomList.value = extractList(res)
|
||||
} catch (error) {
|
||||
console.error('获取机房列表失败:', error)
|
||||
Message.error('获取机房列表失败')
|
||||
roomList.value = []
|
||||
} finally {
|
||||
roomListLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleDatacenterSearch = (keyword: string) => {
|
||||
if (datacenterSearchTimer) {
|
||||
window.clearTimeout(datacenterSearchTimer)
|
||||
@@ -382,8 +359,18 @@ const handleFloorSearch = (keyword: string) => {
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const handleRackSearch = (keyword: string) => {
|
||||
const handleRoomSearch = (keyword: string) => {
|
||||
if (!selectedFloorId.value) return
|
||||
if (roomSearchTimer) {
|
||||
window.clearTimeout(roomSearchTimer)
|
||||
}
|
||||
roomSearchTimer = window.setTimeout(() => {
|
||||
fetchRooms(keyword?.trim() || undefined)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const handleRackSearch = (keyword: string) => {
|
||||
if (!selectedRoomId.value) return
|
||||
if (rackSearchTimer) {
|
||||
window.clearTimeout(rackSearchTimer)
|
||||
}
|
||||
@@ -397,9 +384,11 @@ const handleDatacenterChange = async (datacenterId?: number | string) => {
|
||||
selectedDatacenterId.value = Number(datacenterId)
|
||||
}
|
||||
selectedFloorId.value = undefined
|
||||
selectedRoomId.value = undefined
|
||||
selectedRackId.value = undefined
|
||||
rackInfo.value = {}
|
||||
rackList.value = []
|
||||
roomList.value = []
|
||||
floorList.value = []
|
||||
unitList.value = []
|
||||
await fetchFloors()
|
||||
@@ -409,6 +398,19 @@ const handleFloorChange = async (floorId?: number | string) => {
|
||||
if (floorId !== undefined && floorId !== null && floorId !== '') {
|
||||
selectedFloorId.value = Number(floorId)
|
||||
}
|
||||
selectedRoomId.value = undefined
|
||||
selectedRackId.value = undefined
|
||||
rackInfo.value = {}
|
||||
rackList.value = []
|
||||
roomList.value = []
|
||||
unitList.value = []
|
||||
await fetchRooms()
|
||||
}
|
||||
|
||||
const handleRoomChange = async (roomId?: number | string) => {
|
||||
if (roomId !== undefined && roomId !== null && roomId !== '') {
|
||||
selectedRoomId.value = Number(roomId)
|
||||
}
|
||||
selectedRackId.value = undefined
|
||||
rackInfo.value = {}
|
||||
rackList.value = []
|
||||
@@ -429,14 +431,14 @@ const handleRackChange = (rackId: number) => {
|
||||
// 获取U位列表
|
||||
const fetchUnits = async (rackId?: number) => {
|
||||
const targetRackId = rackId || selectedRackId.value
|
||||
|
||||
|
||||
if (!targetRackId) return
|
||||
|
||||
|
||||
loading.value = true
|
||||
|
||||
|
||||
try {
|
||||
const res = await fetchUnitList(targetRackId)
|
||||
|
||||
|
||||
if (res.code === 0) {
|
||||
const payload = res?.details ?? res?.data ?? {}
|
||||
rackInfo.value = payload?.rack || {}
|
||||
@@ -489,14 +491,14 @@ const handleDisable = async (record: any) => {
|
||||
Message.warning('请先选择机柜')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
const res = await updateUnitStatus({
|
||||
rack_id: selectedRackId.value,
|
||||
start_unit: record.unit_number,
|
||||
end_unit: record.unit_number,
|
||||
status: 'disabled',
|
||||
})
|
||||
|
||||
|
||||
if (res.code === 0) {
|
||||
Message.success('禁用成功')
|
||||
fetchUnits()
|
||||
@@ -521,14 +523,14 @@ const handleEnable = async (record: any) => {
|
||||
Message.warning('请先选择机柜')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
const res = await updateUnitStatus({
|
||||
rack_id: selectedRackId.value,
|
||||
start_unit: record.unit_number,
|
||||
end_unit: record.unit_number,
|
||||
status: 'available',
|
||||
})
|
||||
|
||||
|
||||
if (res.code === 0) {
|
||||
Message.success('启用成功')
|
||||
fetchUnits()
|
||||
@@ -549,21 +551,19 @@ const handleRelease = async (record: any) => {
|
||||
title: '确认释放',
|
||||
content: `确认释放 U位 ${record.unit_number} 吗?`,
|
||||
onOk: async () => {
|
||||
const endUnit = record.occupied_units > 1
|
||||
? record.unit_number + record.occupied_units - 1
|
||||
: record.unit_number
|
||||
|
||||
const endUnit = record.occupied_units > 1 ? record.unit_number + record.occupied_units - 1 : record.unit_number
|
||||
|
||||
if (!selectedRackId.value) {
|
||||
Message.warning('请先选择机柜')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
const res = await releaseUnit({
|
||||
rack_id: selectedRackId.value,
|
||||
start_unit: record.unit_number,
|
||||
end_unit: endUnit,
|
||||
})
|
||||
|
||||
|
||||
if (res.code === 0) {
|
||||
Message.success('释放成功')
|
||||
fetchUnits()
|
||||
@@ -584,21 +584,19 @@ const handleCancelReservation = async (record: any) => {
|
||||
title: '确认取消预留',
|
||||
content: `确认取消 U位 ${record.unit_number} 的预留吗?`,
|
||||
onOk: async () => {
|
||||
const endUnit = record.occupied_units > 1
|
||||
? record.unit_number + record.occupied_units - 1
|
||||
: record.unit_number
|
||||
|
||||
const endUnit = record.occupied_units > 1 ? record.unit_number + record.occupied_units - 1 : record.unit_number
|
||||
|
||||
if (!selectedRackId.value) {
|
||||
Message.warning('请先选择机柜')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
const res = await cancelReservation({
|
||||
rack_id: selectedRackId.value,
|
||||
start_unit: record.unit_number,
|
||||
end_unit: endUnit,
|
||||
})
|
||||
|
||||
|
||||
if (res.code === 0) {
|
||||
Message.success('取消预留成功')
|
||||
fetchUnits()
|
||||
@@ -637,7 +635,7 @@ export default {
|
||||
|
||||
.action-card {
|
||||
margin-bottom: 16px;
|
||||
|
||||
|
||||
:deep(.arco-card-body) {
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
132
src/views/ops/pages/dc/device-collect/components/Detail.vue
Normal file
132
src/views/ops/pages/dc/device-collect/components/Detail.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<a-descriptions :column="2" bordered>
|
||||
<a-descriptions-item label="ID">{{ record.id }}</a-descriptions-item>
|
||||
<a-descriptions-item label="服务标识">{{ record.service_identity }}</a-descriptions-item>
|
||||
<a-descriptions-item label="服务名称">{{ record.name }}</a-descriptions-item>
|
||||
<a-descriptions-item label="设备分类">
|
||||
{{ DEVICE_CATEGORY_MAP[record.device_category] || record.device_category }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="机房ID">{{ record.room_id }}</a-descriptions-item>
|
||||
<a-descriptions-item label="描述信息" :span="2">{{ record.description || '-' }}</a-descriptions-item>
|
||||
|
||||
<a-descriptions-item label="采集地址" :span="2">
|
||||
<a-link v-if="record.agent_config" :href="record.agent_config" target="_blank">{{ record.agent_config }}</a-link>
|
||||
<span v-else>-</span>
|
||||
</a-descriptions-item>
|
||||
|
||||
<a-descriptions-item label="启用状态">
|
||||
<a-tag :color="record.enabled ? 'green' : 'gray'">
|
||||
{{ record.enabled ? '已启用' : '已禁用' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="参与周期采集">
|
||||
<a-tag :color="record.collect_on ? 'green' : 'gray'">
|
||||
{{ record.collect_on ? '已启用' : '未启用' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
|
||||
<a-descriptions-item label="采集间隔">{{ record.collect_interval }}秒</a-descriptions-item>
|
||||
<a-descriptions-item label="采集结果摘要" :span="2">{{ record.collect_last_result || '-' }}</a-descriptions-item>
|
||||
|
||||
<a-descriptions-item label="创建时间">{{ formatTime(record.created_at) }}</a-descriptions-item>
|
||||
<a-descriptions-item label="更新时间">{{ formatTime(record.updated_at) }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<div class="action-bar">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="$emit('edit')">
|
||||
<template #icon><icon-edit /></template>
|
||||
编辑
|
||||
</a-button>
|
||||
<a-button type="outline" @click="$emit('quick-config')">
|
||||
<template #icon><icon-settings /></template>
|
||||
采集配置
|
||||
</a-button>
|
||||
<a-button type="outline" @click="handleViewMetrics">
|
||||
<template #icon><icon-eye /></template>
|
||||
查看最新指标
|
||||
</a-button>
|
||||
<a-button type="outline" status="danger" @click="$emit('delete')">
|
||||
<template #icon><icon-delete /></template>
|
||||
删除
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
|
||||
<a-drawer v-model:visible="metricsVisible" :width="800" title="最新指标数据" :footer="false" unmount-on-close>
|
||||
<a-spin :loading="metricsLoading" style="width: 100%">
|
||||
<div v-if="metricsData.length > 0">
|
||||
<a-list :bordered="false">
|
||||
<a-list-item v-for="(item, index) in metricsData" :key="index">
|
||||
<a-descriptions :column="3" size="small">
|
||||
<a-descriptions-item label="指标名称">{{ item.metric_name }}</a-descriptions-item>
|
||||
<a-descriptions-item label="指标值">{{ item.metric_value }} {{ item.metric_unit || '' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="类型">{{ item.type || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="时间">{{ formatTime(item.timestamp) }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</div>
|
||||
<a-empty v-else description="暂无指标数据" />
|
||||
</a-spin>
|
||||
</a-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { IconEdit, IconDelete, IconSettings, IconEye } from '@arco-design/web-vue/es/icon'
|
||||
import { DEVICE_CATEGORY_MAP, fetchLatestMetrics, type RoomDeviceItem, type MetricItem } from '@/api/ops/room-device'
|
||||
|
||||
interface Props {
|
||||
record: RoomDeviceItem
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
defineEmits(['edit', 'quick-config', 'delete'])
|
||||
|
||||
const metricsVisible = ref(false)
|
||||
const metricsLoading = ref(false)
|
||||
const metricsData = ref<MetricItem[]>([])
|
||||
|
||||
const handleViewMetrics = async () => {
|
||||
metricsVisible.value = true
|
||||
metricsLoading.value = true
|
||||
try {
|
||||
const response = await fetchLatestMetrics(props.record.service_identity)
|
||||
metricsData.value = (response as any)?.details?.data || []
|
||||
} catch (error) {
|
||||
console.error('获取最新指标失败:', error)
|
||||
Message.error('获取最新指标失败')
|
||||
metricsData.value = []
|
||||
} finally {
|
||||
metricsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const formatTime = (time?: string) => {
|
||||
if (!time) return '-'
|
||||
const date = new Date(time)
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
const hours = String(date.getHours()).padStart(2, '0')
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0')
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0')
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.detail-container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
margin-top: 24px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
</style>
|
||||
232
src/views/ops/pages/dc/device-collect/components/FormDialog.vue
Normal file
232
src/views/ops/pages/dc/device-collect/components/FormDialog.vue
Normal file
@@ -0,0 +1,232 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:visible="visible"
|
||||
:title="isEdit ? '编辑机房设备' : '新增机房设备'"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
@update:visible="handleUpdateVisible"
|
||||
:confirm-loading="confirmLoading"
|
||||
width="800px"
|
||||
>
|
||||
<a-form ref="formRef" :model="formData" :rules="rules" layout="vertical">
|
||||
<a-row :gutter="20">
|
||||
<a-col :span="12">
|
||||
<a-form-item field="name" label="服务名称">
|
||||
<a-input v-model="formData.name" placeholder="请输入服务名称" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item field="room_id" label="机房ID">
|
||||
<a-input v-model="formData.room_id" placeholder="请输入机房ID" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="20">
|
||||
<a-col :span="12">
|
||||
<a-form-item field="device_category" label="设备分类">
|
||||
<a-select v-model="formData.device_category" placeholder="请选择设备分类">
|
||||
<a-option v-for="item in DEVICE_CATEGORY_OPTIONS" :key="item.value" :value="item.value">
|
||||
{{ item.label }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item field="description" label="描述信息">
|
||||
<a-textarea v-model="formData.description" placeholder="请输入描述信息" :rows="2" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item field="agent_config" label="采集地址(HTTP/HTTPS GET)">
|
||||
<a-input v-model="formData.agent_config" placeholder="周期采集地址,返回 JSON 格式指标数组" />
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="20">
|
||||
<a-col :span="12">
|
||||
<a-form-item field="enabled" label="启用设备">
|
||||
<a-switch v-model="formData.enabled" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item field="collect_on" label="参与周期采集">
|
||||
<a-switch v-model="formData.collect_on" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="20">
|
||||
<a-col :span="12">
|
||||
<a-form-item v-if="formData.collect_on" field="collect_interval" label="采集间隔(秒)">
|
||||
<a-input-number v-model="formData.collect_interval" placeholder="默认60秒" :min="10" :max="3600" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item field="policy_ids" label="告警策略">
|
||||
<a-select v-model="formData.policy_ids" placeholder="请选择告警策略" multiple allow-clear>
|
||||
<a-option v-for="policy in policyOptions" :key="policy.id" :value="policy.id">
|
||||
{{ policy.name }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed, watch, onMounted } from 'vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import type { FormInstance } from '@arco-design/web-vue'
|
||||
import {
|
||||
createRoomDevice,
|
||||
updateRoomDevice,
|
||||
DEVICE_CATEGORY_OPTIONS,
|
||||
type RoomDeviceCreateData,
|
||||
type RoomDeviceUpdateData,
|
||||
} from '@/api/ops/room-device'
|
||||
import { fetchPolicyOptions, type PolicyOptionItem } from '@/api/ops/alertPolicy'
|
||||
|
||||
interface Props {
|
||||
visible: boolean
|
||||
record?: any
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
record: () => ({}),
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:visible', 'success'])
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const confirmLoading = ref(false)
|
||||
const policyOptions = ref<PolicyOptionItem[]>([])
|
||||
|
||||
const isEdit = computed(() => !!props.record?.id)
|
||||
|
||||
const formData = reactive({
|
||||
name: '',
|
||||
description: '',
|
||||
room_id: '',
|
||||
device_category: '',
|
||||
agent_config: '',
|
||||
enabled: true,
|
||||
collect_on: true,
|
||||
collect_interval: 60,
|
||||
policy_ids: [] as number[],
|
||||
})
|
||||
|
||||
const rules = {
|
||||
name: [{ required: true, message: '请输入服务名称' }],
|
||||
room_id: [{ required: true, message: '请输入机房ID' }],
|
||||
device_category: [{ required: true, message: '请选择设备分类' }],
|
||||
}
|
||||
|
||||
const loadPolicyOptions = async () => {
|
||||
try {
|
||||
const response: any = await fetchPolicyOptions({ enabled: true })
|
||||
if (Array.isArray(response)) {
|
||||
policyOptions.value = response
|
||||
} else if (response && response.details) {
|
||||
policyOptions.value = Array.isArray(response.details) ? response.details : response.details.data || []
|
||||
} else {
|
||||
policyOptions.value = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载告警策略列表失败:', error)
|
||||
policyOptions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
if (val) {
|
||||
if (isEdit.value && props.record) {
|
||||
Object.assign(formData, {
|
||||
name: props.record.name || '',
|
||||
description: props.record.description || '',
|
||||
room_id: props.record.room_id || '',
|
||||
device_category: props.record.device_category || '',
|
||||
agent_config: props.record.agent_config || '',
|
||||
enabled: props.record.enabled ?? true,
|
||||
collect_on: props.record.collect_on ?? true,
|
||||
collect_interval: props.record.collect_interval || 60,
|
||||
policy_ids: props.record.policy_ids || [],
|
||||
})
|
||||
} else {
|
||||
Object.assign(formData, {
|
||||
name: '',
|
||||
description: '',
|
||||
room_id: '',
|
||||
device_category: '',
|
||||
agent_config: '',
|
||||
enabled: true,
|
||||
collect_on: true,
|
||||
collect_interval: 60,
|
||||
policy_ids: [],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
|
||||
confirmLoading.value = true
|
||||
|
||||
if (isEdit.value) {
|
||||
const updateData: RoomDeviceUpdateData = {
|
||||
name: formData.name,
|
||||
description: formData.description,
|
||||
room_id: formData.room_id,
|
||||
device_category: formData.device_category,
|
||||
agent_config: formData.agent_config,
|
||||
enabled: formData.enabled,
|
||||
collect_on: formData.collect_on,
|
||||
collect_interval: formData.collect_interval,
|
||||
policy_ids: formData.policy_ids,
|
||||
}
|
||||
await updateRoomDevice(props.record.id, updateData)
|
||||
Message.success('更新成功')
|
||||
} else {
|
||||
const createData: RoomDeviceCreateData = {
|
||||
name: formData.name,
|
||||
description: formData.description,
|
||||
room_id: formData.room_id,
|
||||
device_category: formData.device_category,
|
||||
agent_config: formData.agent_config,
|
||||
enabled: formData.enabled,
|
||||
collect_on: formData.collect_on,
|
||||
collect_interval: formData.collect_interval,
|
||||
policy_ids: formData.policy_ids,
|
||||
}
|
||||
await createRoomDevice(createData)
|
||||
Message.success('创建成功')
|
||||
}
|
||||
|
||||
emit('success')
|
||||
handleCancel()
|
||||
} catch (error) {
|
||||
console.error('操作失败:', error)
|
||||
Message.error('操作失败')
|
||||
} finally {
|
||||
confirmLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateVisible = (value: boolean) => {
|
||||
emit('update:visible', value)
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false)
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadPolicyOptions()
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<a-modal :visible="visible" title="采集配置" :mask-closable="false" :ok-loading="loading" @ok="handleSubmit" @cancel="handleCancel">
|
||||
<a-form :model="form" layout="vertical">
|
||||
<a-form-item label="参与周期采集">
|
||||
<a-switch v-model="form.collect_on" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item v-if="form.collect_on" label="采集间隔(秒)">
|
||||
<a-input-number v-model="form.collect_interval" placeholder="默认60秒" :min="10" :max="3600" style="width: 100%" allow-clear />
|
||||
<template #extra>
|
||||
<span style="color: #86909c">分桶间隔(秒),系统将按此间隔周期采集</span>
|
||||
</template>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="采集地址(HTTP/HTTPS GET)">
|
||||
<a-input v-model="form.agent_config" placeholder="周期采集地址,返回 JSON 格式指标数组" />
|
||||
<template #extra>
|
||||
<span style="color: #86909c">采集地址应返回 JSON 格式的指标数据,支持 {"metrics":[...]} 或数组形式</span>
|
||||
</template>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { patchRoomDeviceCollect, type RoomDeviceCollectData } from '@/api/ops/room-device'
|
||||
|
||||
interface Props {
|
||||
visible: boolean
|
||||
record: any
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits(['update:visible', 'success'])
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const form = ref({
|
||||
collect_on: true,
|
||||
collect_interval: 60,
|
||||
agent_config: '',
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
if (val && props.record) {
|
||||
form.value.collect_on = props.record.collect_on ?? true
|
||||
form.value.collect_interval = props.record.collect_interval || 60
|
||||
form.value.agent_config = props.record.agent_config || ''
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const handleSubmit = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data: RoomDeviceCollectData = {
|
||||
collect_on: form.value.collect_on,
|
||||
collect_interval: form.value.collect_interval,
|
||||
agent_config: form.value.agent_config,
|
||||
}
|
||||
|
||||
await patchRoomDeviceCollect(props.record.id, data)
|
||||
|
||||
Message.success('配置成功')
|
||||
emit('success')
|
||||
emit('update:visible', false)
|
||||
} catch (error) {
|
||||
Message.error('配置失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false)
|
||||
}
|
||||
</script>
|
||||
66
src/views/ops/pages/dc/device-collect/config/columns.ts
Normal file
66
src/views/ops/pages/dc/device-collect/config/columns.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { DEVICE_CATEGORY_MAP } from '@/api/ops/room-device'
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
dataIndex: 'id',
|
||||
title: 'ID',
|
||||
width: 80,
|
||||
slotName: 'id',
|
||||
},
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: '服务名称',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
dataIndex: 'room_id',
|
||||
title: '机房ID',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataIndex: 'device_category',
|
||||
title: '设备分类',
|
||||
width: 100,
|
||||
render: ({ record }: any) => {
|
||||
return DEVICE_CATEGORY_MAP[record.device_category] || record.device_category
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'agent_config',
|
||||
title: '采集地址',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'enabled',
|
||||
title: '启用状态',
|
||||
width: 100,
|
||||
slotName: 'enabled',
|
||||
},
|
||||
{
|
||||
dataIndex: 'collect_on',
|
||||
title: '数据采集',
|
||||
width: 100,
|
||||
slotName: 'data_collection',
|
||||
},
|
||||
{
|
||||
dataIndex: 'collect_interval',
|
||||
title: '采集间隔(秒)',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataIndex: 'collect_last_result',
|
||||
title: '采集结果',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'actions',
|
||||
title: '操作',
|
||||
width: 180,
|
||||
fixed: 'right' as const,
|
||||
slotName: 'actions',
|
||||
},
|
||||
]
|
||||
31
src/views/ops/pages/dc/device-collect/config/search-form.ts
Normal file
31
src/views/ops/pages/dc/device-collect/config/search-form.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { FormItem } from '@/components/search-form/types'
|
||||
import { DEVICE_CATEGORY_OPTIONS } from '@/api/ops/room-device'
|
||||
|
||||
export const searchFormConfig: FormItem[] = [
|
||||
{
|
||||
field: 'keyword',
|
||||
label: '关键词',
|
||||
type: 'input',
|
||||
placeholder: '请输入服务名称',
|
||||
span: 6,
|
||||
},
|
||||
{
|
||||
field: 'enabled',
|
||||
label: '启用状态',
|
||||
type: 'select',
|
||||
placeholder: '请选择启用状态',
|
||||
options: [
|
||||
{ label: '已启用', value: true },
|
||||
{ label: '已禁用', value: false },
|
||||
],
|
||||
span: 6,
|
||||
},
|
||||
{
|
||||
field: 'device_category',
|
||||
label: '设备分类',
|
||||
type: 'select',
|
||||
placeholder: '请选择设备分类',
|
||||
options: DEVICE_CATEGORY_OPTIONS,
|
||||
span: 6,
|
||||
},
|
||||
]
|
||||
263
src/views/ops/pages/dc/device-collect/index.vue
Normal file
263
src/views/ops/pages/dc/device-collect/index.vue
Normal file
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<search-table
|
||||
:form-model="formModel"
|
||||
:form-items="formItems"
|
||||
:data="tableData"
|
||||
:columns="columns"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
title="机房设备数据采集"
|
||||
search-button-text="查询"
|
||||
reset-button-text="重置"
|
||||
@update:form-model="handleFormModelUpdate"
|
||||
@search="handleSearch"
|
||||
@reset="handleReset"
|
||||
@page-change="handlePageChange"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #toolbar-left>
|
||||
<a-button type="primary" @click="handleAdd">
|
||||
<template #icon>
|
||||
<icon-plus />
|
||||
</template>
|
||||
新增设备
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<template #id="{ record }">
|
||||
{{ record.id }}
|
||||
</template>
|
||||
|
||||
<template #enabled="{ record }">
|
||||
<a-tag :color="record.enabled ? 'green' : 'gray'">
|
||||
{{ record.enabled ? '已启用' : '已禁用' }}
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
<template #data_collection="{ record }">
|
||||
<a-tag :color="record.collect_on ? 'green' : 'gray'">
|
||||
{{ record.collect_on ? '已启用' : '未启用' }}
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
<template #actions="{ record }">
|
||||
<a-space>
|
||||
<a-dropdown trigger="hover">
|
||||
<a-button type="primary" size="small">
|
||||
管理
|
||||
<icon-down />
|
||||
</a-button>
|
||||
<template #content>
|
||||
<a-doption @click="handleDetail(record)">
|
||||
<template #icon>
|
||||
<icon-eye />
|
||||
</template>
|
||||
详情
|
||||
</a-doption>
|
||||
<a-doption @click="handleEdit(record)">
|
||||
<template #icon>
|
||||
<icon-edit />
|
||||
</template>
|
||||
编辑
|
||||
</a-doption>
|
||||
<a-doption @click="handleQuickConfig(record)">
|
||||
<template #icon>
|
||||
<icon-settings />
|
||||
</template>
|
||||
采集配置
|
||||
</a-doption>
|
||||
<a-doption @click="handleDelete(record)" style="color: rgb(var(--danger-6))">
|
||||
<template #icon>
|
||||
<icon-delete />
|
||||
</template>
|
||||
删除
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</template>
|
||||
</search-table>
|
||||
|
||||
<FormDialog v-model:visible="formDialogVisible" :record="currentRecord" @success="handleFormSuccess" />
|
||||
|
||||
<QuickConfigDialog v-model:visible="quickConfigVisible" :record="currentRecord" @success="handleFormSuccess" />
|
||||
|
||||
<a-drawer v-model:visible="detailVisible" :width="800" title="机房设备详情" :footer="false" unmount-on-close>
|
||||
<Detail
|
||||
v-if="currentRecord"
|
||||
:record="currentRecord"
|
||||
@edit="handleDetailEdit"
|
||||
@quick-config="handleDetailQuickConfig"
|
||||
@delete="handleDetailDelete"
|
||||
/>
|
||||
</a-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { Message, Modal } from '@arco-design/web-vue'
|
||||
import { IconPlus, IconDown, IconEdit, IconDelete, IconEye, IconSettings } from '@arco-design/web-vue/es/icon'
|
||||
import type { FormItem } from '@/components/search-form/types'
|
||||
import SearchTable from '@/components/search-table/index.vue'
|
||||
import { searchFormConfig } from './config/search-form'
|
||||
import FormDialog from './components/FormDialog.vue'
|
||||
import QuickConfigDialog from './components/QuickConfigDialog.vue'
|
||||
import Detail from './components/Detail.vue'
|
||||
import { columns as columnsConfig } from './config/columns'
|
||||
import { fetchRoomDeviceList, deleteRoomDevice, type RoomDeviceItem, type RoomDeviceListParams } from '@/api/ops/room-device'
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref<RoomDeviceItem[]>([])
|
||||
const formDialogVisible = ref(false)
|
||||
const quickConfigVisible = ref(false)
|
||||
const detailVisible = ref(false)
|
||||
const currentRecord = ref<RoomDeviceItem | null>(null)
|
||||
const formModel = ref({
|
||||
keyword: '',
|
||||
enabled: undefined as boolean | undefined,
|
||||
device_category: undefined as string | undefined,
|
||||
})
|
||||
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
})
|
||||
|
||||
const formItems = computed<FormItem[]>(() => searchFormConfig)
|
||||
const columns = computed(() => columnsConfig)
|
||||
|
||||
const fetchRoomDeviceData = async () => {
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const params: RoomDeviceListParams = {
|
||||
page: pagination.current,
|
||||
size: pagination.pageSize,
|
||||
keyword: formModel.value.keyword,
|
||||
enabled: formModel.value.enabled,
|
||||
device_category: formModel.value.device_category,
|
||||
}
|
||||
|
||||
const response: any = await fetchRoomDeviceList(params)
|
||||
|
||||
if (response && response.details) {
|
||||
tableData.value = response.details?.data || []
|
||||
pagination.total = response.details?.total || 0
|
||||
} else {
|
||||
tableData.value = []
|
||||
pagination.total = 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取机房设备列表失败:', error)
|
||||
Message.error('获取机房设备列表失败')
|
||||
tableData.value = []
|
||||
pagination.total = 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.current = 1
|
||||
fetchRoomDeviceData()
|
||||
}
|
||||
|
||||
const handleFormModelUpdate = (value: any) => {
|
||||
formModel.value = value
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
formModel.value = {
|
||||
keyword: '',
|
||||
enabled: undefined,
|
||||
device_category: undefined,
|
||||
}
|
||||
pagination.current = 1
|
||||
fetchRoomDeviceData()
|
||||
}
|
||||
|
||||
const handlePageChange = (current: number) => {
|
||||
pagination.current = current
|
||||
fetchRoomDeviceData()
|
||||
}
|
||||
|
||||
const handleRefresh = () => {
|
||||
fetchRoomDeviceData()
|
||||
Message.success('数据已刷新')
|
||||
}
|
||||
|
||||
const handleAdd = () => {
|
||||
currentRecord.value = null
|
||||
formDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleQuickConfig = (record: RoomDeviceItem) => {
|
||||
currentRecord.value = record
|
||||
quickConfigVisible.value = true
|
||||
}
|
||||
|
||||
const handleEdit = (record: RoomDeviceItem) => {
|
||||
currentRecord.value = record
|
||||
formDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleDetail = (record: RoomDeviceItem) => {
|
||||
currentRecord.value = record
|
||||
detailVisible.value = true
|
||||
}
|
||||
|
||||
const handleDetailEdit = () => {
|
||||
detailVisible.value = false
|
||||
formDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleDetailQuickConfig = () => {
|
||||
detailVisible.value = false
|
||||
quickConfigVisible.value = true
|
||||
}
|
||||
|
||||
const handleDetailDelete = () => {
|
||||
detailVisible.value = false
|
||||
if (currentRecord.value) {
|
||||
handleDelete(currentRecord.value)
|
||||
}
|
||||
}
|
||||
|
||||
const handleFormSuccess = () => {
|
||||
fetchRoomDeviceData()
|
||||
}
|
||||
|
||||
const handleDelete = (record: RoomDeviceItem) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确认删除机房设备 "${record.name}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await deleteRoomDevice(record.id)
|
||||
Message.success('删除成功')
|
||||
fetchRoomDeviceData()
|
||||
} catch (error) {
|
||||
console.error('删除机房设备失败:', error)
|
||||
Message.error('删除失败')
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fetchRoomDeviceData()
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'DeviceCollectManagement',
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user