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