。。。

This commit is contained in:
2026-09-20 23:38:08 +08:00
parent 5861b25847
commit 1df91c17ff
5 changed files with 29 additions and 13 deletions
+1
View File
@@ -3,6 +3,7 @@ node_modules/
frontend/node_modules/
frontend/dist/
backend/node_modules/
.CodeCounter
# 运行时数据(SQLite)
backend/data/
+1 -1
View File
@@ -17,6 +17,6 @@ services:
- "/volume2/docker/verdaccio_verdaccio-1/verdaccio_storage:/verdaccio/storage" # Verdaccio 缓存目录(读写,清理需要)
# 数据目录:默认 bind mount 到宿主机 /volume2/docker/verdaccio-manager/data,
# 可在 NAS 文件管理器里直接查看/备份/修改 manager.db;如需改路径,在 .env 设 VCM_DATA_DIR=绝对路径
- "${VCM_DATA_DIR:-/volume2/docker/verdaccio-manager/data}:/app/data" # SQLite 数据(manager.db + WAL)
- "${VCM_DATA_DIR:-/volume2/docker/verdaccio-cache-manager/data}:/app/data" # SQLite 数据(manager.db + WAL)
ports:
- "42338:3000"
+9 -9
View File
@@ -143,29 +143,29 @@ function quickClean() {
</template>
<style scoped>
.stats-1 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; margin-bottom: 18px; }
.stats-2 { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; margin-bottom: 24px; }
.stats-1 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; margin-bottom: 18px; }
.stats-2 { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 16px; margin-bottom: 24px; }
.sec-head { display: flex; align-items: center; justify-content: space-between; margin: 4px 2px 16px; gap: 12px; flex-wrap: wrap; }
.sec-title { font-size: 17px; font-weight: 700; display: flex; align-items: center; gap: 10px; }
.sec-title .emo { font-size: 19px; }
.sec-sub { font-family: var(--num); font-size: 12px; color: var(--ink-faint); font-weight: 600; }
.link-all { padding: 6px 14px; border: none; border-radius: 999px; background: var(--panel-soft); color: var(--orange); font-size: 13px; font-weight: 600; cursor: pointer; transition: transform .2s, box-shadow .2s; }
.link-all:hover { transform: translateY(-1px); box-shadow: var(--shadow); }
.pkg-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.pkg-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.loading-tip { text-align: center; padding: 40px 0; color: var(--ink-faint); font-size: 13px; }
.empty-box { text-align: center; padding: 60px 0; color: var(--ink-faint); font-size: 13px; }
@media (max-width: 1180px) {
.stats-1 { grid-template-columns: repeat(2, 1fr); }
.stats-2 { grid-template-columns: repeat(3, 1fr); }
.stats-1 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.stats-2 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.stats-2 > :nth-child(5) { grid-column: 1 / -1; } /* 5 卡跨列铺满,避免 2+2+1 */
.pkg-grid { grid-template-columns: repeat(2, 1fr); }
.pkg-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 767px) {
.stats-1 { grid-template-columns: repeat(2, 1fr); gap: 10px; }
.stats-2 { grid-template-columns: repeat(2, 1fr); gap: 10px; }
.stats-1 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.stats-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.stats-2 > :nth-child(5) { grid-column: 1 / -1; } /* 第 5 张跨整行 */
.pkg-grid { grid-template-columns: 1fr; gap: 12px; }
.pkg-grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
.sec-head { padding: 4px 0 12px; gap: 8px; }
.sec-title { font-size: 15px; }
.sec-sub { font-size: 11px; }
+18 -3
View File
@@ -13,8 +13,17 @@ const route = useRoute()
const keyword = ref('')
const statusFilter = ref('all') // all | warn | ok | ignored | broken
const sortMode = ref('default') // default | versions-desc | size-desc
const isMobile = ref(false)
let debounceTimer = null
// —— 响应式 placeholder:移动端精简,桌面端完整 ——
function checkMobile() {
isMobile.value = window.matchMedia('(max-width: 767px)').matches
}
const placeholderText = computed(() =>
isMobile.value ? '搜索包名…(回车搜索 · 实时过滤)' : '搜索包名…(回车搜索 · 实时过滤 · 防抖 300ms)',
)
// —— 搜索历史(localStorage 最近 5 条,提交时记录) ——
const HISTORY_KEY = 'vcm-search-history'
const searchHistory = ref(JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]'))
@@ -63,6 +72,8 @@ function closeMenus() {
onMounted(() => {
document.addEventListener('click', closeMenus)
checkMobile()
window.addEventListener('resize', checkMobile)
// 数据由 App 初始化时统一加载,切换菜单不再重复拉取全量列表(响应大,避免卡顿)
if (route.query.status && ['all', 'warn', 'ok', 'ignored', 'broken'].includes(route.query.status)) {
statusFilter.value = route.query.status
@@ -70,6 +81,7 @@ onMounted(() => {
})
onUnmounted(() => {
document.removeEventListener('click', closeMenus)
window.removeEventListener('resize', checkMobile)
})
watch(keyword, () => {
@@ -138,7 +150,7 @@ async function onCleanConfirmed(res) {
<input
v-model="keyword"
type="text"
placeholder="搜索包名…(回车搜索 · 实时过滤 · 防抖 300ms)"
:placeholder="placeholderText"
@keyup.esc="keyword = ''"
@keyup.enter="submitSearch()"
/>
@@ -437,7 +449,10 @@ async function onCleanConfirmed(res) {
.search-box .s-go { display: none; }
.history-row { width: 100%; }
.toolbar { margin: 16px 0 10px; }
.vtable { overflow-x: auto; }
.vtable table { min-width: 880px; }
.vtable { overflow: auto; -webkit-overflow-scrolling: touch; }
.vtable table { min-width: 880px; width: auto; }
.vtable th:first-child,
.vtable td:first-child { min-width: 220px; }
.pkg-cell { word-break: break-all; }
}
</style>
Binary file not shown.