|
|
|
@ -62,6 +62,8 @@ function normalizeCards(modelList: any[] = []): ModelItem[] { |
|
|
|
const card: ModelItem = { |
|
|
|
id: modelCard.id, |
|
|
|
title: modelCard.name, |
|
|
|
unitName: modelCard.unitName, |
|
|
|
systemName: modelCard.systemName, |
|
|
|
version: modelCard.version, |
|
|
|
icon: statusIcons[statusIndex], |
|
|
|
value: 1, |
|
|
|
@ -81,6 +83,12 @@ function normalizeCards(modelList: any[] = []): ModelItem[] { |
|
|
|
return cardList |
|
|
|
} |
|
|
|
|
|
|
|
function getSubtitle(item: ModelItem) { |
|
|
|
const unitText = item.unitName ? `${item.unitName}` : (props.unitId != null ? `${props.unitId}号机组` : '未选择机组') |
|
|
|
const systemText = item.systemName || (props.systemId != null ? `系统${props.systemId}` : '未选择系统') |
|
|
|
return `${unitText} · ${systemText}` |
|
|
|
} |
|
|
|
|
|
|
|
async function fetchModelList(queryParams: ModelCardQueryParams, append: boolean) { |
|
|
|
if (listLoading.value) |
|
|
|
return |
|
|
|
@ -196,37 +204,62 @@ onBeforeUnmount(() => { |
|
|
|
:loading="loading || (listLoading && !modelCardList.length)" |
|
|
|
:hoverable="true" |
|
|
|
class="model-card" |
|
|
|
:style="{ borderLeft: `6px solid ${item.statusColor}` }" |
|
|
|
@click="changeModel(item.id, item.version)" |
|
|
|
> |
|
|
|
<div class="card-top"> |
|
|
|
<div class="card-title" :title="item.title"> |
|
|
|
{{ item.title }} |
|
|
|
<div class="model-card__inner"> |
|
|
|
<header class="model-card__header"> |
|
|
|
<div> |
|
|
|
<div class="model-card__title" :title="item.title"> |
|
|
|
{{ item.title }} |
|
|
|
</div> |
|
|
|
<div class="model-card__subtitle"> |
|
|
|
{{ getSubtitle(item) }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="model-card__header-right"> |
|
|
|
<span class="lock-icon"> |
|
|
|
<Icon :icon="item.status === '已下装' ? 'ant-design:lock-outlined' : 'ant-design:unlock-outlined'" :size="18" /> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
</header> |
|
|
|
|
|
|
|
<div class="model-card__tag-row"> |
|
|
|
<span class="tag-pill tag-pill--blue">{{ item.algorithm || '未知算法' }}</span> |
|
|
|
<span class="tag-pill tag-pill--green">{{ item.version || 'v-test' }}</span> |
|
|
|
<span class="tag-pill">{{ item.createTime || '--' }}</span> |
|
|
|
</div> |
|
|
|
<div class="card-tags"> |
|
|
|
<span class="status-icon" :style="{ color: item.statusColor }"> |
|
|
|
<Icon :icon="item.icon" :size="20" /> |
|
|
|
</span> |
|
|
|
|
|
|
|
<div class="model-card__meta-row"> |
|
|
|
<div class="meta-line"> |
|
|
|
<div class="meta-item"> |
|
|
|
<span class="meta-label">创建人</span> |
|
|
|
<span>{{ item.creator || '未知' }}</span> |
|
|
|
</div> |
|
|
|
<div class="meta-item"> |
|
|
|
<span class="meta-label">创建时间</span> |
|
|
|
<span>{{ item.createTime || '--' }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="model-card__divider" /> |
|
|
|
|
|
|
|
<div class="model-card__bottom"> |
|
|
|
<div class="deploy-info"> |
|
|
|
<div class="deploy-info__line"> |
|
|
|
<span :class="item.status === '已下装' ? 'dot dot--success' : 'dot dot--muted'" /> |
|
|
|
<span>{{ item.status === '已下装' ? '最近已校验' : '未校验' }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="model-card__actions"> |
|
|
|
<button class="btn btn--ghost" @click.stop="changeModel(item.id, item.version)"> |
|
|
|
查看详情 |
|
|
|
</button> |
|
|
|
<button class="btn btn--primary" @click.stop="changeModel(item.id, item.version)"> |
|
|
|
进入诊断 |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="card-meta"> |
|
|
|
<span class="meta-item"> |
|
|
|
<Icon icon="ic:baseline-person" :size="16" class="meta-icon" /> |
|
|
|
{{ item.creator || '未知' }} |
|
|
|
</span> |
|
|
|
<span class="meta-item"> |
|
|
|
<Icon icon="ant-design:calendar-outlined" :size="16" class="meta-icon" /> |
|
|
|
{{ item.createTime || '--' }} |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
<div class="card-divider" /> |
|
|
|
<div class="card-footer"> |
|
|
|
<span class="algo-pill"> |
|
|
|
{{ item.algorithm || '未知' }} |
|
|
|
</span> |
|
|
|
<span class="tag version" :style="{ backgroundColor: item.statusColor, color: '#fff' }"> |
|
|
|
{{ item.version || 'v-test' }} |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
</Card> |
|
|
|
<template #overlay> |
|
|
|
@ -269,140 +302,227 @@ onBeforeUnmount(() => { |
|
|
|
} |
|
|
|
|
|
|
|
.model-card { |
|
|
|
padding: 14px 14px 12px; |
|
|
|
background: linear-gradient(180deg, #fdfdfd 0%, #f7f8fa 100%); |
|
|
|
border: 1px solid #d0d7de; |
|
|
|
border-radius: 8px; |
|
|
|
box-shadow: 0 6px 16px rgb(15 23 42 / 8%); |
|
|
|
transition: transform 0.18s ease, box-shadow 0.18s ease; |
|
|
|
position: relative; |
|
|
|
width: 100%; |
|
|
|
border-radius: 20px; |
|
|
|
background: #ffffff; |
|
|
|
border: 1px solid #e5e7eb; |
|
|
|
box-shadow: 0 6px 20px rgb(17 24 39 / 8%); |
|
|
|
overflow: hidden; |
|
|
|
display: block; |
|
|
|
transition: transform 0.18s ease-out, box-shadow 0.18s ease-out; |
|
|
|
} |
|
|
|
|
|
|
|
.model-card:hover { |
|
|
|
box-shadow: 0 12px 32px rgb(15 23 42 / 12%); |
|
|
|
transform: translateY(-2px); |
|
|
|
box-shadow: 0 10px 30px rgb(17 24 39 / 16%); |
|
|
|
} |
|
|
|
|
|
|
|
.card-top { |
|
|
|
.icon-card { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
min-height: 180px; |
|
|
|
width: 100%; |
|
|
|
background-color: #f3f4f6; |
|
|
|
border: 1px dashed #d1d5db; |
|
|
|
border-radius: 12px; |
|
|
|
transition: border-color 0.2s ease, background 0.2s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.icon-card:hover { |
|
|
|
background-color: #eef2ff; |
|
|
|
border-color: #4c7af0; |
|
|
|
} |
|
|
|
|
|
|
|
.model-card__inner { |
|
|
|
flex: 1; |
|
|
|
padding: 20px 24px 18px; |
|
|
|
} |
|
|
|
|
|
|
|
.model-card__header { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
margin-bottom: 8px; |
|
|
|
align-items: flex-start; |
|
|
|
gap: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.card-title { |
|
|
|
padding-right: 8px; |
|
|
|
overflow: hidden; |
|
|
|
.model-card__title { |
|
|
|
font-size: 18px; |
|
|
|
font-weight: 600; |
|
|
|
line-height: 1.4; |
|
|
|
color: #1f2937; |
|
|
|
text-overflow: ellipsis; |
|
|
|
word-break: keep-all; |
|
|
|
white-space: nowrap; |
|
|
|
color: #111827; |
|
|
|
margin-bottom: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.card-tags { |
|
|
|
display: inline-flex; |
|
|
|
gap: 8px; |
|
|
|
align-items: center; |
|
|
|
.model-card__subtitle { |
|
|
|
font-size: 13px; |
|
|
|
color: #6b7280; |
|
|
|
} |
|
|
|
|
|
|
|
.tag.version { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
padding: 4px 10px; |
|
|
|
font-size: 12px; |
|
|
|
font-weight: 600; |
|
|
|
line-height: 1; |
|
|
|
text-transform: uppercase; |
|
|
|
letter-spacing: 0.3px; |
|
|
|
border-radius: 999px; |
|
|
|
.model-card__header-right { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items: flex-end; |
|
|
|
gap: 6px; |
|
|
|
margin-top: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.status-icon { |
|
|
|
.lock-icon { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
width: 32px; |
|
|
|
height: 32px; |
|
|
|
background-color: rgb(0 0 0 / 6%); |
|
|
|
border: 1px solid rgb(0 0 0 / 8%); |
|
|
|
border-radius: 8px; |
|
|
|
width: 28px; |
|
|
|
height: 28px; |
|
|
|
border-radius: 999px; |
|
|
|
background: #f3f4f6; |
|
|
|
color: #9ca3af; |
|
|
|
} |
|
|
|
|
|
|
|
.card-meta { |
|
|
|
.model-card__tag-row { |
|
|
|
margin-top: 14px; |
|
|
|
display: flex; |
|
|
|
gap: 8px; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
margin-bottom: 8px; |
|
|
|
flex-wrap: wrap; |
|
|
|
} |
|
|
|
|
|
|
|
.tag-pill { |
|
|
|
padding: 4px 12px; |
|
|
|
border-radius: 999px; |
|
|
|
font-size: 12px; |
|
|
|
border: 1px solid #e5e7eb; |
|
|
|
background: #f9fafb; |
|
|
|
color: #4b5563; |
|
|
|
} |
|
|
|
|
|
|
|
.tag-pill--blue { |
|
|
|
background: #eef3ff; |
|
|
|
border-color: #c7d2fe; |
|
|
|
color: #2454e6; |
|
|
|
} |
|
|
|
|
|
|
|
.tag-pill--green { |
|
|
|
background: #e8f7ef; |
|
|
|
border-color: #b7e4c7; |
|
|
|
color: #13804c; |
|
|
|
} |
|
|
|
|
|
|
|
.model-card__meta-row { |
|
|
|
margin-top: 10px; |
|
|
|
font-size: 13px; |
|
|
|
color: #6b7280; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.meta-item { |
|
|
|
display: inline-flex; |
|
|
|
gap: 6px; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.meta-line { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
min-width: 0; |
|
|
|
justify-content: space-between; |
|
|
|
gap: 16px; |
|
|
|
} |
|
|
|
|
|
|
|
.meta-icon { |
|
|
|
.meta-label { |
|
|
|
color: #9ca3af; |
|
|
|
margin-right: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.card-footer { |
|
|
|
.model-card__divider { |
|
|
|
height: 1px; |
|
|
|
margin: 12px 0 12px; |
|
|
|
background: linear-gradient(to right, transparent, #e5e7eb 20%, #e5e7eb 80%, transparent); |
|
|
|
} |
|
|
|
|
|
|
|
.model-card__bottom { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
gap: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.deploy-info { |
|
|
|
font-size: 13px; |
|
|
|
color: #4b5563; |
|
|
|
} |
|
|
|
|
|
|
|
.deploy-info__line { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
padding-top: 6px; |
|
|
|
gap: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.model-card__actions { |
|
|
|
display: flex; |
|
|
|
gap: 8px; |
|
|
|
flex-shrink: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.btn { |
|
|
|
padding: 6px 16px; |
|
|
|
border-radius: 999px; |
|
|
|
font-size: 13px; |
|
|
|
border: 1px solid transparent; |
|
|
|
cursor: pointer; |
|
|
|
white-space: nowrap; |
|
|
|
transition: all 0.15s ease-out; |
|
|
|
} |
|
|
|
|
|
|
|
.btn--ghost { |
|
|
|
background: #ffffff; |
|
|
|
border-color: #e5e7eb; |
|
|
|
color: #4b5563; |
|
|
|
box-shadow: 0 2px 6px rgb(15 23 42 / 6%); |
|
|
|
} |
|
|
|
|
|
|
|
.card-divider { |
|
|
|
height: 1px; |
|
|
|
margin: 4px 0 8px; |
|
|
|
border-top: 1px dashed #e5e7eb; |
|
|
|
.btn--ghost:hover { |
|
|
|
background: #f3f4f6; |
|
|
|
} |
|
|
|
|
|
|
|
.footer-text.strong { |
|
|
|
font-weight: 600; |
|
|
|
.btn--primary { |
|
|
|
background: #2463f4; |
|
|
|
border-color: #2463f4; |
|
|
|
color: #ffffff; |
|
|
|
box-shadow: 0 6px 14px rgb(37 99 235 / 30%); |
|
|
|
} |
|
|
|
|
|
|
|
.footer-divider { |
|
|
|
flex: 1; |
|
|
|
height: 1px; |
|
|
|
border-top: 1px dashed #e5e7eb; |
|
|
|
.btn--primary:hover { |
|
|
|
background: #1d4fd8; |
|
|
|
border-color: #1d4fd8; |
|
|
|
} |
|
|
|
|
|
|
|
.algo-pill { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
padding: 4px 10px; |
|
|
|
font-weight: 700; |
|
|
|
color: #1d4ed8; |
|
|
|
letter-spacing: 0.3px; |
|
|
|
background: #e0e7ff; |
|
|
|
border: 1px solid #c7d2fe; |
|
|
|
border-radius: 10px; |
|
|
|
.dot { |
|
|
|
width: 8px; |
|
|
|
height: 8px; |
|
|
|
border-radius: 999px; |
|
|
|
} |
|
|
|
|
|
|
|
.icon-card { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
min-height: 180px; |
|
|
|
background-color: #f3f4f6; |
|
|
|
border: 1px dashed #d1d5db; |
|
|
|
border-radius: 12px; |
|
|
|
transition: border-color 0.2s ease, background 0.2s ease; |
|
|
|
.dot--success { |
|
|
|
background: #22c55e; |
|
|
|
} |
|
|
|
|
|
|
|
.icon-card:hover { |
|
|
|
background-color: #eef2ff; |
|
|
|
border-color: #4c7af0; |
|
|
|
.dot--muted { |
|
|
|
background: #d1d5db; |
|
|
|
} |
|
|
|
|
|
|
|
@media (max-width: 640px) { |
|
|
|
.model-card { |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
.model-card__bottom { |
|
|
|
flex-direction: column; |
|
|
|
align-items: flex-start; |
|
|
|
} |
|
|
|
|
|
|
|
.model-card__actions { |
|
|
|
align-self: flex-end; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.load-status { |
|
|
|
@ -419,4 +539,9 @@ onBeforeUnmount(() => { |
|
|
|
.load-more-trigger { |
|
|
|
height: 1px; |
|
|
|
} |
|
|
|
|
|
|
|
:deep(.ant-card-body) { |
|
|
|
padding: 0; |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
</style> |
|
|
|
|