|
|
|
@ -37,14 +37,26 @@ const modelCardList = ref<Array<ModelItem>>([]) |
|
|
|
const lastQuery = ref<ModelQueryParams | null>(null) |
|
|
|
const colors = ['#8dc63f', '#dbb09e'] |
|
|
|
const statusStr = ['未下装', '已下装'] |
|
|
|
const icons = ['material-symbols:lock-open-right-outline', 'material-symbols:lock-outline'] |
|
|
|
const statusIcons = ['material-symbols:lock-open', 'material-symbols:lock'] |
|
|
|
|
|
|
|
const buildQuery = (value: any): ModelQueryParams => ({ |
|
|
|
function colorToBg(hex: string, alpha = 0.5) { |
|
|
|
const raw = (hex || '').replace('#', '') |
|
|
|
if (raw.length !== 6) |
|
|
|
return 'rgba(0,0,0,0.5)' |
|
|
|
const r = Number.parseInt(raw.slice(0, 2), 16) |
|
|
|
const g = Number.parseInt(raw.slice(2, 4), 16) |
|
|
|
const b = Number.parseInt(raw.slice(4, 6), 16) |
|
|
|
return `rgba(${r}, ${g}, ${b}, ${alpha})` |
|
|
|
} |
|
|
|
|
|
|
|
function buildQuery(value: any): ModelQueryParams { |
|
|
|
return { |
|
|
|
unitId: value?.unit, |
|
|
|
typeId: value?.type, |
|
|
|
systemId: value?.system, |
|
|
|
name: value?.name, |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async function loadModelList(value: any) { |
|
|
|
const queryParams = buildQuery(value) |
|
|
|
@ -61,7 +73,7 @@ async function loadModelList(value: any) { |
|
|
|
id: modelCard.id, |
|
|
|
title: modelCard.name, |
|
|
|
version: modelCard.version, |
|
|
|
icon: icons[statusIndex], |
|
|
|
icon: statusIcons[statusIndex], |
|
|
|
value: 1, |
|
|
|
total: 1, |
|
|
|
color: colors[statusIndex], |
|
|
|
@ -69,14 +81,10 @@ async function loadModelList(value: any) { |
|
|
|
creator: modelCard.creator, |
|
|
|
createTime: modelCard.createTime, |
|
|
|
description: modelCard.name, |
|
|
|
headStyle: { |
|
|
|
backgroundColor: colors[statusIndex], |
|
|
|
fontSize: '20px', |
|
|
|
}, |
|
|
|
bodyStyle: { |
|
|
|
borderColor: colors[statusIndex], |
|
|
|
borderWidth: '1px', |
|
|
|
}, |
|
|
|
headStyle: {}, |
|
|
|
bodyStyle: {}, |
|
|
|
statusColor: colors[statusIndex], |
|
|
|
cardBg: colorToBg(colors[statusIndex]), |
|
|
|
} |
|
|
|
cardList.push(card) |
|
|
|
} |
|
|
|
@ -100,23 +108,40 @@ async function confirmDelete(id: number | string) { |
|
|
|
|
|
|
|
<template> |
|
|
|
<div class="enter-y"> |
|
|
|
<div class="grid gap-4 md:grid-cols-4"> |
|
|
|
<div class="card-grid"> |
|
|
|
<template v-for="item in modelCardList" :key="item.title"> |
|
|
|
<Dropdown :trigger="['contextmenu']"> |
|
|
|
<Card |
|
|
|
size="small" |
|
|
|
:loading="loading" |
|
|
|
:title="item.title" |
|
|
|
:hoverable="true" |
|
|
|
:body-style="item.bodyStyle" |
|
|
|
:head-style="item.headStyle" |
|
|
|
class="model-card" |
|
|
|
:style="{ backgroundColor: item.cardBg }" |
|
|
|
@click="changeModel(item.id, item.version)" |
|
|
|
> |
|
|
|
<template #extra> |
|
|
|
<Icon :icon="item.icon" :size="30" color="white" /> |
|
|
|
</template> |
|
|
|
<div class="grid p-2 px-5 md:grid-cols-3"> |
|
|
|
<span>创建人: {{ item.creator }}</span><span>创建时间: {{ item.createTime }}</span><span>模型状态: {{ item.status }}</span> |
|
|
|
<div class="card-top"> |
|
|
|
<div class="card-title"> |
|
|
|
{{ item.title }} |
|
|
|
</div> |
|
|
|
<div class="card-tags"> |
|
|
|
<span class="status-icon" :style="{ color: item.statusColor }"> |
|
|
|
<Icon :icon="item.icon" :size="20" /> |
|
|
|
</span> |
|
|
|
</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="solar:calendar-bold" :size="16" class="meta-icon" /> |
|
|
|
{{ item.createTime || '--' }} |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
<div class="card-footer"> |
|
|
|
<span class="footer-text">版本</span> |
|
|
|
<span class="footer-text strong">{{ item.version || 'v-test' }}</span> |
|
|
|
</div> |
|
|
|
</Card> |
|
|
|
<template #overlay> |
|
|
|
@ -143,11 +168,115 @@ async function confirmDelete(id: number | string) { |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<style> |
|
|
|
<style scoped> |
|
|
|
.card-grid { |
|
|
|
display: grid; |
|
|
|
grid-template-columns: repeat(4, minmax(0, 1fr)); |
|
|
|
gap: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.model-card { |
|
|
|
padding: 12px; |
|
|
|
border: 1px solid rgb(0 0 0 / 2%); |
|
|
|
border-radius: 12px; |
|
|
|
box-shadow: 0 6px 18px rgb(0 0 0 / 6%); |
|
|
|
transition: transform 0.2s ease, box-shadow 0.2s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.model-card:hover { |
|
|
|
box-shadow: 0 12px 28px rgb(0 0 0 / 10%); |
|
|
|
transform: translateY(-2px); |
|
|
|
} |
|
|
|
|
|
|
|
.card-top { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
margin-bottom: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.card-title { |
|
|
|
padding-right: 8px; |
|
|
|
overflow: hidden; |
|
|
|
font-size: 18px; |
|
|
|
font-weight: 600; |
|
|
|
line-height: 1.4; |
|
|
|
color: #1f2937; |
|
|
|
text-overflow: ellipsis; |
|
|
|
word-break: keep-all; |
|
|
|
white-space: nowrap; |
|
|
|
} |
|
|
|
|
|
|
|
.card-tags { |
|
|
|
display: inline-flex; |
|
|
|
gap: 8px; |
|
|
|
align-items: center; |
|
|
|
} |
|
|
|
|
|
|
|
.status-icon { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
width: 32px; |
|
|
|
height: 32px; |
|
|
|
background-color: rgb(0 0 0 / 3%); |
|
|
|
border-radius: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.card-meta { |
|
|
|
display: flex; |
|
|
|
gap: 8px; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
margin-bottom: 12px; |
|
|
|
font-size: 12px; |
|
|
|
color: #6b7280; |
|
|
|
} |
|
|
|
|
|
|
|
.meta-item { |
|
|
|
display: inline-flex; |
|
|
|
gap: 6px; |
|
|
|
align-items: center; |
|
|
|
min-width: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.meta-icon { |
|
|
|
color: #9ca3af; |
|
|
|
} |
|
|
|
|
|
|
|
.card-footer { |
|
|
|
display: flex; |
|
|
|
gap: 8px; |
|
|
|
align-items: center; |
|
|
|
padding-top: 10px; |
|
|
|
font-size: 13px; |
|
|
|
color: #4b5563; |
|
|
|
border-top: 1px dashed #e5e7eb; |
|
|
|
} |
|
|
|
|
|
|
|
.footer-text.strong { |
|
|
|
font-weight: 600; |
|
|
|
} |
|
|
|
|
|
|
|
.footer-divider { |
|
|
|
flex: 1; |
|
|
|
height: 1px; |
|
|
|
border-top: 1px dashed #e5e7eb; |
|
|
|
} |
|
|
|
|
|
|
|
.icon-card { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
background-color: #f2f2f2; |
|
|
|
min-height: 180px; |
|
|
|
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; |
|
|
|
} |
|
|
|
</style> |
|
|
|
|