|
|
@ -20,14 +20,20 @@ |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="asset-workspace"> |
|
|
<div class="asset-workspace"> |
|
|
<t-tabs v-model="tab" class="device-asset-tabs" @change="onTabChange"> |
|
|
|
|
|
|
|
|
<t-tabs v-model="tab" class="device-asset-tabs"> |
|
|
<t-tab-panel value="docks" :label="docksTabLabel" :destroy-on-hide="false" /> |
|
|
<t-tab-panel value="docks" :label="docksTabLabel" :destroy-on-hide="false" /> |
|
|
<t-tab-panel value="drones" :label="dronesTabLabel" :destroy-on-hide="false" /> |
|
|
<t-tab-panel value="drones" :label="dronesTabLabel" :destroy-on-hide="false" /> |
|
|
</t-tabs> |
|
|
</t-tabs> |
|
|
|
|
|
|
|
|
<div class="asset-toolbar"> |
|
|
<div class="asset-toolbar"> |
|
|
<div class="asset-search"> |
|
|
<div class="asset-search"> |
|
|
<t-input v-model="search" clearable placeholder="搜索设备名称、编号或 SN"> |
|
|
|
|
|
|
|
|
<t-input |
|
|
|
|
|
v-model="search" |
|
|
|
|
|
clearable |
|
|
|
|
|
placeholder="搜索设备名称、编号或 SN" |
|
|
|
|
|
@keyup.enter="onSearchCommit" |
|
|
|
|
|
@clear="onSearchCommit" |
|
|
|
|
|
> |
|
|
<template #prefix-icon><t-icon name="search" /></template> |
|
|
<template #prefix-icon><t-icon name="search" /></template> |
|
|
</t-input> |
|
|
</t-input> |
|
|
</div> |
|
|
</div> |
|
|
@ -43,7 +49,7 @@ |
|
|
row-key="id" |
|
|
row-key="id" |
|
|
:data="tableData" |
|
|
:data="tableData" |
|
|
:columns="tableColumns" |
|
|
:columns="tableColumns" |
|
|
empty="暂无符合条件的设备" |
|
|
|
|
|
|
|
|
:empty="tableEmpty" |
|
|
hover |
|
|
hover |
|
|
@row-click="handleRowClick" |
|
|
@row-click="handleRowClick" |
|
|
> |
|
|
> |
|
|
@ -85,7 +91,12 @@ |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="table-footer"> |
|
|
<div class="table-footer"> |
|
|
<span>共 {{ tableData.length }} 条</span> |
|
|
|
|
|
|
|
|
<t-pagination |
|
|
|
|
|
v-model:current="pageNum" |
|
|
|
|
|
:total="total" |
|
|
|
|
|
:page-size="pageSize" |
|
|
|
|
|
@current-change="loadTable" |
|
|
|
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
@ -220,7 +231,7 @@ |
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
|
<script setup> |
|
|
<script setup> |
|
|
import { computed, onMounted, reactive, ref } from 'vue' |
|
|
|
|
|
|
|
|
import { computed, onMounted, reactive, ref, watch } from 'vue' |
|
|
import { useDeviceStore } from '@/stores/modules/devicesStore' |
|
|
import { useDeviceStore } from '@/stores/modules/devicesStore' |
|
|
import { useUiStore } from '@/stores/modules/uiStore' |
|
|
import { useUiStore } from '@/stores/modules/uiStore' |
|
|
import { useRouter } from 'vue-router' |
|
|
import { useRouter } from 'vue-router' |
|
|
@ -236,19 +247,18 @@ const userStore = useUserStore() |
|
|
const isAdmin = computed(() => userStore.isAdmin()) |
|
|
const isAdmin = computed(() => userStore.isAdmin()) |
|
|
|
|
|
|
|
|
const tab = ref('docks') |
|
|
const tab = ref('docks') |
|
|
|
|
|
|
|
|
onMounted(async () => { |
|
|
|
|
|
try { |
|
|
|
|
|
await devices.load() |
|
|
|
|
|
loadedAt.value = new Date().toLocaleTimeString('zh-CN', { hour12: false }) |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
ui.toast(e.message || '加载设备失败') |
|
|
|
|
|
} |
|
|
|
|
|
if (!isAdmin.value) loadFirmwares() |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
const pageNum = ref(1) |
|
|
|
|
|
const pageSize = 20 |
|
|
|
|
|
const total = ref(0) |
|
|
|
|
|
const tableRecords = ref([]) |
|
|
|
|
|
const docksTotal = ref(0) |
|
|
|
|
|
const dronesTotal = ref(0) |
|
|
const search = ref('') |
|
|
const search = ref('') |
|
|
|
|
|
const searchKeyword = ref('') |
|
|
const statusFilter = ref('') |
|
|
const statusFilter = ref('') |
|
|
const bindingFilter = ref('') |
|
|
const bindingFilter = ref('') |
|
|
|
|
|
let searchTimer = null |
|
|
|
|
|
|
|
|
const statusOptions = [ |
|
|
const statusOptions = [ |
|
|
{ label: '全部状态', value: '' }, |
|
|
{ label: '全部状态', value: '' }, |
|
|
{ label: '在线', value: 'online' }, |
|
|
{ label: '在线', value: 'online' }, |
|
|
@ -275,12 +285,17 @@ const upgradeFirmwareId = ref(null) |
|
|
const upgrading = ref(false) |
|
|
const upgrading = ref(false) |
|
|
const firmwareVisible = ref(false) |
|
|
const firmwareVisible = ref(false) |
|
|
const firmwareError = ref('') |
|
|
const firmwareError = ref('') |
|
|
const firmwareRecord = computed(() => (drawerId.value ? devices.record(drawerId.value) : null)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function findLocalRecord(id) { |
|
|
|
|
|
const key = String(id) |
|
|
|
|
|
return tableRecords.value.find((d) => d.id === key) || devices.record(key) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const firmwareRecord = computed(() => (drawerId.value ? findLocalRecord(drawerId.value) : null)) |
|
|
const upgradeFirmwareOptions = computed(() => |
|
|
const upgradeFirmwareOptions = computed(() => |
|
|
firmwareList.value.map((f) => ({ label: firmwareOptionLabel(f), value: f.id })) |
|
|
firmwareList.value.map((f) => ({ label: firmwareOptionLabel(f), value: f.id })) |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
const drawerRecord = computed(() => (drawerId.value ? devices.record(drawerId.value) : null)) |
|
|
|
|
|
|
|
|
const drawerRecord = computed(() => (drawerId.value ? findLocalRecord(drawerId.value) : null)) |
|
|
|
|
|
|
|
|
const overview = computed(() => { |
|
|
const overview = computed(() => { |
|
|
const all = [...devices.docks, ...devices.drones] |
|
|
const all = [...devices.docks, ...devices.drones] |
|
|
@ -317,16 +332,180 @@ function displayCoord(value) { |
|
|
return value == null || value === '' ? '--' : value |
|
|
return value == null || value === '' ? '--' : value |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function matchesFilters(d) { |
|
|
|
|
|
const q = search.value.trim().toLowerCase() |
|
|
|
|
|
|
|
|
function fmtTime(t) { |
|
|
|
|
|
if (!t) return '--' |
|
|
|
|
|
const d = new Date(t) |
|
|
|
|
|
if (Number.isNaN(d.getTime())) return '--' |
|
|
|
|
|
return d.toLocaleString('zh-CN', { hour12: false }) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function parseJson(value, fallback = null) { |
|
|
|
|
|
if (!value) return fallback |
|
|
|
|
|
if (typeof value === 'object') return value |
|
|
|
|
|
try { return JSON.parse(value) } catch { return fallback } |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function alarmCodes(realtime) { |
|
|
|
|
|
const codes = parseJson(realtime?.alarmCodes, []) |
|
|
|
|
|
return Array.isArray(codes) ? codes : [] |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function modeText(m) { |
|
|
|
|
|
const key = String(m || '').toUpperCase() |
|
|
|
|
|
switch (key) { |
|
|
|
|
|
case 'STANDBY': return '待命' |
|
|
|
|
|
case 'AUTO': return 'AUTO' |
|
|
|
|
|
case 'GUIDED': return 'GUIDED' |
|
|
|
|
|
case 'LOITER': return '悬停' |
|
|
|
|
|
case 'RTL': return '返航' |
|
|
|
|
|
default: return m || '--' |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function controlModeText(m) { |
|
|
|
|
|
const key = String(m || '').toLowerCase() |
|
|
|
|
|
if (key === 'auto' || key === 'automatic') return '自动' |
|
|
|
|
|
if (key === 'manual') return '手动' |
|
|
|
|
|
return m || '--' |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function displayValue(value) { |
|
|
|
|
|
return value == null || value === '' ? '--' : String(value) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function coordinate(value, min, max) { |
|
|
|
|
|
const number = Number(value) |
|
|
|
|
|
return Number.isFinite(number) && number >= min && number <= max ? number : null |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function gpsText(q) { |
|
|
|
|
|
const key = String(q || '').toUpperCase().replace(/-/g, '_') |
|
|
|
|
|
switch (key) { |
|
|
|
|
|
case 'RTK_FIX': |
|
|
|
|
|
case 'RTK_FIXED': return 'RTK 固定解' |
|
|
|
|
|
case 'RTK_FLOAT': return 'RTK 浮点解' |
|
|
|
|
|
case '3D_FIX': return '3D 定位' |
|
|
|
|
|
case '2D_FIX': return '2D 定位' |
|
|
|
|
|
default: return q ? String(q) : '无定位' |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function mapDockRow(d, detail = {}) { |
|
|
|
|
|
const id = String(d.id) |
|
|
|
|
|
const rt = detail.realtime || {} |
|
|
|
|
|
const online = Boolean(detail.online) |
|
|
|
|
|
const registerStatus = d.registerStatus || 'registered' |
|
|
|
|
|
const pending = registerStatus === 'pending' && !online |
|
|
|
|
|
const st = pending |
|
|
|
|
|
? { status: '待连接', statusClass: 'pending' } |
|
|
|
|
|
: online |
|
|
|
|
|
? alarmCodes(rt).length ? { status: '告警', statusClass: 'alarm' } : { status: '在线', statusClass: 'online' } |
|
|
|
|
|
: { status: '离线', statusClass: 'offline' } |
|
|
|
|
|
const cachedDrone = devices.drones.find((dr) => dr.dockId === d.dockId) |
|
|
|
|
|
return { |
|
|
|
|
|
id, |
|
|
|
|
|
kind: 'dock', |
|
|
|
|
|
dockId: d.dockId, |
|
|
|
|
|
name: d.name || d.dockId, |
|
|
|
|
|
code: d.code || d.sn || d.dockId, |
|
|
|
|
|
sn: d.sn || d.dockId || '--', |
|
|
|
|
|
iccid: d.iccid || '--', |
|
|
|
|
|
longitude: coordinate(d.longitude, -180, 180), |
|
|
|
|
|
latitude: coordinate(d.latitude, -90, 90), |
|
|
|
|
|
location: d.location || '--', |
|
|
|
|
|
status: st.status, |
|
|
|
|
|
statusClass: st.statusClass, |
|
|
|
|
|
binding: cachedDrone?.name || '--', |
|
|
|
|
|
bindingState: cachedDrone ? 'bound' : 'unbound', |
|
|
|
|
|
mode: controlModeText(rt.controlMode), |
|
|
|
|
|
version: d.softwareVer ? `v${d.softwareVer}` : '--', |
|
|
|
|
|
updated: fmtTime(d.updatedAt), |
|
|
|
|
|
protocol: d.protocolVer ? `MQTT v${d.protocolVer}` : '--', |
|
|
|
|
|
registerStatus, |
|
|
|
|
|
realtime: rt, |
|
|
|
|
|
online |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function mapDroneRow(d, detail = {}) { |
|
|
|
|
|
const id = String(d.id) |
|
|
|
|
|
const rt = detail.realtime || {} |
|
|
|
|
|
const armed = ['1', 'true', 1, true].includes(rt.armed) |
|
|
|
|
|
const altitude = coordinate(rt.altitude, -1000, 100000) |
|
|
|
|
|
const flying = armed || (altitude != null && altitude > 0) |
|
|
|
|
|
const online = Boolean(detail.online) |
|
|
|
|
|
const st = !online |
|
|
|
|
|
? { status: '离线', statusClass: 'offline' } |
|
|
|
|
|
: flying |
|
|
|
|
|
? { status: '飞行中', statusClass: 'mission' } |
|
|
|
|
|
: { status: '在巢', statusClass: 'online' } |
|
|
|
|
|
const dock = devices.docks.find((dk) => dk.dockId === d.dockId) |
|
|
|
|
|
const battery = rt.batteryPercent ?? rt.batteryPct ?? d.battery |
|
|
|
|
|
return { |
|
|
|
|
|
id, |
|
|
|
|
|
kind: 'drone', |
|
|
|
|
|
droneSn: d.droneSn, |
|
|
|
|
|
dockId: d.dockId, |
|
|
|
|
|
name: d.name || d.droneSn, |
|
|
|
|
|
code: d.code || d.droneSn, |
|
|
|
|
|
status: st.status, |
|
|
|
|
|
statusClass: st.statusClass, |
|
|
|
|
|
binding: dock?.name || '--', |
|
|
|
|
|
bindingState: dock ? 'bound' : 'unbound', |
|
|
|
|
|
battery: battery != null && battery !== '' ? `${battery}%` : '--', |
|
|
|
|
|
mode: modeText(rt.flightMode), |
|
|
|
|
|
mission: displayValue(rt.missionName || rt.mission), |
|
|
|
|
|
updated: fmtTime(d.updatedAt), |
|
|
|
|
|
sysid: displayValue(rt.currentSysId), |
|
|
|
|
|
gps: gpsText(rt.gpsQuality), |
|
|
|
|
|
sn: d.droneSn || d.code || '--', |
|
|
|
|
|
model: d.model || '--', |
|
|
|
|
|
firmwareVer: d.firmwareVer || '--', |
|
|
|
|
|
realtime: rt, |
|
|
|
|
|
online |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async function enrichRecords(records, kind) { |
|
|
|
|
|
if (!records.length) return [] |
|
|
|
|
|
const details = await Promise.all( |
|
|
|
|
|
records.map((row) => |
|
|
|
|
|
request |
|
|
|
|
|
.get(kind === 'docks' ? urls.DOCK(row.id) : urls.DRONE(row.id)) |
|
|
|
|
|
.then((r) => r || {}) |
|
|
|
|
|
.catch(() => ({})) |
|
|
|
|
|
) |
|
|
|
|
|
) |
|
|
|
|
|
return records.map((row, i) => (kind === 'docks' ? mapDockRow(row, details[i]) : mapDroneRow(row, details[i]))) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async function loadTable() { |
|
|
|
|
|
const kind = tab.value |
|
|
|
|
|
const params = { pageNum: pageNum.value, pageSize } |
|
|
|
|
|
const keyword = searchKeyword.value.trim() |
|
|
|
|
|
if (keyword) params.keyword = keyword |
|
|
|
|
|
try { |
|
|
|
|
|
const page = await request.get(kind === 'docks' ? urls.DOCKS : urls.DRONES, { params }) |
|
|
|
|
|
const records = page?.records || [] |
|
|
|
|
|
total.value = Number(page?.total) || 0 |
|
|
|
|
|
if (kind === 'docks') docksTotal.value = total.value |
|
|
|
|
|
else dronesTotal.value = total.value |
|
|
|
|
|
tableRecords.value = await enrichRecords(records, kind) |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
tableRecords.value = [] |
|
|
|
|
|
total.value = 0 |
|
|
|
|
|
ui.toast(e.message || '加载设备列表失败') |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function matchesClientFilters(d) { |
|
|
if (statusFilter.value && d.statusClass !== statusFilter.value) return false |
|
|
if (statusFilter.value && d.statusClass !== statusFilter.value) return false |
|
|
if (bindingFilter.value && d.bindingState !== bindingFilter.value) return false |
|
|
if (bindingFilter.value && d.bindingState !== bindingFilter.value) return false |
|
|
if (!q) return true |
|
|
|
|
|
const haystack = [d.name, d.code, d.sn, d.location, d.binding].filter(Boolean).join(' ').toLowerCase() |
|
|
|
|
|
return haystack.includes(q) |
|
|
|
|
|
|
|
|
return true |
|
|
} |
|
|
} |
|
|
const docksTabLabel = computed(() => `机巢设备 ${devices.docks.length}`) |
|
|
|
|
|
const dronesTabLabel = computed(() => `无人机 ${devices.drones.length}`) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const docksTabLabel = computed(() => `机巢设备 ${docksTotal.value || devices.docks.length}`) |
|
|
|
|
|
const dronesTabLabel = computed(() => `无人机 ${dronesTotal.value || devices.drones.length}`) |
|
|
|
|
|
|
|
|
const dockColumns = [ |
|
|
const dockColumns = [ |
|
|
{ colKey: 'name', title: '机巢设备', width: '18%' }, |
|
|
{ colKey: 'name', title: '机巢设备', width: '18%' }, |
|
|
@ -351,26 +530,71 @@ const droneColumns = [ |
|
|
] |
|
|
] |
|
|
|
|
|
|
|
|
const tableColumns = computed(() => (tab.value === 'docks' ? dockColumns : droneColumns)) |
|
|
const tableColumns = computed(() => (tab.value === 'docks' ? dockColumns : droneColumns)) |
|
|
const tableData = computed(() => (tab.value === 'docks' ? filteredDocks.value : filteredDrones.value)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const filteredDocks = computed(() => devices.docks.filter(matchesFilters)) |
|
|
|
|
|
|
|
|
const tableData = computed(() => tableRecords.value.filter(matchesClientFilters)) |
|
|
|
|
|
const tableEmpty = computed(() => |
|
|
|
|
|
statusFilter.value || bindingFilter.value |
|
|
|
|
|
? '当前页无符合条件的设备(状态/绑定仅筛选当前页)' |
|
|
|
|
|
: '暂无符合条件的设备' |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
const filteredDrones = computed(() => devices.drones.filter(matchesFilters)) |
|
|
|
|
|
|
|
|
function onSearchCommit() { |
|
|
|
|
|
if (searchTimer) { |
|
|
|
|
|
clearTimeout(searchTimer) |
|
|
|
|
|
searchTimer = null |
|
|
|
|
|
} |
|
|
|
|
|
const next = search.value.trim() |
|
|
|
|
|
if (searchKeyword.value === next && pageNum.value === 1) { |
|
|
|
|
|
loadTable() |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
searchKeyword.value = next |
|
|
|
|
|
pageNum.value = 1 |
|
|
|
|
|
loadTable() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
watch(search, (value) => { |
|
|
|
|
|
if (searchTimer) clearTimeout(searchTimer) |
|
|
|
|
|
searchTimer = setTimeout(() => { |
|
|
|
|
|
searchTimer = null |
|
|
|
|
|
const next = String(value || '').trim() |
|
|
|
|
|
if (searchKeyword.value === next) return |
|
|
|
|
|
searchKeyword.value = next |
|
|
|
|
|
pageNum.value = 1 |
|
|
|
|
|
loadTable() |
|
|
|
|
|
}, 300) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
function onTabChange() { |
|
|
|
|
|
resetFilters() |
|
|
|
|
|
|
|
|
watch(tab, () => { |
|
|
|
|
|
if (searchTimer) { |
|
|
|
|
|
clearTimeout(searchTimer) |
|
|
|
|
|
searchTimer = null |
|
|
|
|
|
} |
|
|
|
|
|
search.value = '' |
|
|
|
|
|
searchKeyword.value = '' |
|
|
|
|
|
statusFilter.value = '' |
|
|
|
|
|
bindingFilter.value = '' |
|
|
drawerOpen.value = false |
|
|
drawerOpen.value = false |
|
|
} |
|
|
|
|
|
|
|
|
pageNum.value = 1 |
|
|
|
|
|
loadTable() |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
function handleRowClick({ row }) { |
|
|
function handleRowClick({ row }) { |
|
|
openDrawer(row.id) |
|
|
openDrawer(row.id) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function resetFilters() { |
|
|
|
|
|
|
|
|
function resetFilters(reload = true) { |
|
|
|
|
|
if (searchTimer) { |
|
|
|
|
|
clearTimeout(searchTimer) |
|
|
|
|
|
searchTimer = null |
|
|
|
|
|
} |
|
|
search.value = '' |
|
|
search.value = '' |
|
|
|
|
|
searchKeyword.value = '' |
|
|
statusFilter.value = '' |
|
|
statusFilter.value = '' |
|
|
bindingFilter.value = '' |
|
|
bindingFilter.value = '' |
|
|
|
|
|
if (reload) { |
|
|
|
|
|
pageNum.value = 1 |
|
|
|
|
|
loadTable() |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function openDrawer(id) { |
|
|
function openDrawer(id) { |
|
|
@ -384,7 +608,7 @@ function goControl(id) { |
|
|
|
|
|
|
|
|
async function reload() { |
|
|
async function reload() { |
|
|
try { |
|
|
try { |
|
|
await devices.load() |
|
|
|
|
|
|
|
|
await Promise.all([loadTable(), devices.load()]) |
|
|
loadedAt.value = new Date().toLocaleTimeString('zh-CN', { hour12: false }) |
|
|
loadedAt.value = new Date().toLocaleTimeString('zh-CN', { hour12: false }) |
|
|
ui.toast('设备列表已刷新') |
|
|
ui.toast('设备列表已刷新') |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
@ -416,6 +640,7 @@ function openEditDock(dock) { |
|
|
editDockRecord.value = dock |
|
|
editDockRecord.value = dock |
|
|
editDockVisible.value = true |
|
|
editDockVisible.value = true |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async function deleteDock(dock) { |
|
|
async function deleteDock(dock) { |
|
|
const ok = await ui.confirm(`确认硬删除机巢「${dock.name}」?`, '删除后机巢及其关联设备数据将永久移除,且无法恢复。') |
|
|
const ok = await ui.confirm(`确认硬删除机巢「${dock.name}」?`, '删除后机巢及其关联设备数据将永久移除,且无法恢复。') |
|
|
if (!ok) return |
|
|
if (!ok) return |
|
|
@ -423,16 +648,17 @@ async function deleteDock(dock) { |
|
|
await request.delete(urls.DOCK(dock.id)) |
|
|
await request.delete(urls.DOCK(dock.id)) |
|
|
drawerOpen.value = false |
|
|
drawerOpen.value = false |
|
|
ui.toast('机巢已永久删除') |
|
|
ui.toast('机巢已永久删除') |
|
|
|
|
|
await loadTable() |
|
|
await devices.load() |
|
|
await devices.load() |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
ui.toast(e.message || '删除机巢失败') |
|
|
ui.toast(e.message || '删除机巢失败') |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleDockSaved() { |
|
|
async function handleDockSaved() { |
|
|
editDockVisible.value = false |
|
|
editDockVisible.value = false |
|
|
try { |
|
|
try { |
|
|
|
|
|
await loadTable() |
|
|
await devices.load() |
|
|
await devices.load() |
|
|
ui.toast('机巢信息已更新') |
|
|
ui.toast('机巢信息已更新') |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
@ -484,6 +710,7 @@ async function submitAddDock() { |
|
|
}) |
|
|
}) |
|
|
addDockVisible.value = false |
|
|
addDockVisible.value = false |
|
|
ui.toast('机巢已成功接入') |
|
|
ui.toast('机巢已成功接入') |
|
|
|
|
|
await loadTable() |
|
|
await devices.load() |
|
|
await devices.load() |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
addDockError.value = e.message || '接入失败' |
|
|
addDockError.value = e.message || '接入失败' |
|
|
@ -536,6 +763,16 @@ async function doUpgrade() { |
|
|
upgrading.value = false |
|
|
upgrading.value = false |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
onMounted(async () => { |
|
|
|
|
|
try { |
|
|
|
|
|
await Promise.all([devices.load(), loadTable()]) |
|
|
|
|
|
loadedAt.value = new Date().toLocaleTimeString('zh-CN', { hour12: false }) |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
ui.toast(e.message || '加载设备失败') |
|
|
|
|
|
} |
|
|
|
|
|
if (!isAdmin.value) loadFirmwares() |
|
|
|
|
|
}) |
|
|
</script> |
|
|
</script> |
|
|
|
|
|
|
|
|
<style scoped> |
|
|
<style scoped> |
|
|
|