feat(admin): 主机组映射展示全部主控并展开加载主机组
Build and Deploy Vue3 / build (push) Successful in 1m23s
Build and Deploy Vue3 / deploy (push) Successful in 30s

主机组映射页改为卡片列表展示所有主控服务,展开后按需请求主机组;套餐管理增加必填参数未配置提醒。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
shiran
2026-05-25 18:31:56 +08:00
parent 9974a82ac8
commit 765f925482
2 changed files with 272 additions and 110 deletions
@@ -162,6 +162,17 @@
<el-form-item label="说明" prop="note">
<el-input v-model="planForm.note" type="textarea" :rows="2" placeholder="请输入套餐说明" />
</el-form-item>
<div v-if="missingMustSpecs.length > 0" class="must-params-alert">
<div class="must-params-alert-header">
<el-icon><WarningFilled /></el-icon>
<span>以下必填参数尚未配置请将其加入参数配置额外参数</span>
</div>
<div class="must-params-alert-tags">
<el-tag v-for="spec in missingMustSpecs" :key="spec.id" type="danger" size="small" effect="plain">
<span class="must-star">*</span>{{ spec.name }}
</el-tag>
</div>
</div>
<el-form-item label="参数配置" prop="args">
<div class="args-config-container">
<div class="args-select-row">
@@ -385,6 +396,10 @@ const selectedExtraArgIds = ref([])
const selectedArgSpecs = computed(() => planSpecList.value.filter(spec => selectedArgIds.value.includes(spec.id)))
const extraSpecList = computed(() => planSpecList.value.filter(spec => !selectedArgIds.value.includes(spec.id)))
const missingMustSpecs = computed(() => {
const allSelectedIds = [...selectedArgIds.value, ...selectedExtraArgIds.value]
return planSpecList.value.filter(s => s.must && !allSelectedIds.includes(s.id))
})
const getSpecDisplayMin = (spec) => {
if (!hasUnit(spec)) return spec.min ?? 0
@@ -1184,6 +1199,26 @@ watch(() => props.visible, (val) => {
.plan-card-actions .el-button + .el-button {
margin-left: 0;
}
.must-params-alert {
margin: 0 0 16px;
padding: 10px 14px;
background: linear-gradient(135deg, #fff5f5 0%, #fff1f0 100%);
border: 1px solid #fcdcdc;
border-radius: 8px;
border-left: 3px solid #f56c6c;
}
.must-params-alert-header {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: #f56c6c;
font-weight: 500;
margin-bottom: 8px;
}
.must-params-alert-header .el-icon { font-size: 16px; flex-shrink: 0; }
.must-params-alert-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.must-params-alert-tags .must-star { color: #f56c6c; font-weight: 700; margin-right: 2px; }
.plan-form-content { max-height: 60vh; overflow-y: auto; padding-right: 8px; margin-right: -8px; }
.plan-form-content::-webkit-scrollbar { width: 6px; }
.plan-form-content::-webkit-scrollbar-track { background: transparent; }