mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-29 07:33:58 +00:00
style: 移除多余空行并统一代码格式
修复代码中的多余空行问题,统一字符串引号使用双引号,调整对象和数组的格式,优化代码缩进和换行,提升代码可读性和一致性
This commit is contained in:
+170
-85
@@ -20,15 +20,15 @@
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-descriptions :column=12 border :direction="'vertical'">
|
||||
<el-descriptions :column="12" border :direction="'vertical'">
|
||||
<el-descriptions-item label="Redis版本">
|
||||
{{ cache.info?.redis_version || '-' }}
|
||||
{{ cache.info?.redis_version || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="运行模式">
|
||||
{{ cache.info?.redis_mode === 'standalone' ? '单机' : '集群' }}
|
||||
{{ cache.info?.redis_mode === "standalone" ? "单机" : "集群" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="端口">
|
||||
{{ cache.info?.tcp_port || '-' }}
|
||||
{{ cache.info?.tcp_port || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="客户端数">
|
||||
{{ cache.info?.connected_clients || 0 }}
|
||||
@@ -37,26 +37,30 @@
|
||||
{{ cache.info?.uptime_in_days || 0 }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="使用内存">
|
||||
{{ cache.info?.used_memory_human || '-' }}
|
||||
{{ cache.info?.used_memory_human || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="使用CPU">
|
||||
{{ cache.info?.used_cpu_user_children ? parseFloat(cache.info.used_cpu_user_children).toFixed(2) : '-'
|
||||
{{
|
||||
cache.info?.used_cpu_user_children
|
||||
? parseFloat(cache.info.used_cpu_user_children).toFixed(2)
|
||||
: "-"
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="内存配置">
|
||||
{{ cache.info?.maxmemory_human || '-' }}
|
||||
{{ cache.info?.maxmemory_human || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="AOF是否开启">
|
||||
{{ cache.info?.aof_enabled === '0' ? '否' : '是' }}
|
||||
{{ cache.info?.aof_enabled === "0" ? "否" : "是" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="RDB是否成功">
|
||||
{{ cache.info?.rdb_last_bgsave_status || '-' }}
|
||||
{{ cache.info?.rdb_last_bgsave_status || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="Key数量">
|
||||
{{ cache.db_size || 0 }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="网络入口/出口">
|
||||
{{ `${cache.info?.instantaneous_input_kbps || 0}kps/${cache.info?.instantaneous_output_kbps || 0}kps`
|
||||
{{
|
||||
`${cache.info?.instantaneous_input_kbps || 0}kps/${cache.info?.instantaneous_output_kbps || 0}kps`
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
@@ -124,25 +128,55 @@
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div>
|
||||
<el-button v-hasPerm="['module_monitor:cache:refresh']" type="primary" link icon="RefreshRight" @click="refreshCacheNames"/>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:cache:refresh']"
|
||||
type="primary"
|
||||
link
|
||||
icon="RefreshRight"
|
||||
@click="refreshCacheNames"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-table :loading="loading" :data="cacheNames" row-key="cache_name" height="600" border>
|
||||
<el-table
|
||||
:loading="loading"
|
||||
:data="cacheNames"
|
||||
row-key="cache_name"
|
||||
height="600"
|
||||
border
|
||||
>
|
||||
<template #empty>
|
||||
<el-empty :image-size="80" description="暂无数据" />
|
||||
</template>
|
||||
<el-table-column prop="cache_name" label="缓存名称" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-button v-hasPerm="['module_monitor:cache:view']" type="primary" link @click="getCacheKeyList(row)">{{ row.cache_name }}</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:cache:view']"
|
||||
type="primary"
|
||||
link
|
||||
@click="getCacheKeyList(row)"
|
||||
>
|
||||
{{ row.cache_name }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="60" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-popconfirm class="box-item" :title="`确认删除缓存 ${row.cache_name} 吗?`" placement="top" @confirm="handleClearCacheName(row)">
|
||||
<el-popconfirm
|
||||
class="box-item"
|
||||
:title="`确认删除缓存 ${row.cache_name} 吗?`"
|
||||
placement="top"
|
||||
@confirm="handleClearCacheName(row)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button v-hasPerm="['module_monitor:cache:delete']" type="danger" size="small" link icon="delete"/>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:cache:delete']"
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
icon="delete"
|
||||
/>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
@@ -168,24 +202,54 @@
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div>
|
||||
<el-button v-hasPerm="['module_monitor:cache:refresh']" type="primary" link icon="RefreshRight" @click="refreshCacheKeys"/>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:cache:refresh']"
|
||||
type="primary"
|
||||
link
|
||||
icon="RefreshRight"
|
||||
@click="refreshCacheKeys"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-table :loading="subLoading" :data="cacheKeys.map(key => ({ cacheKey: key }))" height="600" row-key="cacheKey" border>
|
||||
<el-table
|
||||
:loading="subLoading"
|
||||
:data="cacheKeys.map((key) => ({ cacheKey: key }))"
|
||||
height="600"
|
||||
row-key="cacheKey"
|
||||
border
|
||||
>
|
||||
<template #empty>
|
||||
<el-empty :image-size="80" description="暂无数据" />
|
||||
</template>
|
||||
<el-table-column prop="cacheKey" label="缓存键名" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-button v-hasPerm="['module_monitor:cache:detail']" type="primary" link @click="handleCacheValue(row.cacheKey)">{{ row.cacheKey}}</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:cache:detail']"
|
||||
type="primary"
|
||||
link
|
||||
@click="handleCacheValue(row.cacheKey)"
|
||||
>
|
||||
{{ row.cacheKey }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="60" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-popconfirm class="box-item" :title="`确认删除键 ${row.cacheKey} 吗?`" placement="top" @confirm="handleClearCacheKey(row.cacheKey)">
|
||||
<el-popconfirm
|
||||
class="box-item"
|
||||
:title="`确认删除键 ${row.cacheKey} 吗?`"
|
||||
placement="top"
|
||||
@confirm="handleClearCacheKey(row.cacheKey)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button v-hasPerm="['module_monitor:cache:delete']" type="danger" size="small" link icon="delete"/>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:cache:delete']"
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
icon="delete"
|
||||
/>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
@@ -211,7 +275,15 @@
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div>
|
||||
<el-button v-hasPerm="['module_monitor:cache:delete_all']" type="danger" link icon="delete" @click="handleClearCacheAll">清理全部</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:cache:delete_all']"
|
||||
type="danger"
|
||||
link
|
||||
icon="delete"
|
||||
@click="handleClearCacheAll"
|
||||
>
|
||||
清理全部
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -223,7 +295,13 @@
|
||||
<el-input v-model="cacheForm.cache_key" readonly placeholder="缓存键名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="缓存内容">
|
||||
<el-input v-model="cacheForm.cache_value" type="textarea" :rows="18" readonly placeholder="缓存内容" />
|
||||
<el-input
|
||||
v-model="cacheForm.cache_value"
|
||||
type="textarea"
|
||||
:rows="18"
|
||||
readonly
|
||||
placeholder="缓存内容"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
@@ -235,26 +313,31 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import CacheAPI, { type CacheInfo, type CacheForm, type CacheMonitor, type RedisInfo } from "@/api/module_monitor/cache";
|
||||
import * as echarts from 'echarts';
|
||||
import CacheAPI, {
|
||||
type CacheInfo,
|
||||
type CacheForm,
|
||||
type CacheMonitor,
|
||||
type RedisInfo,
|
||||
} from "@/api/module_monitor/cache";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
// 响应式状态定义
|
||||
const cacheNames = ref<CacheInfo[]>([]);
|
||||
const cacheKeys = ref<string[]>([]);
|
||||
const loading = ref(true);
|
||||
const subLoading = ref(false);
|
||||
const nowCacheName = ref('');
|
||||
const nowCacheName = ref("");
|
||||
const commandstats = ref<HTMLElement | null>(null);
|
||||
const usedmemory = ref<HTMLElement | null>(null);
|
||||
const cache = ref<CacheMonitor>({
|
||||
info: {} as RedisInfo,
|
||||
command_stats: [],
|
||||
db_size: 0
|
||||
db_size: 0,
|
||||
});
|
||||
const cacheForm = ref<CacheForm>({
|
||||
cache_name: '',
|
||||
cache_key: '',
|
||||
cache_value: ''
|
||||
cache_name: "",
|
||||
cache_key: "",
|
||||
cache_value: "",
|
||||
});
|
||||
|
||||
let commandstatsInstance: echarts.ECharts | null = null;
|
||||
@@ -263,9 +346,9 @@ let usedmemoryInstance: echarts.ECharts | null = null;
|
||||
const resetCacheForm = () => {
|
||||
cacheKeys.value = [];
|
||||
cacheForm.value = {
|
||||
cache_name: '',
|
||||
cache_key: '',
|
||||
cache_value: ''
|
||||
cache_name: "",
|
||||
cache_key: "",
|
||||
cache_value: "",
|
||||
};
|
||||
};
|
||||
|
||||
@@ -273,11 +356,11 @@ const resetCacheForm = () => {
|
||||
const getCacheNameList = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await CacheAPI.getCacheNames()
|
||||
const response = await CacheAPI.getCacheNames();
|
||||
cacheNames.value = response.data.data;
|
||||
resetCacheForm();
|
||||
} catch (error) {
|
||||
console.error('获取缓存列表出错:', error);
|
||||
console.error("获取缓存列表出错:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -294,7 +377,7 @@ const handleClearCacheName = async (row: CacheInfo) => {
|
||||
await CacheAPI.deleteCacheName(row.cache_name);
|
||||
refreshCacheNames();
|
||||
} catch (error) {
|
||||
console.error('清理缓存名称出错:', error);
|
||||
console.error("清理缓存名称出错:", error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -310,11 +393,11 @@ const getCacheKeyList = async (row?: CacheInfo) => {
|
||||
nowCacheName.value = cacheName;
|
||||
cacheForm.value = {
|
||||
cache_name: cacheName,
|
||||
cache_key: '',
|
||||
cache_value: ''
|
||||
cache_key: "",
|
||||
cache_value: "",
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取缓存键名列表出错:', error);
|
||||
console.error("获取缓存键名列表出错:", error);
|
||||
} finally {
|
||||
subLoading.value = false;
|
||||
}
|
||||
@@ -331,34 +414,30 @@ async function handleClearCacheKey(cacheKey: string) {
|
||||
await CacheAPI.deleteCacheKey(cacheKey);
|
||||
getCacheKeyList();
|
||||
} catch (error) {
|
||||
console.error('清理缓存键名出错:', error);
|
||||
console.error("清理缓存键名出错:", error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 缓存内容相关方法
|
||||
async function handleCacheValue(cacheKey: string) {
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await CacheAPI.getCacheValue(nowCacheName.value, cacheKey)
|
||||
const response = await CacheAPI.getCacheValue(nowCacheName.value, cacheKey);
|
||||
cacheForm.value = response.data.data;
|
||||
} catch (error) {
|
||||
console.error('获取缓存内容失败:', error);
|
||||
console.error("获取缓存内容失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 清理全部缓存
|
||||
const handleClearCacheAll = async () => {
|
||||
ElMessageBox.confirm(
|
||||
'确定要清理全部缓存吗?',
|
||||
'危险!',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
ElMessageBox.confirm("确定要清理全部缓存吗?", "危险!", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(async () => {
|
||||
return await CacheAPI.deleteCacheAll();
|
||||
})
|
||||
@@ -366,8 +445,8 @@ const handleClearCacheAll = async () => {
|
||||
getCacheNameList();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error !== 'cancel') {
|
||||
console.error('清理全部缓存失败:', error);
|
||||
if (error !== "cancel") {
|
||||
console.error("清理全部缓存失败:", error);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -376,15 +455,15 @@ const handleClearCacheAll = async () => {
|
||||
const getInfo = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await CacheAPI.getCacheInfo()
|
||||
const response = await CacheAPI.getCacheInfo();
|
||||
cache.value = response.data.data || {
|
||||
info: {},
|
||||
command_stats: [],
|
||||
dbSize: 0
|
||||
dbSize: 0,
|
||||
};
|
||||
initCharts();
|
||||
} catch (error) {
|
||||
console.error('获取缓存监控数据失败:', error);
|
||||
console.error("获取缓存监控数据失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -394,44 +473,50 @@ const getInfo = async () => {
|
||||
const initCharts = () => {
|
||||
if (!commandstats.value || !usedmemory.value) return;
|
||||
|
||||
commandstatsInstance = echarts.init(commandstats.value, 'macarons');
|
||||
usedmemoryInstance = echarts.init(usedmemory.value, 'macarons');
|
||||
commandstatsInstance = echarts.init(commandstats.value, "macarons");
|
||||
usedmemoryInstance = echarts.init(usedmemory.value, "macarons");
|
||||
|
||||
const commandStatsOption = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b} : {c} ({d}%)'
|
||||
trigger: "item",
|
||||
formatter: "{a} <br/>{b} : {c} ({d}%)",
|
||||
},
|
||||
series: [{
|
||||
name: '命令',
|
||||
type: 'pie',
|
||||
roseType: 'radius',
|
||||
radius: [15, 95],
|
||||
center: ['50%', '38%'],
|
||||
data: cache.value.command_stats || [],
|
||||
animationEasing: 'cubicInOut',
|
||||
animationDuration: 1000
|
||||
}]
|
||||
series: [
|
||||
{
|
||||
name: "命令",
|
||||
type: "pie",
|
||||
roseType: "radius",
|
||||
radius: [15, 95],
|
||||
center: ["50%", "38%"],
|
||||
data: cache.value.command_stats || [],
|
||||
animationEasing: "cubicInOut",
|
||||
animationDuration: 1000,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const usedMemory = cache.value.info?.used_memory_human || '0';
|
||||
const usedMemory = cache.value.info?.used_memory_human || "0";
|
||||
const usedMemoryOption = {
|
||||
tooltip: {
|
||||
formatter: `{b} <br/>{a} : ${usedMemory}`
|
||||
formatter: `{b} <br/>{a} : ${usedMemory}`,
|
||||
},
|
||||
series: [{
|
||||
name: '峰值',
|
||||
type: 'gauge',
|
||||
min: 0,
|
||||
max: 1000,
|
||||
detail: {
|
||||
formatter: usedMemory
|
||||
series: [
|
||||
{
|
||||
name: "峰值",
|
||||
type: "gauge",
|
||||
min: 0,
|
||||
max: 1000,
|
||||
detail: {
|
||||
formatter: usedMemory,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: parseFloat(usedMemory) || 0,
|
||||
name: "内存消耗",
|
||||
},
|
||||
],
|
||||
},
|
||||
data: [{
|
||||
value: parseFloat(usedMemory) || 0,
|
||||
name: '内存消耗'
|
||||
}]
|
||||
}]
|
||||
],
|
||||
};
|
||||
|
||||
commandstatsInstance.setOption(commandStatsOption);
|
||||
|
||||
@@ -3,7 +3,13 @@
|
||||
<div class="app-container">
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-container">
|
||||
<el-form ref="queryFormRef" :model="queryFormData" :inline="true" label-suffix=":" @submit.prevent="handleQuery" >
|
||||
<el-form
|
||||
ref="queryFormRef"
|
||||
:model="queryFormData"
|
||||
:inline="true"
|
||||
label-suffix=":"
|
||||
@submit.prevent="handleQuery"
|
||||
>
|
||||
<el-form-item prop="ipaddr" label="IP地址">
|
||||
<el-input v-model="queryFormData.ipaddr" placeholder="请输入IP地址" clearable />
|
||||
</el-form-item>
|
||||
@@ -15,8 +21,21 @@
|
||||
</el-form-item>
|
||||
<!-- 查询、重置、展开/收起按钮 -->
|
||||
<el-form-item class="search-buttons">
|
||||
<el-button v-hasPerm="['module_monitor:online:query']" type="primary" icon="search" native-type="submit">查询</el-button>
|
||||
<el-button v-hasPerm="['module_monitor:online:query']" icon="refresh" @click="handleResetQuery">重置</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:online:query']"
|
||||
type="primary"
|
||||
icon="search"
|
||||
native-type="submit"
|
||||
>
|
||||
查询
|
||||
</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:online:query']"
|
||||
icon="refresh"
|
||||
@click="handleResetQuery"
|
||||
>
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@@ -39,7 +58,14 @@
|
||||
<div class="data-table__toolbar--left">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPerm="['module_monitor:online:force_logout']" type="danger" icon="delete" @click="handleClear">强退所有</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:online:force_logout']"
|
||||
type="danger"
|
||||
icon="delete"
|
||||
@click="handleClear"
|
||||
>
|
||||
强退所有
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
@@ -47,7 +73,13 @@
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-tooltip content="刷新">
|
||||
<el-button v-hasPerm="['module_monitor:online:refresh']" type="primary" icon="refresh" circle @click="handleRefresh"/>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:online:refresh']"
|
||||
type="primary"
|
||||
icon="refresh"
|
||||
circle
|
||||
@click="handleRefresh"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
@@ -67,29 +99,117 @@
|
||||
</div>
|
||||
|
||||
<!-- 表格区域:系统配置列表 -->
|
||||
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" :height="450" border stripe @selection-change="handleSelectionChange">
|
||||
<el-table
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="pageTableData"
|
||||
highlight-current-row
|
||||
class="data-table__content"
|
||||
:height="450"
|
||||
border
|
||||
stripe
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<template #empty>
|
||||
<el-empty :image-size="80" description="暂无数据" />
|
||||
</template>
|
||||
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" align="center" />
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" min-width="60" />
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'session_id')?.show" key="session_id" label="会话编号" prop="session_id" min-width="250" show-overflow-tooltip/>
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'login_type')?.show" key="login_type" label="登录类型" prop="login_type" min-width="100" />
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'ipaddr')?.show" key="ipaddr" label="IP地址" prop="ipaddr" min-width="150" show-overflow-tooltip>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'selection')?.show"
|
||||
type="selection"
|
||||
min-width="55"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'index')?.show"
|
||||
type="index"
|
||||
fixed
|
||||
label="序号"
|
||||
min-width="60"
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'session_id')?.show"
|
||||
key="session_id"
|
||||
label="会话编号"
|
||||
prop="session_id"
|
||||
min-width="250"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'login_type')?.show"
|
||||
key="login_type"
|
||||
label="登录类型"
|
||||
prop="login_type"
|
||||
min-width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'ipaddr')?.show"
|
||||
key="ipaddr"
|
||||
label="IP地址"
|
||||
prop="ipaddr"
|
||||
min-width="150"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-text>{{ scope.row.ipaddr }}</el-text>
|
||||
<CopyButton v-if="scope.row.ipaddr" :text="scope.row.ipaddr" style="margin-left: 2px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="用户名" prop="name" min-width="80" show-overflow-tooltip />
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'user_name')?.show" key="user_name" label="账号" prop="user_name" min-width="80" />
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'login_location')?.show" key="login_location" label="登录位置" prop="login_location" min-width="280" show-overflow-tooltip/>
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'os')?.show" key="os" label="操作系统" prop="os" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'login_time')?.show" key="login_time" label="登录时间" prop="login_time" min-width="180" />
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" key="operation" fixed="right" label="操作" min-width="100">
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'name')?.show"
|
||||
key="name"
|
||||
label="用户名"
|
||||
prop="name"
|
||||
min-width="80"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'user_name')?.show"
|
||||
key="user_name"
|
||||
label="账号"
|
||||
prop="user_name"
|
||||
min-width="80"
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'login_location')?.show"
|
||||
key="login_location"
|
||||
label="登录位置"
|
||||
prop="login_location"
|
||||
min-width="280"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'os')?.show"
|
||||
key="os"
|
||||
label="操作系统"
|
||||
prop="os"
|
||||
min-width="120"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'login_time')?.show"
|
||||
key="login_time"
|
||||
label="登录时间"
|
||||
prop="login_time"
|
||||
min-width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="tableColumns.find((col) => col.prop === 'operation')?.show"
|
||||
key="operation"
|
||||
fixed="right"
|
||||
label="操作"
|
||||
min-width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button v-hasPerm="['module_monitor:online:force_logout']" type="danger" size="small" link icon="delete" @click="handleSubmit(scope.row.session_id)">强退
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:online:force_logout']"
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
icon="delete"
|
||||
@click="handleSubmit(scope.row.session_id)"
|
||||
>
|
||||
强退
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -97,12 +217,15 @@
|
||||
|
||||
<!-- 分页区域 -->
|
||||
<template #footer>
|
||||
<pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
|
||||
<pagination
|
||||
v-model:total="total"
|
||||
v-model:page="queryFormData.page_no"
|
||||
v-model:limit="queryFormData.page_size"
|
||||
@pagination="loadingData"
|
||||
/>
|
||||
</template>
|
||||
</el-card>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -111,7 +234,10 @@ defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
import OnlineAPI, { type OnlineUserPageQuery, type OnlineUserTable } from "@/api/module_monitor/online";
|
||||
import OnlineAPI, {
|
||||
type OnlineUserPageQuery,
|
||||
type OnlineUserTable,
|
||||
} from "@/api/module_monitor/online";
|
||||
|
||||
const queryFormRef = ref();
|
||||
const total = ref(0);
|
||||
@@ -121,20 +247,19 @@ const loading = ref(false);
|
||||
// 分页表单
|
||||
const pageTableData = ref<OnlineUserTable[]>([]);
|
||||
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: '选择框', prop: 'selection', show: true },
|
||||
{ label: '序号', prop: 'index', show: true },
|
||||
{ label: '会话编号', prop: 'session_id', show: true },
|
||||
{ label: '登录类型', prop: 'login_type', show: true },
|
||||
{ label: '登录名称', prop: 'name', show: true },
|
||||
{ label: '用户账号', prop: 'user_name', show: true },
|
||||
{ label: '主机', prop: 'ipaddr', show: true },
|
||||
{ label: '登录地点', prop: 'login_location', show: true },
|
||||
{ label: '操作系统', prop: 'os', show: true },
|
||||
{ label: '登录时间', prop: 'login_time', show: true },
|
||||
{ label: '操作', prop: 'operation', show: true }
|
||||
{ label: "选择框", prop: "selection", show: true },
|
||||
{ label: "序号", prop: "index", show: true },
|
||||
{ label: "会话编号", prop: "session_id", show: true },
|
||||
{ label: "登录类型", prop: "login_type", show: true },
|
||||
{ label: "登录名称", prop: "name", show: true },
|
||||
{ label: "用户账号", prop: "user_name", show: true },
|
||||
{ label: "主机", prop: "ipaddr", show: true },
|
||||
{ label: "登录地点", prop: "login_location", show: true },
|
||||
{ label: "操作系统", prop: "os", show: true },
|
||||
{ label: "登录时间", prop: "login_time", show: true },
|
||||
{ label: "操作", prop: "operation", show: true },
|
||||
]);
|
||||
|
||||
// 分页查询参数
|
||||
@@ -143,13 +268,13 @@ const queryFormData = reactive<OnlineUserPageQuery>({
|
||||
page_size: 10,
|
||||
name: undefined,
|
||||
login_location: undefined,
|
||||
ipaddr: undefined
|
||||
ipaddr: undefined,
|
||||
});
|
||||
|
||||
// 列表刷新
|
||||
async function handleRefresh () {
|
||||
async function handleRefresh() {
|
||||
await loadingData();
|
||||
};
|
||||
}
|
||||
|
||||
// 加载表格数据
|
||||
async function loadingData() {
|
||||
@@ -158,11 +283,9 @@ async function loadingData() {
|
||||
const response = await OnlineAPI.getOnlineList(queryFormData);
|
||||
pageTableData.value = response.data.data.items;
|
||||
total.value = response.data.data.total;
|
||||
}
|
||||
catch (error: any) {
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
@@ -191,19 +314,21 @@ async function handleSubmit(session_id: string) {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
await OnlineAPI.deleteOnline(session_id);
|
||||
handleResetQuery();
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}).catch(() => {
|
||||
ElMessageBox.close();
|
||||
});
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
await OnlineAPI.deleteOnline(session_id);
|
||||
handleResetQuery();
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessageBox.close();
|
||||
});
|
||||
}
|
||||
|
||||
// 强退所有
|
||||
@@ -212,19 +337,21 @@ async function handleClear() {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
await OnlineAPI.clearOnline();
|
||||
handleResetQuery();
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}).catch(() => {
|
||||
ElMessageBox.close();
|
||||
});
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
await OnlineAPI.clearOnline();
|
||||
handleResetQuery();
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessageBox.close();
|
||||
});
|
||||
}
|
||||
onMounted(() => {
|
||||
loadingData();
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
<div class="app-container">
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-container">
|
||||
<el-form ref="queryFormRef" :model="queryFormData" :inline="true" label-suffix=":" @submit.prevent="handleQuery">
|
||||
<el-form
|
||||
ref="queryFormRef"
|
||||
:model="queryFormData"
|
||||
:inline="true"
|
||||
label-suffix=":"
|
||||
@submit.prevent="handleQuery"
|
||||
>
|
||||
<el-form-item prop="name" label="关键词">
|
||||
<el-input
|
||||
v-model="queryFormData.name"
|
||||
@@ -13,8 +19,21 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="search-buttons">
|
||||
<el-button v-hasPerm="['module_monitor:resource:query']" type="primary" icon="search" native-type="submit">查询</el-button>
|
||||
<el-button v-hasPerm="['module_monitor:resource:query']" icon="refresh" @click="handleResetQuery">重置</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:query']"
|
||||
type="primary"
|
||||
icon="search"
|
||||
native-type="submit"
|
||||
>
|
||||
查询
|
||||
</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:query']"
|
||||
icon="refresh"
|
||||
@click="handleResetQuery"
|
||||
>
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@@ -31,7 +50,6 @@
|
||||
</span>
|
||||
<!-- 资源路径 -->
|
||||
<div class="breadcrumb-container">
|
||||
|
||||
<span class="breadcrumb-label"></span>
|
||||
<el-breadcrumb separator="/">
|
||||
<el-breadcrumb-item
|
||||
@@ -52,20 +70,46 @@
|
||||
<div class="data-table__toolbar--left">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPerm="['module_monitor:resource:upload']" type="success" icon="plus" @click="handleUpload">上传文件</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:upload']"
|
||||
type="success"
|
||||
icon="plus"
|
||||
@click="handleUpload"
|
||||
>
|
||||
上传文件
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPerm="['module_monitor:resource:create_dir']" type="primary" icon="folder-add" @click="handleCreateDir">新建文件夹</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:create_dir']"
|
||||
type="primary"
|
||||
icon="folder-add"
|
||||
@click="handleCreateDir"
|
||||
>
|
||||
新建文件夹
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPerm="['module_monitor:resource:delete']" type="danger" icon="delete" :disabled="selectedItems.length === 0" @click="handleBatchDelete">批量删除</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:delete']"
|
||||
type="danger"
|
||||
icon="delete"
|
||||
:disabled="selectedItems.length === 0"
|
||||
@click="handleBatchDelete"
|
||||
>
|
||||
批量删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="data-table__toolbar--right">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-checkbox v-model="showHiddenFiles" v-hasPerm="['module_monitor:resource:show_hidden']" @change="handleShowHiddenChange">
|
||||
<el-checkbox
|
||||
v-model="showHiddenFiles"
|
||||
v-hasPerm="['module_monitor:resource:show_hidden']"
|
||||
@change="handleShowHiddenChange"
|
||||
>
|
||||
显示隐藏文件
|
||||
</el-checkbox>
|
||||
</el-col>
|
||||
@@ -89,7 +133,13 @@
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-tooltip content="刷新">
|
||||
<el-button v-hasPerm="['module_monitor:resource:refresh']" type="primary" icon="refresh" circle @click="handleRefresh"/>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:refresh']"
|
||||
type="primary"
|
||||
icon="refresh"
|
||||
circle
|
||||
@click="handleRefresh"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -121,7 +171,7 @@
|
||||
<Folder v-if="row.is_dir" />
|
||||
<Document v-else />
|
||||
</el-icon>
|
||||
<span
|
||||
<span
|
||||
v-hasPerm="['module_monitor:resource:preview']"
|
||||
:class="{ 'file-name-clickable': true }"
|
||||
@click="handleFileNameClick(row)"
|
||||
@@ -137,7 +187,13 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="修改时间" prop="modified_time" min-width="180" sortable />
|
||||
<el-table-column fixed="right" label="操作" align="center" min-width="200" class="search-buttons">
|
||||
<el-table-column
|
||||
fixed="right"
|
||||
label="操作"
|
||||
align="center"
|
||||
min-width="200"
|
||||
class="search-buttons"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="!row.is_dir"
|
||||
@@ -150,10 +206,24 @@
|
||||
>
|
||||
下载
|
||||
</el-button>
|
||||
<el-button v-hasPerm="['module_monitor:resource:rename']" type="primary" size="small" link icon="edit" @click="handleRename(row)">
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:rename']"
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
icon="edit"
|
||||
@click="handleRename(row)"
|
||||
>
|
||||
重命名
|
||||
</el-button>
|
||||
<el-button v-hasPerm="['module_monitor:resource:delete']" type="danger" size="small" link icon="delete" @click="handleDelete(row)">
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:delete']"
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
icon="delete"
|
||||
@click="handleDelete(row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -179,9 +249,9 @@
|
||||
<div class="item-name">{{ item.name }}</div>
|
||||
<div v-if="!item.is_dir" class="item-size">
|
||||
{{ formatFileSize(item.size) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页区域 -->
|
||||
<template #footer>
|
||||
@@ -211,28 +281,30 @@
|
||||
>
|
||||
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或<em>点击上传</em>
|
||||
将文件拖到此处,或
|
||||
<em>点击上传</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip" style="color: red;">
|
||||
<div class="el-upload__tip" style="color: red">
|
||||
不支持多文件上传,单个文件不超过100MB,多文件上传,取最后一个文件上传
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<template #footer>
|
||||
<el-button @click="uploadDialogVisible = false">取消</el-button>
|
||||
<el-button v-hasPerm="['module_monitor:resource:upload']" type="primary" :loading="uploading" @click="handleUploadConfirm">
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:upload']"
|
||||
type="primary"
|
||||
:loading="uploading"
|
||||
@click="handleUploadConfirm"
|
||||
>
|
||||
确定上传
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 新建文件夹对话框 -->
|
||||
<el-dialog
|
||||
v-model="createDirDialogVisible"
|
||||
title="新建文件夹"
|
||||
width="400px"
|
||||
>
|
||||
<el-dialog v-model="createDirDialogVisible" title="新建文件夹" width="400px">
|
||||
<el-form :model="createDirForm" label-width="80px">
|
||||
<el-form-item label="文件夹名" required>
|
||||
<el-input
|
||||
@@ -244,16 +316,18 @@
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="createDirDialogVisible = false">取消</el-button>
|
||||
<el-button v-hasPerm="['module_monitor:resource:create_dir']" type="primary" @click="handleCreateDirConfirm">确定</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:create_dir']"
|
||||
type="primary"
|
||||
@click="handleCreateDirConfirm"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 重命名对话框 -->
|
||||
<el-dialog
|
||||
v-model="renameDialogVisible"
|
||||
title="重命名"
|
||||
width="400px"
|
||||
>
|
||||
<el-dialog v-model="renameDialogVisible" title="重命名" width="400px">
|
||||
<el-form :model="renameForm" label-width="80px">
|
||||
<el-form-item label="新名称" required>
|
||||
<el-input
|
||||
@@ -265,7 +339,13 @@
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="renameDialogVisible = false">取消</el-button>
|
||||
<el-button v-hasPerm="['module_monitor:resource:rename']" type="primary" @click="handleRenameConfirm">确定</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['module_monitor:resource:rename']"
|
||||
type="primary"
|
||||
@click="handleRenameConfirm"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -277,66 +357,70 @@ defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ref, reactive, onMounted, computed } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import {
|
||||
List,
|
||||
Grid,
|
||||
Folder,
|
||||
Document,
|
||||
UploadFilled,
|
||||
QuestionFilled
|
||||
} from '@element-plus/icons-vue'
|
||||
import { ResourceAPI, type ResourceItem, type ResourcePageQuery } from '@/api/module_monitor/resource'
|
||||
QuestionFilled,
|
||||
} from "@element-plus/icons-vue";
|
||||
import {
|
||||
ResourceAPI,
|
||||
type ResourceItem,
|
||||
type ResourcePageQuery,
|
||||
} from "@/api/module_monitor/resource";
|
||||
|
||||
// 分页表单
|
||||
const fileList = ref<ResourceItem[]>([])
|
||||
const fileList = ref<ResourceItem[]>([]);
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const selectedItems = ref<ResourceItem[]>([])
|
||||
const breadcrumbList = ref([{ name: '资源根目录', path: '/' }])
|
||||
const showHiddenFiles = ref(false)
|
||||
const viewMode = ref<'list' | 'grid'>('list')
|
||||
const total = ref(0)
|
||||
const isSearchMode = ref(false) // 用于标记是否处于搜索模式
|
||||
const queryFormRef = ref()
|
||||
const loading = ref(false);
|
||||
const selectedItems = ref<ResourceItem[]>([]);
|
||||
const breadcrumbList = ref([{ name: "资源根目录", path: "/" }]);
|
||||
const showHiddenFiles = ref(false);
|
||||
const viewMode = ref<"list" | "grid">("list");
|
||||
const total = ref(0);
|
||||
const isSearchMode = ref(false); // 用于标记是否处于搜索模式
|
||||
const queryFormRef = ref();
|
||||
|
||||
// 路径相关数据
|
||||
const currentPath = ref('/') // 当前路径的响应式变量
|
||||
const currentPath = ref("/"); // 当前路径的响应式变量
|
||||
|
||||
// 分页查询参数
|
||||
const pagination = reactive({
|
||||
page_no: 1,
|
||||
page_size: 10
|
||||
})
|
||||
page_size: 10,
|
||||
});
|
||||
|
||||
// 搜索表单数据
|
||||
const queryFormData = reactive<ResourcePageQuery>({
|
||||
name: undefined,
|
||||
page_no: 1,
|
||||
page_size: 10
|
||||
})
|
||||
page_size: 10,
|
||||
});
|
||||
|
||||
// 对话框状态
|
||||
const uploadDialogVisible = ref(false)
|
||||
const createDirDialogVisible = ref(false)
|
||||
const renameDialogVisible = ref(false)
|
||||
const uploading = ref(false)
|
||||
const uploadDialogVisible = ref(false);
|
||||
const createDirDialogVisible = ref(false);
|
||||
const renameDialogVisible = ref(false);
|
||||
const uploading = ref(false);
|
||||
|
||||
// 上传相关
|
||||
const uploadRef = ref()
|
||||
const uploadFileList = ref<any[]>([])
|
||||
const uploadRef = ref();
|
||||
const uploadFileList = ref<any[]>([]);
|
||||
|
||||
// 表单数据
|
||||
const createDirForm = reactive({
|
||||
dir_name: ''
|
||||
})
|
||||
dir_name: "",
|
||||
});
|
||||
|
||||
const renameForm = reactive({
|
||||
new_name: '',
|
||||
old_path: ''
|
||||
})
|
||||
new_name: "",
|
||||
old_path: "",
|
||||
});
|
||||
|
||||
// 计算属性
|
||||
const currentQuery = computed(() => {
|
||||
@@ -344,80 +428,80 @@ const currentQuery = computed(() => {
|
||||
const query: any = {
|
||||
include_hidden: showHiddenFiles.value,
|
||||
page_no: pagination.page_no,
|
||||
page_size: pagination.page_size
|
||||
}
|
||||
|
||||
page_size: pagination.page_size,
|
||||
};
|
||||
|
||||
// 如果当前路径不是根路径,则添加路径参数
|
||||
if (currentPath.value && currentPath.value !== '/') {
|
||||
if (currentPath.value && currentPath.value !== "/") {
|
||||
// 对于文件夹导航,直接传递文件夹名称
|
||||
query.path = currentPath.value
|
||||
query.path = currentPath.value;
|
||||
}
|
||||
|
||||
|
||||
// 添加搜索关键词
|
||||
if (queryFormData.name) {
|
||||
query.name = queryFormData.name
|
||||
query.name = queryFormData.name;
|
||||
}
|
||||
|
||||
return query
|
||||
})
|
||||
|
||||
return query;
|
||||
});
|
||||
|
||||
// 加载文件列表
|
||||
async function loadFileList() {
|
||||
loading.value = true
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await ResourceAPI.getResourceList(currentQuery.value)
|
||||
|
||||
const response = await ResourceAPI.getResourceList(currentQuery.value);
|
||||
|
||||
// 正确处理后端返回的分页数据结构
|
||||
const pageResult = response.data?.data
|
||||
|
||||
const pageResult = response.data?.data;
|
||||
|
||||
if (pageResult && Array.isArray(pageResult.items)) {
|
||||
fileList.value = pageResult.items
|
||||
total.value = pageResult.total
|
||||
fileList.value = pageResult.items;
|
||||
total.value = pageResult.total;
|
||||
if (pageResult.page_no !== undefined) {
|
||||
pagination.page_no = pageResult.page_no
|
||||
pagination.page_no = pageResult.page_no;
|
||||
}
|
||||
if (pageResult.page_size !== undefined) {
|
||||
pagination.page_size = pageResult.page_size
|
||||
pagination.page_size = pageResult.page_size;
|
||||
}
|
||||
} else {
|
||||
fileList.value = []
|
||||
total.value = 0
|
||||
fileList.value = [];
|
||||
total.value = 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Load file list error:', error)
|
||||
fileList.value = []
|
||||
total.value = 0
|
||||
console.error("Load file list error:", error);
|
||||
fileList.value = [];
|
||||
total.value = 0;
|
||||
} finally {
|
||||
loading.value = false
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 面包屑点击处理
|
||||
function handleBreadcrumbClick(item: any) {
|
||||
// 更新当前路径为点击的面包屑项路径
|
||||
currentPath.value = item.path
|
||||
updateBreadcrumb()
|
||||
loadFileList()
|
||||
currentPath.value = item.path;
|
||||
updateBreadcrumb();
|
||||
loadFileList();
|
||||
}
|
||||
|
||||
// 更新面包屑路径
|
||||
function updateBreadcrumb() {
|
||||
// 对于根路径,直接显示根目录
|
||||
if (currentPath.value === '/') {
|
||||
breadcrumbList.value = [{ name: '资源根目录', path: '/' }]
|
||||
return
|
||||
if (currentPath.value === "/") {
|
||||
breadcrumbList.value = [{ name: "资源根目录", path: "/" }];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 对于嵌套路径,需要分解并构建面包屑
|
||||
const parts = currentPath.value.split('/').filter(part => part !== '')
|
||||
|
||||
const parts = currentPath.value.split("/").filter((part) => part !== "");
|
||||
|
||||
breadcrumbList.value = [
|
||||
{ name: '资源根目录', path: '/' },
|
||||
{ name: "资源根目录", path: "/" },
|
||||
...parts.map((part, index) => ({
|
||||
name: part,
|
||||
path: parts.slice(0, index + 1).join('/')
|
||||
}))
|
||||
]
|
||||
path: parts.slice(0, index + 1).join("/"),
|
||||
})),
|
||||
];
|
||||
}
|
||||
|
||||
// 文件名点击处理
|
||||
@@ -425,16 +509,16 @@ function handleFileNameClick(row: ResourceItem) {
|
||||
if (row.is_dir) {
|
||||
// 如果当前在根路径,则直接使用文件夹名称
|
||||
// 如果当前已在某个文件夹中,则拼接路径
|
||||
if (currentPath.value === '/') {
|
||||
currentPath.value = row.name
|
||||
if (currentPath.value === "/") {
|
||||
currentPath.value = row.name;
|
||||
} else {
|
||||
currentPath.value = currentPath.value + '/' + row.name
|
||||
currentPath.value = currentPath.value + "/" + row.name;
|
||||
}
|
||||
updateBreadcrumb()
|
||||
loadFileList()
|
||||
updateBreadcrumb();
|
||||
loadFileList();
|
||||
} else {
|
||||
// 文件预览,使用后端返回的完整URL
|
||||
handleFilePreview(row)
|
||||
handleFilePreview(row);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,259 +527,255 @@ function handleItemClick(item: ResourceItem) {
|
||||
if (item.is_dir) {
|
||||
// 如果当前在根路径,则直接使用文件夹名称
|
||||
// 如果当前已在某个文件夹中,则拼接路径
|
||||
if (currentPath.value === '/') {
|
||||
currentPath.value = item.name
|
||||
if (currentPath.value === "/") {
|
||||
currentPath.value = item.name;
|
||||
} else {
|
||||
currentPath.value = currentPath.value + '/' + item.name
|
||||
currentPath.value = currentPath.value + "/" + item.name;
|
||||
}
|
||||
updateBreadcrumb()
|
||||
loadFileList()
|
||||
updateBreadcrumb();
|
||||
loadFileList();
|
||||
} else {
|
||||
// 文件预览,使用后端返回的完整URL
|
||||
handleFilePreview(item)
|
||||
handleFilePreview(item);
|
||||
}
|
||||
}
|
||||
|
||||
// 文件预览
|
||||
function handleFilePreview(file: ResourceItem) {
|
||||
// 直接使用file_url字段进行预览
|
||||
let previewUrl = file.file_url
|
||||
|
||||
let previewUrl = file.file_url;
|
||||
|
||||
// 如果是相对路径,构建完整URL
|
||||
if (previewUrl && !previewUrl.startsWith('http')) {
|
||||
previewUrl = `${window.location.origin}${previewUrl}`
|
||||
if (previewUrl && !previewUrl.startsWith("http")) {
|
||||
previewUrl = `${window.location.origin}${previewUrl}`;
|
||||
}
|
||||
|
||||
|
||||
// 所有文件类型统一直接打开预览
|
||||
window.open(previewUrl, '_blank')
|
||||
window.open(previewUrl, "_blank");
|
||||
}
|
||||
|
||||
// 选择项变化处理
|
||||
function handleSelectionChange(selection: ResourceItem[]) {
|
||||
selectedItems.value = selection
|
||||
selectedItems.value = selection;
|
||||
}
|
||||
|
||||
// 打开上传对话框
|
||||
function handleUpload() {
|
||||
uploadDialogVisible.value = true
|
||||
uploadFileList.value = []
|
||||
uploadDialogVisible.value = true;
|
||||
uploadFileList.value = [];
|
||||
}
|
||||
|
||||
// 上传文件变化处理
|
||||
function handleUploadChange(file: any, fileList: any[]) {
|
||||
uploadFileList.value = fileList
|
||||
uploadFileList.value = fileList;
|
||||
}
|
||||
|
||||
// 确认上传文件
|
||||
async function handleUploadConfirm() {
|
||||
if (uploadFileList.value.length === 0) {
|
||||
ElMessage.warning('请选择要上传的文件')
|
||||
return
|
||||
ElMessage.warning("请选择要上传的文件");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
uploading.value = true
|
||||
const formData = new FormData()
|
||||
uploading.value = true;
|
||||
const formData = new FormData();
|
||||
uploadFileList.value.forEach((file: any) => {
|
||||
formData.append('file', file.raw)
|
||||
})
|
||||
|
||||
// 在根目录时传递空字符串作为target_path,与后端relative_path格式保持一致
|
||||
const targetPath = currentPath.value === '/' ? '' : currentPath.value
|
||||
formData.append('target_path', targetPath)
|
||||
formData.append("file", file.raw);
|
||||
});
|
||||
|
||||
await ResourceAPI.uploadFile(formData)
|
||||
uploadDialogVisible.value = false
|
||||
loadFileList()
|
||||
// 在根目录时传递空字符串作为target_path,与后端relative_path格式保持一致
|
||||
const targetPath = currentPath.value === "/" ? "" : currentPath.value;
|
||||
formData.append("target_path", targetPath);
|
||||
|
||||
await ResourceAPI.uploadFile(formData);
|
||||
uploadDialogVisible.value = false;
|
||||
loadFileList();
|
||||
} catch (error) {
|
||||
console.error('Upload error:', error)
|
||||
console.error("Upload error:", error);
|
||||
} finally {
|
||||
uploading.value = false
|
||||
uploading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭上传对话框
|
||||
function handleUploadClose() {
|
||||
uploadDialogVisible.value = false
|
||||
uploadFileList.value = []
|
||||
uploadDialogVisible.value = false;
|
||||
uploadFileList.value = [];
|
||||
}
|
||||
|
||||
// 打开新建目录对话框
|
||||
function handleCreateDir() {
|
||||
createDirForm.dir_name = ''
|
||||
createDirDialogVisible.value = true
|
||||
createDirForm.dir_name = "";
|
||||
createDirDialogVisible.value = true;
|
||||
}
|
||||
|
||||
// 确认创建目录
|
||||
async function handleCreateDirConfirm() {
|
||||
if (!createDirForm.dir_name.trim()) {
|
||||
ElMessage.warning('请输入文件夹名称')
|
||||
return
|
||||
ElMessage.warning("请输入文件夹名称");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 在根目录时传递空字符串作为parent_path,与后端relative_path格式保持一致
|
||||
const parentPath = currentPath.value === '/' ? '' : currentPath.value
|
||||
const parentPath = currentPath.value === "/" ? "" : currentPath.value;
|
||||
await ResourceAPI.createDirectory({
|
||||
parent_path: parentPath,
|
||||
dir_name: createDirForm.dir_name.trim()
|
||||
})
|
||||
createDirDialogVisible.value = false
|
||||
loadFileList()
|
||||
dir_name: createDirForm.dir_name.trim(),
|
||||
});
|
||||
createDirDialogVisible.value = false;
|
||||
loadFileList();
|
||||
} catch (error) {
|
||||
console.error('Create directory error:', error)
|
||||
console.error("Create directory error:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 列表刷新
|
||||
async function handleRefresh() {
|
||||
await loadFileList()
|
||||
await loadFileList();
|
||||
}
|
||||
|
||||
// 查询(重置页码后获取数据)
|
||||
async function handleQuery() {
|
||||
queryFormData.page_no = 1
|
||||
await loadFileList()
|
||||
queryFormData.page_no = 1;
|
||||
await loadFileList();
|
||||
}
|
||||
|
||||
// 重置查询
|
||||
async function handleResetQuery() {
|
||||
queryFormRef.value.resetFields()
|
||||
queryFormData.page_no = 1
|
||||
isSearchMode.value = false // 退出搜索模式
|
||||
await loadFileList()
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormData.page_no = 1;
|
||||
isSearchMode.value = false; // 退出搜索模式
|
||||
await loadFileList();
|
||||
}
|
||||
|
||||
// 显示隐藏文件切换
|
||||
function handleShowHiddenChange() {
|
||||
loadFileList()
|
||||
loadFileList();
|
||||
}
|
||||
|
||||
// 文件下载
|
||||
async function handleDownload(item: ResourceItem) {
|
||||
try {
|
||||
// 使用file_url字段
|
||||
const response = await ResourceAPI.downloadFile(item.file_url)
|
||||
const blob = response.data
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = item.name
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
window.URL.revokeObjectURL(url)
|
||||
const response = await ResourceAPI.downloadFile(item.file_url);
|
||||
const blob = response.data;
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = item.name;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error('Download error:', error)
|
||||
console.error("Download error:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 打开重命名对话框
|
||||
function handleRename(item: ResourceItem) {
|
||||
// 使用file_url字段
|
||||
renameForm.old_path = item.file_url
|
||||
renameForm.new_name = item.name
|
||||
renameDialogVisible.value = true
|
||||
renameForm.old_path = item.file_url;
|
||||
renameForm.new_name = item.name;
|
||||
renameDialogVisible.value = true;
|
||||
}
|
||||
|
||||
// 确认重命名
|
||||
async function handleRenameConfirm() {
|
||||
if (!renameForm.new_name.trim()) {
|
||||
ElMessage.warning('请输入新名称')
|
||||
return
|
||||
ElMessage.warning("请输入新名称");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await ResourceAPI.renameResource({
|
||||
old_path: renameForm.old_path,
|
||||
new_name: renameForm.new_name.trim()
|
||||
})
|
||||
renameDialogVisible.value = false
|
||||
loadFileList()
|
||||
new_name: renameForm.new_name.trim(),
|
||||
});
|
||||
renameDialogVisible.value = false;
|
||||
loadFileList();
|
||||
} catch (error) {
|
||||
console.error('Rename error:', error)
|
||||
console.error("Rename error:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 文件删除
|
||||
async function handleDelete(item: ResourceItem) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要删除 ${item.name} 吗?`,
|
||||
'确认删除',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
await ElMessageBox.confirm(`确定要删除 ${item.name} 吗?`, "确认删除", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
// 使用file_url字段
|
||||
await ResourceAPI.deleteResource([item.file_url])
|
||||
loadFileList()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('Delete error:', error)
|
||||
}
|
||||
await ResourceAPI.deleteResource([item.file_url]);
|
||||
loadFileList();
|
||||
} catch (error) {
|
||||
if (error !== "cancel") {
|
||||
console.error("Delete error:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页处理
|
||||
function handlePagination(params: { page: number; limit: number }) {
|
||||
pagination.page_no = params.page
|
||||
pagination.page_size = params.limit
|
||||
loadFileList()
|
||||
pagination.page_no = params.page;
|
||||
pagination.page_size = params.limit;
|
||||
loadFileList();
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
async function handleBatchDelete() {
|
||||
if (selectedItems.value.length === 0) {
|
||||
ElMessage.warning('请选择要删除的文件')
|
||||
return
|
||||
ElMessage.warning("请选择要删除的文件");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要删除选中的 ${selectedItems.value.length} 个文件吗?`,
|
||||
'确认删除',
|
||||
"确认删除",
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// 使用file_url字段
|
||||
const paths = selectedItems.value.map(item => item.file_url)
|
||||
|
||||
await ResourceAPI.deleteResource(paths)
|
||||
loadFileList()
|
||||
const paths = selectedItems.value.map((item) => item.file_url);
|
||||
|
||||
await ResourceAPI.deleteResource(paths);
|
||||
loadFileList();
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('Batch delete error:', error)
|
||||
if (error !== "cancel") {
|
||||
console.error("Batch delete error:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
function formatFileSize(size?: number | null) {
|
||||
if (!size || size === null) return '-'
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
||||
let unitIndex = 0
|
||||
let fileSize = size
|
||||
if (!size || size === null) return "-";
|
||||
const units = ["B", "KB", "MB", "GB", "TB"];
|
||||
let unitIndex = 0;
|
||||
let fileSize = size;
|
||||
|
||||
while (fileSize >= 1024 && unitIndex < units.length - 1) {
|
||||
fileSize /= 1024
|
||||
unitIndex++
|
||||
fileSize /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
|
||||
return `${fileSize.toFixed(1)} ${units[unitIndex]}`
|
||||
return `${fileSize.toFixed(1)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
loadFileList()
|
||||
})
|
||||
loadFileList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -713,7 +793,7 @@ onMounted(() => {
|
||||
.file-name-clickable {
|
||||
cursor: pointer;
|
||||
color: var(--el-color-primary);
|
||||
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary-light-3);
|
||||
text-decoration: underline;
|
||||
@@ -727,7 +807,7 @@ onMounted(() => {
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
height: calc(100vh - 200px);
|
||||
gap: 20px;
|
||||
|
||||
|
||||
.grid-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -750,7 +830,7 @@ onMounted(() => {
|
||||
&.is-link {
|
||||
cursor: pointer;
|
||||
color: var(--el-color-primary);
|
||||
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary-light-3);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="app-container" >
|
||||
<div class="app-container">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12" class="mb-4">
|
||||
<el-card :loading="loading" shadow="hover">
|
||||
<el-card :loading="loading" shadow="hover">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<el-icon><Cpu/></el-icon>
|
||||
<el-icon><Cpu /></el-icon>
|
||||
<span class="flex items-center gap-2">CPU使用情况</span>
|
||||
<el-tooltip content="展示CPU核心数及使用率">
|
||||
<el-icon><QuestionFilled /></el-icon>
|
||||
@@ -19,18 +19,23 @@
|
||||
<span>核心数</span>
|
||||
<el-tooltip :content="(server.cpu?.cpu_num || 0).toFixed(1)">
|
||||
<div class="text-center mb-4">
|
||||
<el-progress
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="100"
|
||||
:format="() => `${server.cpu?.cpu_num || 0}`"
|
||||
:format="() => `${server.cpu?.cpu_num || 0}`"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="总核心数" >{{server.cpu?.cpu_num || 0}}</el-descriptions-item>
|
||||
<el-descriptions-item label="已用核心" >{{Math.floor((server.cpu?.used || 0) * server.cpu?.cpu_num / 100)}}</el-descriptions-item>
|
||||
<el-descriptions-item label="空闲核心" >{{Math.floor((server.cpu?.free || 0) * server.cpu?.cpu_num / 100)}}</el-descriptions-item>
|
||||
<el-descriptions-item label="总核心数">
|
||||
{{ server.cpu?.cpu_num || 0 }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="已用核心">
|
||||
{{ Math.floor(((server.cpu?.used || 0) * server.cpu?.cpu_num) / 100) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="空闲核心">
|
||||
{{ Math.floor(((server.cpu?.free || 0) * server.cpu?.cpu_num) / 100) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -40,17 +45,29 @@
|
||||
<span>使用率</span>
|
||||
<el-tooltip :content="(server.cpu?.used || 0).toFixed(1) + '%'">
|
||||
<div class="text-center mb-4">
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="server.cpu?.used || 0"
|
||||
:status="server.cpu?.used > 80 ? 'exception' : server.cpu?.used > 60 ? 'warning' : 'success'"
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="server.cpu?.used || 0"
|
||||
:status="
|
||||
server.cpu?.used > 80
|
||||
? 'exception'
|
||||
: server.cpu?.used > 60
|
||||
? 'warning'
|
||||
: 'success'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="用户使用率" >{{(server.cpu?.used || 0).toFixed(1) + '%'}}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统使用率" >{{(server.cpu?.sys || 0).toFixed(1) + '%'}}</el-descriptions-item>
|
||||
<el-descriptions-item label="当前空闲率" >{{(server.cpu?.free || 0).toFixed(1) + '%'}}</el-descriptions-item>
|
||||
<el-descriptions-item label="用户使用率">
|
||||
{{ (server.cpu?.used || 0).toFixed(1) + "%" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="系统使用率">
|
||||
{{ (server.cpu?.sys || 0).toFixed(1) + "%" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="当前空闲率">
|
||||
{{ (server.cpu?.free || 0).toFixed(1) + "%" }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -59,7 +76,7 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb-4">
|
||||
<el-card :loading="loading" shadow="hover">
|
||||
<el-card :loading="loading" shadow="hover">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<el-icon><Memo /></el-icon>
|
||||
@@ -76,17 +93,29 @@
|
||||
<span>系统内存</span>
|
||||
<el-tooltip :content="(server.mem?.usage || 0).toFixed(1) + '%'">
|
||||
<div class="text-center mb-4">
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="server.mem?.usage || 0"
|
||||
:status="server.mem?.usage > 80 ? 'exception' : server.mem?.usage > 60 ? 'warning' : 'success'"
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="server.mem?.usage || 0"
|
||||
:status="
|
||||
server.mem?.usage > 80
|
||||
? 'exception'
|
||||
: server.mem?.usage > 60
|
||||
? 'warning'
|
||||
: 'success'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="总内存" >{{server.mem?.total}}</el-descriptions-item>
|
||||
<el-descriptions-item label="已用内存" >{{server.mem?.used}}</el-descriptions-item>
|
||||
<el-descriptions-item label="空闲内存" >{{server.mem?.free}}</el-descriptions-item>
|
||||
<el-descriptions-item label="总内存">
|
||||
{{ server.mem?.total }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="已用内存">
|
||||
{{ server.mem?.used }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="空闲内存">
|
||||
{{ server.mem?.free }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -96,17 +125,29 @@
|
||||
<span>Python内存</span>
|
||||
<el-tooltip :content="(server.py?.memory_usage || 0).toFixed(1) + '%'">
|
||||
<div class="text-center mb-4">
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="server.py?.memory_usage || 0"
|
||||
:status="server.py?.memory_usage > 80 ? 'exception' : server.py?.memory_usage > 60 ? 'warning' : 'success'"
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="server.py?.memory_usage || 0"
|
||||
:status="
|
||||
server.py?.memory_usage > 80
|
||||
? 'exception'
|
||||
: server.py?.memory_usage > 60
|
||||
? 'warning'
|
||||
: 'success'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="总内存" >{{server.py?.memory_total}}</el-descriptions-item>
|
||||
<el-descriptions-item label="已用内存" >{{server.py?.memory_used}}</el-descriptions-item>
|
||||
<el-descriptions-item label="空闲内存" >{{server.py?.memory_free}}</el-descriptions-item>
|
||||
<el-descriptions-item label="总内存">
|
||||
{{ server.py?.memory_total }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="已用内存">
|
||||
{{ server.py?.memory_used }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="空闲内存">
|
||||
{{ server.py?.memory_free }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -115,7 +156,7 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb-4">
|
||||
<el-card :loading="loading" >
|
||||
<el-card :loading="loading">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<el-icon><Monitor /></el-icon>
|
||||
@@ -126,16 +167,24 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="服务器名称">{{ server.sys?.computer_name || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="操作系统">{{ server.sys?.os_name || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="服务器IP">{{ server.sys?.computer_ip || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统架构">{{ server.sys?.os_arch || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="服务器名称">
|
||||
{{ server.sys?.computer_name || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="操作系统">
|
||||
{{ server.sys?.os_name || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="服务器IP">
|
||||
{{ server.sys?.computer_ip || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="系统架构">
|
||||
{{ server.sys?.os_arch || "-" }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb-4">
|
||||
<el-card :loading="loading" class="shadow-sm">
|
||||
<el-card :loading="loading" class="shadow-sm">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<el-icon><Dish /></el-icon>
|
||||
@@ -146,12 +195,24 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-descriptions :column="3" border>
|
||||
<el-descriptions-item label="Python名称">{{ server.py?.name || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="Python版本">{{ server.py?.version || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="启动时间">{{ server.py?.start_time || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="运行时长">{{ server.py?.run_time || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="安装路径">{{ server.py?.home || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="项目路径">{{ server.sys?.user_dir || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="Python名称">
|
||||
{{ server.py?.name || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="Python版本">
|
||||
{{ server.py?.version || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="启动时间">
|
||||
{{ server.py?.start_time || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="运行时长">
|
||||
{{ server.py?.run_time || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="安装路径">
|
||||
{{ server.py?.home || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="项目路径">
|
||||
{{ server.sys?.user_dir || "-" }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -169,35 +230,19 @@
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-table :data="server.disks" border >
|
||||
<el-table :data="server.disks" border>
|
||||
<template #empty>
|
||||
<el-empty :image-size="80" description="暂无数据" />
|
||||
</template>
|
||||
<el-table-column
|
||||
label="盘符路径"
|
||||
prop="dir_name"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column
|
||||
label="文件系统"
|
||||
prop="sys_type_name"
|
||||
align="center"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
label="盘符名称"
|
||||
prop="type_name"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="usage"
|
||||
label="使用率"
|
||||
align="center"
|
||||
>
|
||||
<el-table-column label="盘符路径" prop="dir_name" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="文件系统" prop="sys_type_name" align="center" width="100" />
|
||||
<el-table-column label="盘符名称" prop="type_name" />
|
||||
<el-table-column prop="usage" label="使用率" align="center">
|
||||
<template #default="{ row }">
|
||||
<!-- 使用 element-plus 的 Progress 组件 -->
|
||||
<div>
|
||||
<el-progress
|
||||
:percentage="Number(row.usage)"
|
||||
<el-progress
|
||||
:percentage="Number(row.usage)"
|
||||
:status="row.usage > 80 ? 'exception' : row.usage > 60 ? 'warning' : 'success'"
|
||||
:text-inside="true"
|
||||
:stroke-width="16"
|
||||
@@ -205,24 +250,9 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="总大小"
|
||||
prop="total"
|
||||
align="center"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
label="可用大小"
|
||||
prop="free"
|
||||
align="center"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
label="已用大小"
|
||||
prop="used"
|
||||
align="center"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column label="总大小" prop="total" align="center" width="100" />
|
||||
<el-table-column label="可用大小" prop="free" align="center" width="100" />
|
||||
<el-table-column label="已用大小" prop="used" align="center" width="100" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -231,8 +261,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ServerAPI, {type ServerInfo } from '@/api/module_monitor/server'
|
||||
|
||||
import ServerAPI, { type ServerInfo } from "@/api/module_monitor/server";
|
||||
|
||||
const loading = ref(false);
|
||||
const server = ref<ServerInfo>({
|
||||
@@ -240,33 +269,33 @@ const server = ref<ServerInfo>({
|
||||
cpu_num: 0,
|
||||
used: 0,
|
||||
sys: 0,
|
||||
free: 0
|
||||
free: 0,
|
||||
},
|
||||
mem: {
|
||||
total: '',
|
||||
used: '',
|
||||
free: '',
|
||||
usage: 0
|
||||
total: "",
|
||||
used: "",
|
||||
free: "",
|
||||
usage: 0,
|
||||
},
|
||||
sys: {
|
||||
computer_name: '',
|
||||
os_name: '',
|
||||
computer_ip: '',
|
||||
os_arch: '',
|
||||
user_dir: ''
|
||||
computer_name: "",
|
||||
os_name: "",
|
||||
computer_ip: "",
|
||||
os_arch: "",
|
||||
user_dir: "",
|
||||
},
|
||||
py: {
|
||||
name: '',
|
||||
version: '',
|
||||
start_time: '',
|
||||
run_time: '',
|
||||
home: '',
|
||||
memory_total: '',
|
||||
memory_used: '',
|
||||
memory_free: '',
|
||||
memory_usage: 0
|
||||
name: "",
|
||||
version: "",
|
||||
start_time: "",
|
||||
run_time: "",
|
||||
home: "",
|
||||
memory_total: "",
|
||||
memory_used: "",
|
||||
memory_free: "",
|
||||
memory_usage: 0,
|
||||
},
|
||||
disks: []
|
||||
disks: [],
|
||||
});
|
||||
|
||||
async function getList() {
|
||||
@@ -275,7 +304,7 @@ async function getList() {
|
||||
const response = await ServerAPI.getServer();
|
||||
server.value = response.data.data;
|
||||
} catch (error) {
|
||||
console.error('获取服务器信息失败:', error);
|
||||
console.error("获取服务器信息失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user