style(Venom): 优化包管理器定制页 UI
- 新增品牌/概览区(软件包数、版本发布数)与工具条,列表改用卡片 + 包头像/说明双行单元格 - 配置视图改为 包信息头 + 配置/发布双栏卡片 + 发布历史卡片,表单改 label 顶置 - 全部配色走 Element Plus CSS 变量,自动适配宿主明/暗主题;引入 @element-plus/icons-vue
This commit is contained in:
1 parent
993d142bdd
commit
8beb280aad
3 files changed
+336
-93
No files matched your search
+1
@@ -8,6 +8,7 @@
|
||||
"name": "venom-ui",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"element-plus": "^2.14.3",
|
||||
"vue": "^3.5.40"
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"build": "vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"element-plus": "^2.14.3",
|
||||
"vue": "^3.5.40"
|
||||
},
|
||||
|
||||
@@ -6,9 +6,22 @@
|
||||
* 配置视图:编辑包说明/配置内容、发布新版本、查看发布历史
|
||||
*
|
||||
* 视图切换在组件内部完成(不占用宿主路由),符合「远端页面自理」的微前端约定。
|
||||
* 样式仅依赖 Element Plus 的 CSS 变量,自动适配宿主明/暗主题。
|
||||
*/
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import {
|
||||
ArrowLeft,
|
||||
Box,
|
||||
Clock,
|
||||
Collection,
|
||||
Finished,
|
||||
Plus,
|
||||
Promotion,
|
||||
Refresh,
|
||||
Search,
|
||||
User,
|
||||
} from '@element-plus/icons-vue'
|
||||
import {
|
||||
venomApi,
|
||||
type RemoteContext,
|
||||
@@ -37,6 +50,11 @@ const createForm = reactive({ PackageName: '', PackageDesc: '', ConfigText: '' }
|
||||
const configForm = reactive({ PackageDesc: '', ConfigText: '' })
|
||||
const releaseForm = reactive({ Version: '', Notes: '' })
|
||||
|
||||
/** 全部软件包的发布次数合计(列表概览用) */
|
||||
const totalReleases = computed(() =>
|
||||
packages.value.reduce((sum, p) => sum + (p.ReleaseCount || 0), 0),
|
||||
)
|
||||
|
||||
async function loadPackages(): Promise<void> {
|
||||
loading.value = true
|
||||
try {
|
||||
@@ -158,119 +176,204 @@ onMounted(loadPackages)
|
||||
<div class="venom-page">
|
||||
<!-- ==================== 列表视图 ==================== -->
|
||||
<template v-if="!openedUUID">
|
||||
<div class="head">
|
||||
<div class="brand">
|
||||
<span class="brand-name">这是Venom</span>
|
||||
<span class="brand-sub">Venom 包管理器 · 软件包列表</span>
|
||||
<!-- 品牌 / 概览 -->
|
||||
<div class="venom-hero">
|
||||
<div class="hero-badge"><el-icon :size="26"><Box /></el-icon></div>
|
||||
<div class="hero-text">
|
||||
<div class="hero-title">这是Venom</div>
|
||||
<div class="hero-sub">Venom 包管理器 · 软件包仓库(包名全局唯一)</div>
|
||||
</div>
|
||||
<div class="spacer" />
|
||||
<div class="hero-stats">
|
||||
<div class="stat">
|
||||
<div class="stat-value">{{ packages.length }}</div>
|
||||
<div class="stat-label">软件包</div>
|
||||
</div>
|
||||
<div class="stat-divider" />
|
||||
<div class="stat">
|
||||
<div class="stat-value">{{ totalReleases }}</div>
|
||||
<div class="stat-label">版本发布</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 工具条 -->
|
||||
<div class="toolbar">
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
placeholder="按包名搜索"
|
||||
clearable
|
||||
class="search"
|
||||
:prefix-icon="Search"
|
||||
@keyup.enter="loadPackages"
|
||||
@clear="loadPackages"
|
||||
/>
|
||||
<el-button @click="loadPackages">刷新</el-button>
|
||||
<el-button type="primary" @click="openCreate">新建软件包</el-button>
|
||||
<div class="spacer" />
|
||||
<el-button :icon="Refresh" round @click="loadPackages">刷新</el-button>
|
||||
<el-button type="primary" :icon="Plus" round @click="openCreate">新建软件包</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="packages" border size="default" class="table">
|
||||
<el-table-column prop="PackageName" label="包名" min-width="180" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span class="pkg-name">{{ row.PackageName }}</span>
|
||||
<!-- 包列表 -->
|
||||
<el-card shadow="never" class="panel">
|
||||
<el-table v-loading="loading" :data="packages" class="table" row-key="PackageUUID">
|
||||
<el-table-column label="软件包" min-width="260">
|
||||
<template #default="{ row }">
|
||||
<div class="pkg-cell">
|
||||
<div class="pkg-avatar"><el-icon><Collection /></el-icon></div>
|
||||
<div class="pkg-meta">
|
||||
<div class="pkg-name">{{ row.PackageName }}</div>
|
||||
<div class="pkg-desc">{{ row.PackageDesc || '—' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建人" width="150">
|
||||
<template #default="{ row }">
|
||||
<span class="muted">{{ row.CreatorName || '—' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="CreateTime" label="创建时间" width="180" />
|
||||
<el-table-column label="版本" width="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.ReleaseCount ? 'success' : 'info'" effect="plain" round size="small">
|
||||
{{ row.ReleaseCount || 0 }} 个
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="130" fixed="right" align="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="openConfig(row)">打开配置</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="还没有软件包" :image-size="90">
|
||||
<el-button type="primary" :icon="Plus" round @click="openCreate">新建软件包</el-button>
|
||||
</el-empty>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="PackageDesc" label="说明" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="CreatorName" label="创建人" width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="CreateTime" label="创建时间" width="180" />
|
||||
<el-table-column prop="ReleaseCount" label="发布数" width="90" align="center" />
|
||||
<el-table-column label="操作" width="130" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="openConfig(row)">打开配置</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="还没有软件包,点右上角「新建软件包」开始" :image-size="80" />
|
||||
</template>
|
||||
</el-table>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<!-- ==================== 配置视图 ==================== -->
|
||||
<template v-else>
|
||||
<div class="head">
|
||||
<el-button link @click="backToList">← 返回列表</el-button>
|
||||
<div class="brand">
|
||||
<span class="brand-name">{{ detail?.PackageName || '' }}</span>
|
||||
<span class="brand-sub">包配置</span>
|
||||
<!-- 包信息头 -->
|
||||
<div class="detail-head">
|
||||
<el-button :icon="ArrowLeft" text @click="backToList">返回列表</el-button>
|
||||
<div class="detail-title">
|
||||
<div class="pkg-avatar lg"><el-icon :size="18"><Box /></el-icon></div>
|
||||
<span class="detail-name">{{ detail?.PackageName || '' }}</span>
|
||||
</div>
|
||||
<div class="detail-tags">
|
||||
<el-tag type="success" effect="plain" round size="small">
|
||||
<el-icon><Finished /></el-icon>发布 {{ detail?.ReleaseCount || 0 }} 次
|
||||
</el-tag>
|
||||
<el-tag v-if="detail?.CreatorName" effect="plain" round size="small">
|
||||
<el-icon><User /></el-icon>{{ detail?.CreatorName }}
|
||||
</el-tag>
|
||||
<el-tag v-if="detail?.UpdateTime" effect="plain" round size="small">
|
||||
<el-icon><Clock /></el-icon>{{ detail?.UpdateTime }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="spacer" />
|
||||
<el-tag size="small" effect="plain">发布 {{ detail?.ReleaseCount || 0 }} 次</el-tag>
|
||||
</div>
|
||||
|
||||
<el-divider content-position="left">包配置</el-divider>
|
||||
<el-form label-width="96px" class="form">
|
||||
<el-form-item label="包名">
|
||||
<el-input :model-value="detail?.PackageName || ''" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="包说明">
|
||||
<el-input v-model="configForm.PackageDesc" maxlength="512" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="配置内容">
|
||||
<el-input
|
||||
v-model="configForm.ConfigText"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
placeholder="包配置内容(如依赖、构建参数等)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="saving" @click="saveConfig">保存配置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="detail-grid">
|
||||
<!-- 包配置 -->
|
||||
<el-card shadow="never" class="panel">
|
||||
<template #header>
|
||||
<div class="panel-head">
|
||||
<el-icon><Collection /></el-icon>
|
||||
<span>包配置</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form label-position="top" class="form">
|
||||
<el-form-item label="包名">
|
||||
<el-input :model-value="detail?.PackageName || ''" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="包说明">
|
||||
<el-input v-model="configForm.PackageDesc" maxlength="512" placeholder="可选" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item label="配置内容">
|
||||
<el-input
|
||||
v-model="configForm.ConfigText"
|
||||
type="textarea"
|
||||
:rows="7"
|
||||
placeholder="包配置内容(如依赖、构建参数等)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" round :loading="saving" @click="saveConfig">保存配置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-divider content-position="left">发布新版本</el-divider>
|
||||
<el-form label-width="96px" class="form">
|
||||
<el-form-item label="版本号">
|
||||
<el-input v-model="releaseForm.Version" maxlength="64" placeholder="如 1.0.0" class="version" />
|
||||
</el-form-item>
|
||||
<el-form-item label="发布说明">
|
||||
<el-input v-model="releaseForm.Notes" type="textarea" :rows="3" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" :loading="publishing" @click="publishRelease">发布</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 发布新版本 -->
|
||||
<el-card shadow="never" class="panel">
|
||||
<template #header>
|
||||
<div class="panel-head">
|
||||
<el-icon><Promotion /></el-icon>
|
||||
<span>发布新版本</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form label-position="top" class="form">
|
||||
<el-form-item label="版本号">
|
||||
<el-input v-model="releaseForm.Version" maxlength="64" placeholder="如 1.0.0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="发布说明">
|
||||
<el-input v-model="releaseForm.Notes" type="textarea" :rows="7" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" round :icon="Promotion" :loading="publishing" @click="publishRelease">
|
||||
发布
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<el-divider content-position="left">发布历史</el-divider>
|
||||
<el-table :data="releases" border size="small" class="table">
|
||||
<el-table-column prop="Version" label="版本" width="140" />
|
||||
<el-table-column prop="PublisherName" label="发布人" width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="CreateTime" label="发布时间" width="180" />
|
||||
<el-table-column prop="Notes" label="发布说明" min-width="200" show-overflow-tooltip />
|
||||
<template #empty>
|
||||
<el-empty description="暂无发布记录" :image-size="60" />
|
||||
<!-- 发布历史 -->
|
||||
<el-card shadow="never" class="panel">
|
||||
<template #header>
|
||||
<div class="panel-head">
|
||||
<el-icon><Clock /></el-icon>
|
||||
<span>发布历史</span>
|
||||
<el-tag class="panel-count" effect="plain" round size="small">{{ releases.length }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table>
|
||||
<el-table :data="releases" class="table" row-key="ReleaseUUID">
|
||||
<el-table-column label="版本" width="150">
|
||||
<template #default="{ row }">
|
||||
<el-tag effect="plain" round size="small">{{ row.Version }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="发布人" width="160">
|
||||
<template #default="{ row }">
|
||||
<span class="muted">{{ row.PublisherName || '—' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="CreateTime" label="发布时间" width="180" />
|
||||
<el-table-column prop="Notes" label="发布说明" min-width="200" show-overflow-tooltip />
|
||||
<template #empty>
|
||||
<el-empty description="暂无发布记录" :image-size="70" />
|
||||
</template>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<!-- ==================== 新建软件包 ==================== -->
|
||||
<el-dialog v-model="dialogVisible" title="新建软件包" width="620px" :close-on-click-modal="false">
|
||||
<el-form label-width="96px">
|
||||
<el-form label-position="top" class="form">
|
||||
<el-form-item label="包名" required>
|
||||
<el-input v-model="createForm.PackageName" maxlength="128" placeholder="包名必须全局唯一" />
|
||||
</el-form-item>
|
||||
<el-form-item label="包说明">
|
||||
<el-input v-model="createForm.PackageDesc" maxlength="512" placeholder="可选" />
|
||||
<el-input v-model="createForm.PackageDesc" maxlength="512" placeholder="可选" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item label="配置内容">
|
||||
<el-input v-model="createForm.ConfigText" type="textarea" :rows="5" placeholder="可选" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="saving" @click="submitCreate">创建</el-button>
|
||||
<el-button round @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" round :loading="saving" @click="submitCreate">创建</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -280,43 +383,181 @@ onMounted(loadPackages)
|
||||
.venom-page {
|
||||
padding: 4px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
}
|
||||
.head {
|
||||
|
||||
/* ==== 品牌 / 概览 ==== */
|
||||
.venom-hero {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 12px;
|
||||
gap: 14px;
|
||||
padding: 16px 18px;
|
||||
border-radius: 12px;
|
||||
background: var(--el-color-primary-light-9);
|
||||
border: 1px solid var(--el-color-primary-light-7);
|
||||
}
|
||||
.brand {
|
||||
.hero-badge {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, var(--el-color-primary), var(--el-color-primary-light-3));
|
||||
box-shadow: 0 4px 12px var(--el-color-primary-light-5);
|
||||
}
|
||||
.brand-name {
|
||||
font-size: 16px;
|
||||
.hero-text {
|
||||
min-width: 0;
|
||||
}
|
||||
.hero-title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--el-text-color-primary);
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.brand-sub {
|
||||
.hero-sub {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
.hero-stats {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
}
|
||||
.stat {
|
||||
text-align: center;
|
||||
}
|
||||
.stat-value {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
.stat-divider {
|
||||
width: 1px;
|
||||
height: 28px;
|
||||
background: var(--el-border-color);
|
||||
}
|
||||
|
||||
/* ==== 工具条 ==== */
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.search {
|
||||
width: 260px;
|
||||
}
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
.search {
|
||||
width: 220px;
|
||||
|
||||
/* ==== 面板 ==== */
|
||||
.panel {
|
||||
border-radius: 12px;
|
||||
}
|
||||
.panel-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
.panel-count {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.table {
|
||||
width: 100%;
|
||||
}
|
||||
.form {
|
||||
max-width: 720px;
|
||||
|
||||
/* ==== 包单元格 ==== */
|
||||
.pkg-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-width: 0;
|
||||
}
|
||||
.version {
|
||||
width: 220px;
|
||||
.pkg-avatar {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 9px;
|
||||
color: var(--el-color-primary);
|
||||
background: var(--el-color-primary-light-9);
|
||||
border: 1px solid var(--el-color-primary-light-8);
|
||||
}
|
||||
.pkg-avatar.lg {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.pkg-meta {
|
||||
min-width: 0;
|
||||
}
|
||||
.pkg-name {
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
.pkg-desc {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.muted {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
/* ==== 配置视图 ==== */
|
||||
.detail-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.detail-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.detail-name {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
.detail-tags {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.detail-tags .el-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.detail-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
.form {
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user