diff --git a/frontend/src/features/admin/components/AdminTablePagination.vue b/frontend/src/features/admin/components/AdminTablePagination.vue index ca8e0944..0cf9c3b8 100644 --- a/frontend/src/features/admin/components/AdminTablePagination.vue +++ b/frontend/src/features/admin/components/AdminTablePagination.vue @@ -1,5 +1,6 @@ diff --git a/frontend/src/features/admin/views/AdminListingsView.vue b/frontend/src/features/admin/views/AdminListingsView.vue index 0f2ea2ea..5a739e7f 100644 --- a/frontend/src/features/admin/views/AdminListingsView.vue +++ b/frontend/src/features/admin/views/AdminListingsView.vue @@ -11,6 +11,7 @@ import { type AdminListingQuery, type Listing, } from '@/features/listings' +import AdminTablePagination from '@/features/admin/components/AdminTablePagination.vue' import { useAdminTable } from '@/features/admin/composables/useAdminTable' import { adminPath } from '@/shared/utils/adminPath' import { formatCentWithSymbol } from '@/shared/utils/money' @@ -79,14 +80,6 @@ const { const listings = computed(() => listingPage.value.items) const totalListings = computed(() => listingPage.value.total) -const publishedCount = computed( - () => listings.value.filter(item => item.status === 'published').length -) -const rentedCount = computed(() => listings.value.filter(item => item.status === 'rented').length) -const pendingCount = computed( - () => listings.value.filter(item => item.review_status === 'pending').length -) -const totalPages = computed(() => Math.max(1, Math.ceil(totalListings.value / pageSize.value))) const insuranceOptions = computed(() => publishOptions.value.insurance_options.length ? publishOptions.value.insurance_options @@ -372,36 +365,6 @@ function levelSlotLabel(value: string) { return value ? value.replace(/级$/, '') : '-' } -function setStatusFilter(status: string) { - filters.status = (filters.status === status ? '' : status) as AdminListingQuery['status'] - filters.review_status = '' - void queryListings() -} - -function setReviewStatusFilter(reviewStatus: string) { - filters.review_status = ( - filters.review_status === reviewStatus ? '' : reviewStatus - ) as AdminListingQuery['review_status'] - filters.status = '' - void queryListings() -} - -async function handlePageSizeChange(size: number) { - pageSize.value = size - currentPage.value = 1 - await loadListings() -} - -async function prevPage() { - currentPage.value = Math.max(1, currentPage.value - 1) - await loadListings() -} - -async function nextPage() { - currentPage.value = Math.min(totalPages.value, currentPage.value + 1) - await loadListings() -} - async function copyTableScreenshot() { try { const blob = await createTableScreenshotBlob() @@ -690,43 +653,25 @@ function formatQuantity(value: number) {
- -
-
- 全部商品 - {{ totalListings }} +
+
+ 筛选条件 + + 共 {{ totalListings }} 件商品 +
-
- 已上架 - {{ publishedCount }} -
-
- 已锁定 - {{ rentedCount }} -
-
- 待审核 - {{ pendingCount }} +
+ 重置 + 查询 + 复制截图 + 下载截图
-
@@ -813,7 +758,7 @@ function formatQuantity(value: number) { - + -
- 重置 - 查询 - 复制截图 - 下载截图 -
@@ -1095,29 +1030,13 @@ function formatQuantity(value: number) { -
- 当前页 {{ listings.length }} 条,共 {{ totalListings }} 条 -
- 每页 - - - - - - - {{ currentPage }}/{{ totalPages }}页 - 上页 - 下页 -
-
+ diff --git a/frontend/src/features/auth/views/MobileProfileView.css b/frontend/src/features/auth/views/MobileProfileView.css index 281439f7..9a711c13 100644 --- a/frontend/src/features/auth/views/MobileProfileView.css +++ b/frontend/src/features/auth/views/MobileProfileView.css @@ -12,31 +12,6 @@ background: linear-gradient(180deg, #fff8f3 0%, #ffffff 82%); } -.hero-top-row { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 14px; -} - -.hero-title { - display: grid; - gap: 3px; -} - -.app-title { - font-size: 17px; - font-weight: 900; - color: #111827; - letter-spacing: 0; -} - -.hero-title small { - color: #8b95a5; - font-size: 10px; - font-weight: 600; -} - .hero-setting-btn { display: grid; width: 34px; @@ -953,6 +928,528 @@ min-width: 132px; } +/* ========== Compact mobile account center ========== */ +.profile-hero { + position: relative; + padding: 15px 16px 14px; + border: 0; + border-radius: 0 0 18px 18px; + background: linear-gradient(165deg, #fff8f1 0%, #ffffff 76%); + box-shadow: 0 5px 18px rgba(154, 89, 25, 0.045); +} + +.hero-setting-btn { + position: absolute; + top: 14px; + right: 16px; + z-index: 1; + width: 32px; + height: 32px; + border-color: #f2dfd0; +} + +.profile-hero-content { + padding-right: 38px; +} + +.avatar-circle { + width: 62px; + height: 62px; + border: 2px solid #ffffff; + box-shadow: + 0 0 0 1px #f0d8c6, + 0 5px 12px rgba(185, 104, 34, 0.1); +} + +.user-nickname { + font-size: 18px; +} + +.user-meta { + margin-top: 4px; + font-size: 11px; +} + +.owner-quality-tag { + border-color: #edcd91; + background: #fff3da !important; + color: #995b08 !important; +} + +.hero-status-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-top: 13px; + padding-top: 11px; + border-top: 1px solid #f4e9df; +} + +.hero-level-pill, +.hero-benefits-btn { + display: inline-flex; + align-items: center; + min-height: 28px; + border: 0; + background: transparent; +} + +.hero-level-pill { + min-width: 0; + gap: 5px; + padding: 0 9px; + border: 1px solid #f1dccb; + border-radius: 999px; + background: rgba(255, 255, 255, 0.82); +} + +.hero-level-pill span { + color: #8d7c70; + font-size: 9px; +} + +.hero-level-pill strong { + overflow: hidden; + color: #b65308; + font-size: 12px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.hero-level-pill .van-icon { + flex: 0 0 auto; + color: #b98e6d; +} + +.hero-level-pill.is-store { + border-color: #ccebd9; + background: #f3fbf6; +} + +.hero-level-pill.is-store strong { + color: #13864c; +} + +.hero-benefits-btn { + flex: 0 0 auto; + gap: 2px; + padding: 0; + color: #7e8794; + font-size: 10px; + font-weight: 700; +} + +.asset-overview-card { + display: grid; + grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr); + margin: 12px 16px 0; + overflow: hidden; + border: 1px solid #eceff3; + border-radius: 14px; + background: #ffffff; + box-shadow: 0 4px 14px rgba(15, 23, 42, 0.03); +} + +.asset-points { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: center; + gap: 9px; + min-width: 0; + padding: 13px 11px; + border: 0; + border-right: 1px solid #f0f2f5; + background: linear-gradient(135deg, #fff9f3 0%, #ffffff 88%); + text-align: left; +} + +.asset-icon { + display: grid; + width: 34px; + height: 34px; + flex: 0 0 auto; + place-items: center; + border-radius: 10px; +} + +.points-icon { + background: #ffeadc; + color: #ef6200; +} + +.asset-copy { + display: grid; + min-width: 0; + gap: 1px; +} + +.asset-copy small { + color: #8b95a3; + font-size: 9px; + font-weight: 700; +} + +.asset-copy strong { + color: #252d3b; + font-size: 18px; + line-height: 1.15; +} + +.asset-copy em { + overflow: hidden; + color: #9aa2ae; + font-size: 8px; + font-style: normal; + text-overflow: ellipsis; + white-space: nowrap; +} + +.asset-arrow { + color: #b9aea3; +} + +.asset-wallet { + display: grid; + align-content: center; + gap: 6px; + min-width: 0; + padding: 12px 13px; + background: #ffffff; +} + +.asset-wallet-head, +.asset-wallet-main { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} + +.asset-wallet-head > span { + color: #8b95a3; + font-size: 9px; + font-weight: 700; +} + +.asset-wallet-head button { + padding: 0; + border: 0; + background: transparent; + color: #b27035; + font-size: 9px; + font-weight: 700; +} + +.asset-wallet-main > strong { + min-width: 0; + overflow: hidden; + color: #222a37; + font-size: 19px; + line-height: 1.2; + text-overflow: ellipsis; + white-space: nowrap; +} + +.asset-withdraw { + flex: 0 0 auto; + min-height: 26px; + padding: 0 9px; + border: 1px solid #f3c8aa; + border-radius: 999px; + background: #fff8f2; + color: #d95b00; + font-size: 10px; + font-weight: 800; +} + +.quality-entry-card { + display: grid; + gap: 9px; + margin: 12px 16px 0; + padding: 12px 13px; + border: 1px solid #eee2d3; + border-radius: 14px; + background: linear-gradient(135deg, #fffaf4 0%, #ffffff 74%); + box-shadow: 0 4px 14px rgba(134, 85, 34, 0.025); +} + +.quality-entry-card.is-active { + border-color: #e6c17c; + background: linear-gradient(135deg, #fff8e9 0%, #ffffff 74%); +} + +.quality-entry-head, +.quality-entry-title, +.quality-entry-actions, +.quality-entry-active { + display: flex; + align-items: center; +} + +.quality-entry-head { + justify-content: space-between; + gap: 10px; +} + +.quality-entry-title { + min-width: 0; + gap: 9px; +} + +.quality-entry-icon { + display: grid; + width: 30px; + height: 30px; + flex: 0 0 auto; + place-items: center; + border: 1px solid #efd7b9; + border-radius: 9px; + background: #fff1df; + color: #cf670c; +} + +.quality-entry-copy { + display: grid; + min-width: 0; + gap: 1px; +} + +.quality-entry-copy span { + color: #8c7c6e; + font-size: 9px; + font-weight: 700; +} + +.quality-entry-copy strong { + overflow: hidden; + color: #2d3340; + font-size: 13px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.quality-entry-card :deep(.van-tag) { + flex: 0 0 auto; + font-size: 9px; +} + +.quality-entry-summary { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 6px 10px; + padding-top: 8px; + border-top: 1px solid #f3eadf; +} + +.quality-entry-summary span { + color: #877a6e; + font-size: 9px; +} + +.quality-entry-summary button { + display: inline-flex; + align-items: center; + gap: 2px; + margin-left: auto; + padding: 0; + border: 0; + background: transparent; + color: #bd681b; + font-size: 9px; + font-weight: 700; +} + +.quality-entry-actions, +.quality-entry-active { + justify-content: space-between; + gap: 8px; + padding-top: 8px; + border-top: 1px solid #f3eadf; +} + +.quality-entry-actions > span, +.quality-entry-active > span { + min-width: 0; + color: #8a8178; + font-size: 9px; + line-height: 1.45; +} + +.quality-entry-actions > div { + display: flex; + flex: 0 0 auto; + gap: 5px; +} + +.quality-entry-actions :deep(.van-button) { + height: 28px; + padding: 0 9px; + font-size: 9px; + font-weight: 800; +} + +.quality-cancel-link { + flex: 0 0 auto; + min-height: 26px; + padding: 0 8px; + border: 1px solid #f4c4cb; + border-radius: 999px; + background: #fff7f8; + color: #c63d50; + font-size: 9px; + font-weight: 800; +} + +.quality-cancel-link:disabled { + opacity: 0.45; +} + +.service-panel, +.more-services-card { + margin: 12px 16px 0; + border: 1px solid #eceff3; + border-radius: 14px; + background: #ffffff; + box-shadow: 0 4px 14px rgba(15, 23, 42, 0.03); +} + +.service-panel { + padding: 13px 14px; +} + +.service-section-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + margin-bottom: 10px; +} + +.service-section-head h3 { + margin: 0; + color: #202733; + font-size: 13px; +} + +.service-section-head button { + display: inline-flex; + align-items: center; + gap: 1px; + padding: 0; + border: 0; + background: transparent; + color: #8a929f; + font-size: 9px; +} + +.service-grid { + display: grid; + align-items: start; +} + +.service-grid.five { + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.service-grid.three { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.service-item { + display: grid; + justify-items: center; + gap: 5px; + min-width: 0; +} + +.service-item:active .service-icon { + transform: scale(0.92); +} + +.service-icon { + display: grid; + width: 36px; + height: 36px; + place-items: center; + border-radius: 10px; + transition: transform 0.15s ease; +} + +.service-icon.warning { + background: #fff5de; + color: #d89000; +} + +.service-icon.info { + background: #edf4ff; + color: #3178d9; +} + +.service-icon.primary { + background: #eef4ff; + color: #1d6dd1; +} + +.service-icon.success { + background: #ebf9f3; + color: #159a6b; +} + +.service-icon.orange { + background: #fff0e7; + color: #e96508; +} + +.service-icon.gold { + background: #fff6e6; + color: #c78a21; +} + +.service-icon.teal { + background: #e9f8f7; + color: #13938d; +} + +.service-item > span { + overflow: hidden; + max-width: 100%; + color: #4a5361; + font-size: 10px; + font-weight: 600; + text-overflow: ellipsis; + white-space: nowrap; +} + +.service-divider { + height: 1px; + margin: 13px 0; + background: #f0f2f5; +} + +.more-services-card { + overflow: hidden; + margin-bottom: 14px; +} + +.more-services-title { + padding: 13px 14px 8px; + color: #4e5867; + font-size: 11px; + font-weight: 800; +} + +.more-services-card :deep(.van-cell) { + padding: 11px 14px; + font-size: 13px; +} + +.more-services-card :deep(.van-cell__left-icon) { + margin-right: 9px; + color: #9a7454; +} + /* ========== 响应式适配 ========== */ @media (min-width: 520px) { .mobile-profile-shell { diff --git a/frontend/src/features/auth/views/MobileProfileView.vue b/frontend/src/features/auth/views/MobileProfileView.vue index a2806913..6eb0aa5a 100644 --- a/frontend/src/features/auth/views/MobileProfileView.vue +++ b/frontend/src/features/auth/views/MobileProfileView.vue @@ -139,6 +139,7 @@ const settingsGroups = [ title: '账号与安全', items: [ { label: '资料更改', icon: 'edit', action: 'profile' }, + { label: '修改密码', icon: 'lock', action: 'password' }, { label: '实名认证', icon: 'idcard', action: 'realname' }, { label: '注销账号', icon: 'delete-o', action: 'cancel-account' }, ], @@ -328,6 +329,9 @@ function onSettingClick(action: string) { case 'profile': openProfileEditor() break + case 'password': + openPasswordEditor() + break case 'realname': router.push('/m/realname') break @@ -464,15 +468,14 @@ function resolveAvatarURL(url: string | undefined | null) { - -
- - - +