refactor: extract image form to standalone page and implement tags view store
- Created ImageForm.vue as standalone page for add/edit image functionality - Removed dialog-based image form from VmImages.vue - Implemented tagsViewStore for global tab state management - Added automatic tab closing on form cancel/back - Fixed data persistence issue when switching between image edits - Removed quick actions section from ImageForm - Updated router configuration for new image form route
This commit is contained in:
+129
-196
@@ -446,8 +446,8 @@
|
||||
<!-- <serverChart v-if="TypeData" :Type="TypeData" class="chart-section" /> -->
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="content-wrapper">
|
||||
<el-tabs type="border-card" class="main-tabs">
|
||||
<el-card class="main-container" shadow="never">
|
||||
<el-tabs class="main-tabs">
|
||||
<!-- 实例规格列表 -->
|
||||
<el-tab-pane label="实例规格列表">
|
||||
<div class="tab-header">
|
||||
@@ -464,11 +464,11 @@
|
||||
<el-table
|
||||
v-loading="specLoading"
|
||||
:data="spec_list"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%"
|
||||
table-layout="auto"
|
||||
class="data-table"
|
||||
:header-cell-style="{ background: '#fafafa', color: '#333', fontWeight: 600 }"
|
||||
>
|
||||
<el-table-column prop="plan_id" label="规格ID" width="80" />
|
||||
<el-table-column prop="name" label="规格名称" min-width="120" show-overflow-tooltip />
|
||||
@@ -510,24 +510,24 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="160" fixed="right">
|
||||
<el-table-column label="操作" width="160" fixed="right" align="center">
|
||||
<template #default="scope">
|
||||
<div class="table-actions">
|
||||
<el-tooltip content="编辑" placement="top" :hide-after="1500">
|
||||
<el-button
|
||||
type="primary"
|
||||
circle
|
||||
link
|
||||
:icon="Edit"
|
||||
@click="show_spec(scope.row); centerDialogVisible = true; addOrChange = false;"
|
||||
/>
|
||||
>编辑</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top" :hide-after="1500">
|
||||
<el-button
|
||||
type="danger"
|
||||
circle
|
||||
link
|
||||
:icon="Delete"
|
||||
@click="deleteSpec(scope.row.plan_id)"
|
||||
/>
|
||||
>删除</el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
@@ -562,9 +562,9 @@
|
||||
<el-table
|
||||
:data="user_servers"
|
||||
stripe
|
||||
border
|
||||
style="width: 100%"
|
||||
class="data-table"
|
||||
:header-cell-style="{ background: '#fafafa', color: '#333', fontWeight: 600 }"
|
||||
>
|
||||
<el-table-column label="ID" prop="container_id" width="80" />
|
||||
<el-table-column label="价格" prop="pay" width="100">
|
||||
@@ -598,7 +598,7 @@
|
||||
: scope.row.container_state == 4
|
||||
? 'danger'
|
||||
: 'info'"
|
||||
effect="light"
|
||||
effect="plain"
|
||||
>
|
||||
{{
|
||||
scope.row.container_state == 0
|
||||
@@ -616,11 +616,11 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" fixed="right">
|
||||
<el-table-column label="操作" width="100" fixed="right" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
:icon="Setting"
|
||||
@click="$router.push('/servers/container?container_id=' + scope.row.container_id)"
|
||||
>
|
||||
@@ -667,9 +667,9 @@
|
||||
<el-table
|
||||
:data="floatList"
|
||||
style="width: 100%"
|
||||
border
|
||||
stripe
|
||||
class="data-table"
|
||||
:header-cell-style="{ background: '#fafafa', color: '#333', fontWeight: 600 }"
|
||||
>
|
||||
<el-table-column label="ID" prop="id" width="80" />
|
||||
<el-table-column label="创建时间" min-width="160">
|
||||
@@ -680,7 +680,7 @@
|
||||
<el-table-column label="浮动IP" prop="floating_ip" min-width="150" />
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.is_used ? 'success' : 'info'" effect="light">
|
||||
<el-tag :type="scope.row.is_used ? 'success' : 'info'" effect="plain">
|
||||
{{ scope.row.is_used ? "已绑定" : "未绑定" }}
|
||||
</el-tag>
|
||||
</template>
|
||||
@@ -690,10 +690,10 @@
|
||||
<el-tooltip content="删除IP" placement="top" :hide-after="1500">
|
||||
<el-button
|
||||
type="danger"
|
||||
circle
|
||||
link
|
||||
:icon="Delete"
|
||||
@click="delFloating(scope.row.id)"
|
||||
/>
|
||||
>删除</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -702,7 +702,7 @@
|
||||
<el-empty v-if="floatList.length === 0" description="暂无浮动IP数据" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 添加/编辑实例规格对话框 -->
|
||||
<el-dialog
|
||||
@@ -2617,9 +2617,7 @@ import { ElMessageBox } from 'element-plus';
|
||||
|
||||
<style scoped>
|
||||
.server-container {
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
min-height: calc(100vh - 120px);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 页面标题区域 */
|
||||
@@ -2628,6 +2626,9 @@ import { ElMessageBox } from 'element-plus';
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding: 16px 20px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e1e8ed;
|
||||
}
|
||||
|
||||
.page-header .left {
|
||||
@@ -2638,7 +2639,7 @@ import { ElMessageBox } from 'element-plus';
|
||||
|
||||
.page-header .title {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
@@ -2647,7 +2648,8 @@ import { ElMessageBox } from 'element-plus';
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px 12px;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
@@ -2669,13 +2671,13 @@ import { ElMessageBox } from 'element-plus';
|
||||
/* 返回按钮样式 */
|
||||
.back-btn {
|
||||
font-size: 16px;
|
||||
color: #409EFF;
|
||||
padding: 8px 0;
|
||||
margin-right: 16px;
|
||||
color: #606266;
|
||||
padding: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.back-btn:hover {
|
||||
color: #66b1ff;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
/* 服务器信息卡片 */
|
||||
@@ -2684,6 +2686,7 @@ import { ElMessageBox } from 'element-plus';
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
/* 服务器详细信息卡片 */
|
||||
@@ -2692,16 +2695,17 @@ import { ElMessageBox } from 'element-plus';
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid #ebeef5;
|
||||
border: 1px solid #e1e8ed;
|
||||
}
|
||||
|
||||
.info-card:hover {
|
||||
@@ -2710,10 +2714,10 @@ import { ElMessageBox } from 'element-plus';
|
||||
}
|
||||
|
||||
.card-title {
|
||||
background-color: #f5f7fa;
|
||||
background-color: #fafbfc;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
font-size: 16px;
|
||||
border-bottom: 1px solid #e1e8ed;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
display: flex;
|
||||
@@ -2722,7 +2726,7 @@ import { ElMessageBox } from 'element-plus';
|
||||
}
|
||||
|
||||
.card-title .el-icon {
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
@@ -2745,32 +2749,31 @@ import { ElMessageBox } from 'element-plus';
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 15px;
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.info-value.highlight {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
/* 硬件信息样式 - 符合整体设计风格 */
|
||||
/* 硬件信息样式 */
|
||||
.device-count {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.hardware-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
@@ -2780,21 +2783,21 @@ import { ElMessageBox } from 'element-plus';
|
||||
.hardware-devices {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.device-item {
|
||||
padding: 16px;
|
||||
padding: 12px;
|
||||
background-color: #fafbfc;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e1e8ed;
|
||||
}
|
||||
|
||||
.device-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.device-title {
|
||||
@@ -2807,57 +2810,27 @@ import { ElMessageBox } from 'element-plus';
|
||||
|
||||
.device-title .el-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.device-details {
|
||||
margin-top: 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.usage-progress {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* 使用率状态颜色类 */
|
||||
.info-value.usage-normal {
|
||||
color: #67C23A;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info-value.usage-medium {
|
||||
color: #409EFF;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info-value.usage-warning {
|
||||
color: #E6A23C;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info-value.usage-critical {
|
||||
color: #F56C6C;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 实际硬件划分样式 */
|
||||
.highlight-item {
|
||||
padding: 8px;
|
||||
background-color: #f0f9ff;
|
||||
border-radius: 4px;
|
||||
border-left: 3px solid #409EFF;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 流量信息样式 */
|
||||
.traffic-section {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.traffic-section:last-child {
|
||||
@@ -2865,62 +2838,38 @@ import { ElMessageBox } from 'element-plus';
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 8px;
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.traffic-speed-grid,
|
||||
.traffic-total-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.traffic-total-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
}
|
||||
|
||||
.traffic-total-grid,
|
||||
.traffic-distribution {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.raw-data {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
background-color: #fafbfc;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e1e8ed;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.raw-data .info-value {
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.traffic-note {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* 旧样式保持兼容 */
|
||||
.usage-high {
|
||||
color: #F56C6C;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.usage-medium {
|
||||
color: #E6A23C;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 错误状态样式 */
|
||||
.error-status {
|
||||
color: #F56C6C;
|
||||
@@ -2929,15 +2878,10 @@ import { ElMessageBox } from 'element-plus';
|
||||
}
|
||||
|
||||
/* 主要内容区域 */
|
||||
.chart-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
||||
margin-bottom: 24px;
|
||||
.main-container {
|
||||
margin: 0 20px 20px 20px;
|
||||
border: 1px solid #e1e8ed;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
@@ -2945,11 +2889,13 @@ import { ElMessageBox } from 'element-plus';
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
}
|
||||
|
||||
.tab-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
@@ -2969,40 +2915,67 @@ import { ElMessageBox } from 'element-plus';
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 表格样式 */
|
||||
.data-table {
|
||||
margin-bottom: 16px;
|
||||
/* 表格样式优化 */
|
||||
:deep(.el-table) {
|
||||
border: none;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.table-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
:deep(.el-table__header) {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.resource-value {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.unit {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.price-tag {
|
||||
:deep(.el-table th) {
|
||||
background: #f8f9fa !important;
|
||||
border-bottom: 2px solid #e1e8ed;
|
||||
color: #2c3e50;
|
||||
font-weight: 600;
|
||||
color: #F56C6C;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.time-info {
|
||||
font-size: 13px;
|
||||
:deep(.el-table td) {
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
color: #34495e;
|
||||
}
|
||||
|
||||
:deep(.el-table tr:hover > td) {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Tabs 样式优化 */
|
||||
:deep(.el-tabs__header) {
|
||||
margin: 0;
|
||||
border-bottom: 1px solid #e1e8ed;
|
||||
background: #fff;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item.is-active) {
|
||||
color: #409EFF;
|
||||
background: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__content) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 分页样式 */
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
padding: 16px 20px;
|
||||
border-top: 1px solid #e1e8ed;
|
||||
background: #fafbfc;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
@@ -3013,15 +2986,13 @@ import { ElMessageBox } from 'element-plus';
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px dashed #ebeef5;
|
||||
border-bottom: 1px dashed #e1e8ed;
|
||||
}
|
||||
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -3124,27 +3095,24 @@ import { ElMessageBox } from 'element-plus';
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.page-header .left {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.server-info {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.server-detail-info {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.info-card.location-info {
|
||||
grid-column: auto;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
margin: 0 16px 16px 16px;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
@@ -3159,40 +3127,5 @@ import { ElMessageBox } from 'element-plus';
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* 硬件信息响应式 */
|
||||
.hardware-summary {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.device-item {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.device-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 流量信息响应式 */
|
||||
.traffic-speed-grid,
|
||||
.traffic-total-grid,
|
||||
.traffic-distribution {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.raw-data {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user