优化pc页面ui大小和商品管理的表格项目
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ function handleKeydown(e: KeyboardEvent) {
|
||||
|
||||
<style scoped>
|
||||
.chat-page {
|
||||
max-width: 900px;
|
||||
max-width: 1720px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user