优化pc页面ui大小和商品管理的表格项目

This commit is contained in:
yml
2026-06-01 00:29:48 +08:00
parent 0797452ea4
commit 4437c3b439
8 changed files with 215 additions and 73 deletions
+53 -1
View File
@@ -474,7 +474,7 @@ h1 {
.table-panel {
margin-top: 0;
width: 100%;
overflow-x: auto;
overflow-x: hidden;
background: #ffffff;
border-radius: 14px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
@@ -500,6 +500,58 @@ h1 {
min-width: 760px;
}
.admin-listings-table.el-table .el-table__inner-wrapper {
min-width: 0;
}
.admin-listings-table.el-table .el-scrollbar__wrap {
overflow-x: hidden !important;
}
.admin-listings-table.el-table .el-scrollbar__bar.is-horizontal {
display: none;
}
.admin-listings-table.el-table {
font-size: 12px;
}
.admin-listings-table.el-table th {
font-size: 11px;
letter-spacing: 0;
text-transform: none;
}
.admin-listings-table.el-table .cell {
padding: 0 5px;
line-height: 1.35;
white-space: normal;
word-break: break-word;
}
.admin-listings-table.el-table th .cell {
white-space: nowrap;
word-break: keep-all;
overflow-wrap: normal;
overflow: visible;
}
.admin-listings-table .listing-code {
display: inline-block;
font-size: 11px;
line-height: 1;
white-space: nowrap;
word-break: keep-all;
}
.admin-listings-table.el-table .el-table__cell {
padding: 8px 0;
}
.admin-listings-table.el-table .el-button--small {
padding: 4px 8px;
}
.table-subtext {
display: block;
margin-top: 4px;
+2 -2
View File
@@ -58,7 +58,7 @@
.page {
width: 100%;
max-width: 1440px;
max-width: 1720px;
}
.page-header {
@@ -605,7 +605,7 @@ h1 {
}
.pc-main {
width: min(1280px, calc(100% - 40px));
width: min(1720px, calc(100% - 40px));
margin: 0 auto;
padding: 18px 0 56px;
}
+34 -3
View File
@@ -20,6 +20,10 @@ export function getCoinM(item: Listing) {
return getCoinWan(item) / 100;
}
export function formatListingCode(item: Listing) {
return `SP${String(item.id).padStart(6, "0")}`;
}
export function formatHafCoinM(amountWan: number) {
const amountM = amountWan / 100;
const rounded = Math.round(amountM * 10) / 10;
@@ -185,10 +189,32 @@ export function getOnlineTimeText(item: Listing) {
}
export function getDailyLoss(item: Listing) {
const dailyLossM = getDailyLossM(item);
return dailyLossM > 0 ? `${formatCompactNumber(dailyLossM)}M` : "";
}
export function getDailyLossM(item: Listing) {
const configuredLoss = readAssetNumber(item, "daily_loss_m");
if (configuredLoss > 0) return configuredLoss;
const coinWan = getCoinWan(item);
if (coinWan >= 30000) return "30M";
if (coinWan >= 10000) return "20M";
return "10M";
if (coinWan >= 30000) return 30;
if (coinWan >= 10000) return 20;
return 10;
}
export function getEstimatedRentalDays(item: Listing) {
const coinM = getCoinM(item);
const dailyLossM = getDailyLossM(item);
if (coinM <= 0 || dailyLossM <= 0) return 0;
return coinM / dailyLossM;
}
export function formatEstimatedRentalDuration(item: Listing) {
const days = getEstimatedRentalDays(item);
if (days <= 0) return "--";
if (days < 1) return `${Math.max(1, Math.round(days * 24))}小时`;
return `${formatCompactNumber(days)}`;
}
export function readAssetString(item: Listing, key: string) {
@@ -237,3 +263,8 @@ function formatRatioNumber(value: number) {
const rounded = roundMoney(value);
return Number.isInteger(rounded) ? `${rounded}` : rounded.toFixed(2);
}
function formatCompactNumber(value: number) {
const rounded = Math.round(value * 10) / 10;
return Number.isInteger(rounded) ? `${rounded}` : rounded.toFixed(1);
}
+1 -1
View File
@@ -308,7 +308,7 @@ function handleKeydown(e: KeyboardEvent) {
<style scoped>
.chat-page {
max-width: 900px;
max-width: 1720px;
margin: 0 auto;
}
+120 -44
View File
@@ -5,8 +5,17 @@ import { computed, reactive } from 'vue'
import { fetchAdminListings, type AdminListingQuery, type Listing } from '@/api/listings'
import { useAdminTable } from '@/composables/useAdminTable'
import { useMoney } from '@/composables/useMoney'
import { listingReviewStatusLabel, listingStatusLabel } from '@/utils/statusLabels'
import { formatDateTime } from '@/utils/time'
import {
assetRegions,
formatEstimatedRentalDuration,
formatHafCoinM,
formatListingCode,
formatRatio,
getCoinWan,
getDailyLoss,
getResourceQuantity,
getSkinGroup,
} from '@/utils/listingDisplay'
const money = useMoney()
@@ -38,22 +47,63 @@ function listingPrice(row: Listing) {
return money(row.price)
}
function ownerName(row: Listing) {
return row.owner_phone || row.owner_nickname || `号主 ${row.owner_id}`
function listingCoinM(row: Listing) {
return formatHafCoinM(getCoinWan(row))
}
function statusType(status: string) {
if (status === 'published') return 'success'
if (status === 'rented') return 'warning'
if (status === 'offline') return 'info'
return ''
function assetText(row: Listing, key: string) {
const value = row.asset_summary?.[key]
if (typeof value === 'number') return formatQuantity(value)
if (typeof value === 'string' && value.trim()) return value.trim()
return '-'
}
function reviewType(status: string) {
if (status === 'approved') return 'success'
if (status === 'pending') return 'warning'
if (status === 'rejected') return 'danger'
return 'info'
function levelText(row: Listing, key: string) {
const value = assetText(row, key)
return value === '-' ? value : value.replace(/级$/, '')
}
function regionText(row: Listing) {
const regions = assetRegions(row)
return regions.length ? regions.join('、') : '-'
}
function resourceText(row: Listing, key: string) {
const quantity = getResourceQuantity(row, key)
return quantity > 0 ? formatQuantity(quantity) : '-'
}
function skinGroupText(row: Listing, groupKey: string) {
const skins = getSkinGroup(row, groupKey)
return skins.length ? skins.join('、') : '-'
}
function characterAndWeaponSkinText(row: Listing) {
const groups = [
{ label: '红皮', key: 'operatorRed' },
{ label: '金皮', key: 'operatorGold' },
{ label: '武器', key: 'weapon' },
]
const parts = groups
.map((group) => {
const names = getSkinGroup(row, group.key)
return names.length ? `${group.label}${names.join('、')}` : ''
})
.filter(Boolean)
return parts.length ? parts.join(' / ') : '-'
}
function rentAndDepositText(row: Listing) {
return `${listingPrice(row)}/${money(row.deposit_amount)}`
}
function estimateTitle(row: Listing) {
return `按哈夫币 ${listingCoinM(row)}、日耗 ${getDailyLoss(row)} 估算`
}
function formatQuantity(value: number) {
const rounded = Math.round(value * 10) / 10
return Number.isInteger(rounded) ? `${rounded}` : rounded.toFixed(1)
}
</script>
@@ -63,7 +113,7 @@ function reviewType(status: string) {
<div class="page-header">
<p class="eyebrow">Listings</p>
<h1>商品管理</h1>
<p>查看全部租号商品号主区服平台价格押金上架状态和审核状态</p>
<p>查看商品编码地区上号方式账号资产租金押金比例和预计租期</p>
</div>
<div class="toolbar-actions">
<el-button @click="resetFilters">重置</el-button>
@@ -116,47 +166,73 @@ function reviewType(status: string) {
</el-form-item>
</el-form>
<el-table v-loading="loading" class="table-panel" :data="listings">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column label="商品" min-width="220">
<el-table
v-loading="loading"
class="table-panel admin-listings-table"
:data="listings"
row-key="id"
stripe
empty-text="暂无商品"
>
<el-table-column label="商品编码" width="88">
<template #default="{ row }">
<strong>{{ row.title }}</strong>
<span class="table-subtext">账号 ID: {{ row.account_id }}</span>
<strong class="listing-code">{{ formatListingCode(row) }}</strong>
</template>
</el-table-column>
<el-table-column label="号主" min-width="150">
<el-table-column label="地区" width="86">
<template #default="{ row }">{{ regionText(row) }}</template>
</el-table-column>
<el-table-column prop="login_platform" label="上号方式" width="78" />
<el-table-column label="哈夫币(M)" width="82">
<template #default="{ row }">{{ listingCoinM(row) }}</template>
</el-table-column>
<el-table-column label="保险" width="54">
<template #default="{ row }">{{ assetText(row, 'season_insurance') }}</template>
</el-table-column>
<el-table-column label="体力(级)" width="68">
<template #default="{ row }">{{ levelText(row, 'stamina_level') }}</template>
</el-table-column>
<el-table-column label="负重(级)" width="68">
<template #default="{ row }">{{ levelText(row, 'load_level') }}</template>
</el-table-column>
<el-table-column label="账号等级" width="74">
<template #default="{ row }">{{ assetText(row, 'fire_level') }}</template>
</el-table-column>
<el-table-column label="绝密KD" width="66">
<template #default="{ row }">{{ assetText(row, 'secret_kd') }}</template>
</el-table-column>
<el-table-column label="awm子弹" width="72">
<template #default="{ row }">{{ resourceText(row, 'awmAmmo') }}</template>
</el-table-column>
<el-table-column label="六头" width="48">
<template #default="{ row }">{{ resourceText(row, 'helmet6') }}</template>
</el-table-column>
<el-table-column label="六甲" width="48">
<template #default="{ row }">{{ resourceText(row, 'armor6') }}</template>
</el-table-column>
<el-table-column label="特殊刀皮" width="104">
<template #default="{ row }">
<strong>{{ ownerName(row) }}</strong>
<span class="table-subtext">ID: {{ row.owner_id }}</span>
{{ skinGroupText(row, 'melee') }}
</template>
</el-table-column>
<el-table-column prop="server_region" label="区服" width="120" />
<el-table-column prop="login_platform" label="平台" width="120" />
<el-table-column prop="rank_level" label="段位" width="110" />
<el-table-column prop="haf_coin_amount" label="哈夫币" width="110" />
<el-table-column label="价格" width="100">
<template #default="{ row }">{{ listingPrice(row) }}</template>
</el-table-column>
<el-table-column label="押金" width="100">
<template #default="{ row }">{{ money(row.deposit_amount) }}</template>
</el-table-column>
<el-table-column label="商品状态" width="110">
<el-table-column label="人物红皮/人物金皮/武器皮肤" min-width="226">
<template #default="{ row }">
<el-tag :type="statusType(row.status)">{{ listingStatusLabel(row.status) }}</el-tag>
{{ characterAndWeaponSkinText(row) }}
</template>
</el-table-column>
<el-table-column label="审核状态" width="110">
<el-table-column label="租金/押金" width="90">
<template #default="{ row }">{{ rentAndDepositText(row) }}</template>
</el-table-column>
<el-table-column label="比例" width="62">
<template #default="{ row }">{{ formatRatio(row) }}</template>
</el-table-column>
<el-table-column label="租期" width="82">
<template #default="{ row }">
<el-tag :type="reviewType(row.review_status)">{{ listingReviewStatusLabel(row.review_status) }}</el-tag>
<span :title="estimateTitle(row)">{{ formatEstimatedRentalDuration(row) }}</span>
<span class="table-subtext">日耗 {{ getDailyLoss(row) }}</span>
</template>
</el-table-column>
<el-table-column label="上架时间" min-width="180">
<template #default="{ row }">{{ formatDateTime(row.published_at) }}</template>
</el-table-column>
<el-table-column label="更新时间" min-width="180">
<template #default="{ row }">{{ formatDateTime(row.updated_at) }}</template>
</el-table-column>
<el-table-column label="操作" width="110">
<el-table-column label="详情" width="60">
<template #default="{ row }">
<RouterLink :to="`/admin/listings/${row.id}`">
<el-button size="small">详情</el-button>
@@ -38,7 +38,6 @@ const {
calculatedCoinBasePrice,
calculatedConsumablePrice,
calculatedSellerPrice,
calculatedFinalPrice,
calculatedRatioText,
calculatedDefaultSaleRatioText,
saleRatioRangeText,
@@ -553,15 +552,9 @@ function selectRadio<T extends string>(value: T, setter: (value: T) => void) {
:placeholder="priceConfig.price_placeholder"
class="publish-field result-field total-price-field"
/>
<van-field
:model-value="calculatedFinalPrice ? `¥${calculatedFinalPrice}` : ''"
label="首页展示价"
readonly
class="publish-field result-field"
/>
</div>
<p class="price-breakdown-hint">
卖家价格 = 纯币基础价 + 额外消耗品首页展示价为平台加价后的买家价格
卖家价格 = 纯币基础价 + 额外消耗品
</p>
<van-field
+4 -4
View File
@@ -814,7 +814,7 @@ function resetSkinFilter() {
display: grid;
gap: 20px;
width: 100%;
max-width: 1280px;
max-width: 1720px;
min-width: 0;
margin: 0 auto;
overflow-x: clip;
@@ -854,7 +854,7 @@ function resetSkinFilter() {
.hero-section {
display: grid;
grid-template-columns: minmax(0, 1fr) 280px;
grid-template-columns: minmax(0, 1fr) 320px;
gap: 20px;
min-width: 0;
}
@@ -1595,8 +1595,8 @@ function resetSkinFilter() {
.listing-card-v2 {
display: grid;
grid-template-columns: 200px 1fr 180px;
gap: 24px;
grid-template-columns: 240px 1fr 200px;
gap: 30px;
padding: 20px;
text-decoration: none;
color: inherit;
@@ -41,14 +41,12 @@ const {
calculatedCoinBasePrice,
calculatedConsumablePrice,
calculatedSellerPrice,
calculatedFinalPrice,
calculatedRatioText,
calculatedDefaultSaleRatioText,
saleRatioRangeText,
acceleratedSaleRatioPlaceholder,
recommendedDepositAmount,
depositBreakdownItems,
platformRuleLabel,
publishTitle,
hasAcceleratedSaleRatioInput,
isQuantityItemDisabled,
@@ -440,10 +438,6 @@ function selectDailyLoss(value: string | number) {
<span>发布价格</span>
<strong>{{ calculatedSellerPrice ? `¥${calculatedSellerPrice}` : '--' }}</strong>
</div>
<div class="price-cell">
<span>首页展示价</span>
<strong>{{ calculatedFinalPrice ? `¥${calculatedFinalPrice}` : '--' }}</strong>
</div>
</div>
<label class="input-block remark">
@@ -465,10 +459,6 @@ function selectDailyLoss(value: string | number) {
<strong>{{ calculatedSellerPrice ? `¥${calculatedSellerPrice}` : '--' }}</strong>
</div>
<div class="summary-list">
<div>
<span>首页展示价</span>
<strong>{{ calculatedFinalPrice ? `¥${calculatedFinalPrice}` : '--' }}</strong>
</div>
<div>
<span>哈夫币</span>
<strong>{{ coinMAmount || '--' }}M</strong>