增加前端格式检查配置
This commit is contained in:
@@ -4,7 +4,13 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
|
||||
|
||||
import { fetchAdminFileBlob } from '@/shared/api/files'
|
||||
import { adjustListingReviewPrice, approveListing, fetchPendingReviewListings, rejectListing, type Listing } from '@/features/listings'
|
||||
import {
|
||||
adjustListingReviewPrice,
|
||||
approveListing,
|
||||
fetchPendingReviewListings,
|
||||
rejectListing,
|
||||
type Listing,
|
||||
} from '@/features/listings'
|
||||
import {
|
||||
assetRegions,
|
||||
formatHafCoinM,
|
||||
@@ -26,7 +32,13 @@ interface RiskItem {
|
||||
}
|
||||
|
||||
const defaultScreenshotURL = '/api/listings/default-upload-screenshot'
|
||||
const rejectReasonOptions = ['默认截图,需补充真实截图', '账号资产信息不完整', '价格或押金异常', '封禁记录需补充说明', '联系方式异常']
|
||||
const rejectReasonOptions = [
|
||||
'默认截图,需补充真实截图',
|
||||
'账号资产信息不完整',
|
||||
'价格或押金异常',
|
||||
'封禁记录需补充说明',
|
||||
'联系方式异常',
|
||||
]
|
||||
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
@@ -50,10 +62,12 @@ const filters = reactive({
|
||||
const previewURLs = reactive<Record<string, string>>({})
|
||||
const createdObjectURLs = new Set<string>()
|
||||
|
||||
const selectedListing = computed(() => listings.value.find((item) => item.id === selectedID.value) || listings.value[0] || null)
|
||||
const selectedListing = computed(
|
||||
() => listings.value.find(item => item.id === selectedID.value) || listings.value[0] || null
|
||||
)
|
||||
const filteredListings = computed(() => {
|
||||
const keyword = filters.keyword.trim().toLowerCase()
|
||||
return listings.value.filter((item) => {
|
||||
return listings.value.filter(item => {
|
||||
if (filters.risk === 'external' && !isExternalUpload(item)) return false
|
||||
if (filters.risk === 'defaultImage' && !hasDefaultScreenshot(item)) return false
|
||||
if (filters.risk === 'ban' && !hasBanRecord(item)) return false
|
||||
@@ -62,26 +76,33 @@ const filteredListings = computed(() => {
|
||||
})
|
||||
})
|
||||
const activeRisks = computed(() => (selectedListing.value ? riskItems(selectedListing.value) : []))
|
||||
const selectedResources = computed(() => (selectedListing.value ? getListingResources(selectedListing.value) : []))
|
||||
const selectedSkins = computed(() => (selectedListing.value ? getSkinNames(selectedListing.value) : []))
|
||||
const priceAdjustPreview = computed(() => (priceAdjustListing.value ? calculatePriceAdjustPreview(priceAdjustListing.value) : null))
|
||||
const selectedResources = computed(() =>
|
||||
selectedListing.value ? getListingResources(selectedListing.value) : []
|
||||
)
|
||||
const selectedSkins = computed(() =>
|
||||
selectedListing.value ? getSkinNames(selectedListing.value) : []
|
||||
)
|
||||
const priceAdjustPreview = computed(() =>
|
||||
priceAdjustListing.value ? calculatePriceAdjustPreview(priceAdjustListing.value) : null
|
||||
)
|
||||
|
||||
watch(
|
||||
() => selectedListing.value,
|
||||
async (listing) => {
|
||||
async listing => {
|
||||
if (!listing) return
|
||||
selectedID.value = listing.id
|
||||
await nextTick()
|
||||
loadScreenshotPreviews(listing)
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(priceAdjustMode, (mode, previousMode) => {
|
||||
if (!priceAdjustListing.value || !previousMode || mode === previousMode) return
|
||||
const preview = calculatePriceAdjustPreview(priceAdjustListing.value, previousMode)
|
||||
if (mode === 'price') {
|
||||
priceAdjustForm.buyer_total_price = preview.buyerTotalPrice || buyerTotalPrice(priceAdjustListing.value)
|
||||
priceAdjustForm.buyer_total_price =
|
||||
preview.buyerTotalPrice || buyerTotalPrice(priceAdjustListing.value)
|
||||
} else {
|
||||
priceAdjustForm.buyer_ratio = preview.buyerRatio || buyerRatio(priceAdjustListing.value)
|
||||
}
|
||||
@@ -89,14 +110,14 @@ watch(priceAdjustMode, (mode, previousMode) => {
|
||||
|
||||
onMounted(loadListings)
|
||||
onBeforeUnmount(() => {
|
||||
createdObjectURLs.forEach((url) => URL.revokeObjectURL(url))
|
||||
createdObjectURLs.forEach(url => URL.revokeObjectURL(url))
|
||||
})
|
||||
|
||||
async function loadListings() {
|
||||
loading.value = true
|
||||
try {
|
||||
listings.value = await fetchPendingReviewListings()
|
||||
if (!selectedID.value || !listings.value.some((item) => item.id === selectedID.value)) {
|
||||
if (!selectedID.value || !listings.value.some(item => item.id === selectedID.value)) {
|
||||
selectedID.value = listings.value[0]?.id || null
|
||||
}
|
||||
} finally {
|
||||
@@ -109,7 +130,7 @@ function selectListing(row: Listing) {
|
||||
}
|
||||
|
||||
function replaceListing(next: Listing) {
|
||||
const index = listings.value.findIndex((item) => item.id === next.id)
|
||||
const index = listings.value.findIndex(item => item.id === next.id)
|
||||
if (index >= 0) {
|
||||
listings.value.splice(index, 1, next)
|
||||
} else {
|
||||
@@ -157,8 +178,14 @@ async function handleSavePriceAdjust() {
|
||||
if (!priceAdjustListing.value) return
|
||||
const payload =
|
||||
priceAdjustMode.value === 'ratio'
|
||||
? { buyer_ratio: Number(priceAdjustForm.buyer_ratio || 0), reason: priceAdjustForm.reason.trim() }
|
||||
: { buyer_total_price: Number(priceAdjustForm.buyer_total_price || 0), reason: priceAdjustForm.reason.trim() }
|
||||
? {
|
||||
buyer_ratio: Number(priceAdjustForm.buyer_ratio || 0),
|
||||
reason: priceAdjustForm.reason.trim(),
|
||||
}
|
||||
: {
|
||||
buyer_total_price: Number(priceAdjustForm.buyer_total_price || 0),
|
||||
reason: priceAdjustForm.reason.trim(),
|
||||
}
|
||||
if ((payload.buyer_ratio || payload.buyer_total_price || 0) <= 0) {
|
||||
ElMessage.warning('请填写有效的加价后比例或价格')
|
||||
return
|
||||
@@ -233,7 +260,9 @@ function assetNumberText(row: Listing, key: string) {
|
||||
|
||||
function priceBreakdown(row: Listing) {
|
||||
const breakdown = row.asset_summary?.price_breakdown
|
||||
return typeof breakdown === 'object' && breakdown !== null ? (breakdown as Record<string, unknown>) : {}
|
||||
return typeof breakdown === 'object' && breakdown !== null
|
||||
? (breakdown as Record<string, unknown>)
|
||||
: {}
|
||||
}
|
||||
|
||||
function breakdownNumber(row: Listing, key: string) {
|
||||
@@ -278,7 +307,8 @@ function sellerCoinBasePrice(row: Listing) {
|
||||
}
|
||||
|
||||
function sellerRatio(row: Listing) {
|
||||
const value = breakdownNumber(row, 'seller_ratio') || breakdownNumber(row, 'seller_reference_ratio')
|
||||
const value =
|
||||
breakdownNumber(row, 'seller_ratio') || breakdownNumber(row, 'seller_reference_ratio')
|
||||
if (value > 0) return value
|
||||
const base = sellerCoinBasePrice(row)
|
||||
return base > 0 ? getCoinWan(row) / base : 0
|
||||
@@ -302,7 +332,10 @@ function buyerRatio(row: Listing) {
|
||||
return base > 0 ? getCoinWan(row) / base : 0
|
||||
}
|
||||
|
||||
function calculatePriceAdjustPreview(row: Listing, mode: 'ratio' | 'price' = priceAdjustMode.value) {
|
||||
function calculatePriceAdjustPreview(
|
||||
row: Listing,
|
||||
mode: 'ratio' | 'price' = priceAdjustMode.value
|
||||
) {
|
||||
const consumablePrice = getListingConsumablePrice(row)
|
||||
const coinWan = getCoinWan(row)
|
||||
if (mode === 'price') {
|
||||
@@ -313,7 +346,8 @@ function calculatePriceAdjustPreview(row: Listing, mode: 'ratio' | 'price' = pri
|
||||
}
|
||||
const buyerRatioInput = Number(priceAdjustForm.buyer_ratio || 0)
|
||||
const buyerCoinBasePrice = buyerRatioInput > 0 ? roundPreviewMoney(coinWan / buyerRatioInput) : 0
|
||||
const buyerTotalPrice = buyerCoinBasePrice > 0 ? roundPreviewMoney(buyerCoinBasePrice + consumablePrice) : 0
|
||||
const buyerTotalPrice =
|
||||
buyerCoinBasePrice > 0 ? roundPreviewMoney(buyerCoinBasePrice + consumablePrice) : 0
|
||||
const buyerRatio = buyerCoinBasePrice > 0 ? roundPreviewRatio(coinWan / buyerCoinBasePrice) : 0
|
||||
return { buyerCoinBasePrice, buyerTotalPrice, buyerRatio }
|
||||
}
|
||||
@@ -412,7 +446,7 @@ function isExternalUpload(row: Listing) {
|
||||
}
|
||||
|
||||
function hasDefaultScreenshot(row: Listing) {
|
||||
return row.screenshot_urls?.some((url) => isDefaultScreenshot(url)) || false
|
||||
return row.screenshot_urls?.some(url => isDefaultScreenshot(url)) || false
|
||||
}
|
||||
|
||||
function isDefaultScreenshot(url: string) {
|
||||
@@ -425,12 +459,18 @@ function riskItems(row: Listing): RiskItem[] {
|
||||
if (!row.screenshot_urls?.length) items.push({ label: '没有账号截图', level: 'danger' })
|
||||
if (hasDefaultScreenshot(row)) items.push({ label: '使用默认截图', level: 'warning' })
|
||||
if (hasBanRecord(row)) items.push({ label: `封禁记录:${banRecordText(row)}`, level: 'danger' })
|
||||
if (getListingConsumablePrice(row) > 0 && Number(row.deposit_amount || 0) <= getListingConsumablePrice(row)) {
|
||||
if (
|
||||
getListingConsumablePrice(row) > 0 &&
|
||||
Number(row.deposit_amount || 0) <= getListingConsumablePrice(row)
|
||||
) {
|
||||
items.push({ label: '押金不高于消耗品价值', level: 'danger' })
|
||||
}
|
||||
if (readAssetNumber(row, 'daily_loss_m') <= 0) items.push({ label: '缺少每日损耗', level: 'warning' })
|
||||
if (readAssetNumber(row, 'fire_level') <= 40) items.push({ label: '烽火等级接近下限', level: 'warning' })
|
||||
if (!readAssetString(row, 'season_insurance')) items.push({ label: '缺少保险格数', level: 'warning' })
|
||||
if (readAssetNumber(row, 'daily_loss_m') <= 0)
|
||||
items.push({ label: '缺少每日损耗', level: 'warning' })
|
||||
if (readAssetNumber(row, 'fire_level') <= 40)
|
||||
items.push({ label: '烽火等级接近下限', level: 'warning' })
|
||||
if (!readAssetString(row, 'season_insurance'))
|
||||
items.push({ label: '缺少保险格数', level: 'warning' })
|
||||
if (!items.length) items.push({ label: '未发现明显风险', level: 'info' })
|
||||
return items
|
||||
}
|
||||
@@ -525,19 +565,35 @@ function readError(error: unknown, fallback: string) {
|
||||
</div>
|
||||
|
||||
<div class="review-summary">
|
||||
<button class="summary-card" :class="{ active: filters.risk === 'all' }" @click="filters.risk = 'all'">
|
||||
<button
|
||||
class="summary-card"
|
||||
:class="{ active: filters.risk === 'all' }"
|
||||
@click="filters.risk = 'all'"
|
||||
>
|
||||
<span>待审核</span>
|
||||
<strong>{{ listings.length }}</strong>
|
||||
</button>
|
||||
<button class="summary-card" :class="{ active: filters.risk === 'external' }" @click="filters.risk = 'external'">
|
||||
<button
|
||||
class="summary-card"
|
||||
:class="{ active: filters.risk === 'external' }"
|
||||
@click="filters.risk = 'external'"
|
||||
>
|
||||
<span>外部上传</span>
|
||||
<strong>{{ listings.filter(isExternalUpload).length }}</strong>
|
||||
</button>
|
||||
<button class="summary-card" :class="{ active: filters.risk === 'defaultImage' }" @click="filters.risk = 'defaultImage'">
|
||||
<button
|
||||
class="summary-card"
|
||||
:class="{ active: filters.risk === 'defaultImage' }"
|
||||
@click="filters.risk = 'defaultImage'"
|
||||
>
|
||||
<span>默认截图</span>
|
||||
<strong>{{ listings.filter(hasDefaultScreenshot).length }}</strong>
|
||||
</button>
|
||||
<button class="summary-card" :class="{ active: filters.risk === 'ban' }" @click="filters.risk = 'ban'">
|
||||
<button
|
||||
class="summary-card"
|
||||
:class="{ active: filters.risk === 'ban' }"
|
||||
@click="filters.risk = 'ban'"
|
||||
>
|
||||
<span>封禁风险</span>
|
||||
<strong>{{ listings.filter(hasBanRecord).length }}</strong>
|
||||
</button>
|
||||
@@ -546,7 +602,12 @@ function readError(error: unknown, fallback: string) {
|
||||
<div class="review-workbench">
|
||||
<aside class="review-queue">
|
||||
<div class="queue-toolbar">
|
||||
<el-input v-model="filters.keyword" :prefix-icon="Search" clearable placeholder="搜索标题、客服、段位、皮肤" />
|
||||
<el-input
|
||||
v-model="filters.keyword"
|
||||
:prefix-icon="Search"
|
||||
clearable
|
||||
placeholder="搜索标题、客服、段位、皮肤"
|
||||
/>
|
||||
<el-select v-model="filters.risk" placeholder="风险筛选">
|
||||
<el-option label="全部待审" value="all" />
|
||||
<el-option label="外部上传" value="external" />
|
||||
@@ -571,16 +632,23 @@ function readError(error: unknown, fallback: string) {
|
||||
<div class="queue-meta">
|
||||
<span>{{ item.rank_level || '-' }}</span>
|
||||
<span>{{ assetText(item, 'season_insurance') }}</span>
|
||||
<span>{{ assetText(item, 'stamina_level') }}/{{ assetText(item, 'load_level') }}</span>
|
||||
<span
|
||||
>{{ assetText(item, 'stamina_level') }}/{{ assetText(item, 'load_level') }}</span
|
||||
>
|
||||
<span>KD {{ assetNumberText(item, 'secret_kd') }}</span>
|
||||
</div>
|
||||
<div class="queue-footer">
|
||||
<span>{{ money(item.price) }} / 押 {{ money(item.deposit_amount) }}</span>
|
||||
<el-tag v-if="isExternalUpload(item)" size="small" type="info">{{ uploaderName(item) }}</el-tag>
|
||||
<el-tag v-if="isExternalUpload(item)" size="small" type="info">{{
|
||||
uploaderName(item)
|
||||
}}</el-tag>
|
||||
<el-tag v-if="hasDefaultScreenshot(item)" size="small" type="warning">默认图</el-tag>
|
||||
</div>
|
||||
</button>
|
||||
<el-empty v-if="!loading && !filteredListings.length" description="暂无符合条件的待审核商品" />
|
||||
<el-empty
|
||||
v-if="!loading && !filteredListings.length"
|
||||
description="暂无符合条件的待审核商品"
|
||||
/>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -595,12 +663,29 @@ function readError(error: unknown, fallback: string) {
|
||||
<RouterLink :to="`/admin/listings/${selectedListing.id}`">
|
||||
<el-button>详情页</el-button>
|
||||
</RouterLink>
|
||||
<el-button :icon="Close" type="danger" :loading="submitting" @click="openReject(selectedListing)">拒绝</el-button>
|
||||
<el-button :icon="Check" type="primary" :loading="submitting" @click="handleApprove(selectedListing)">通过</el-button>
|
||||
<el-button
|
||||
:icon="Close"
|
||||
type="danger"
|
||||
:loading="submitting"
|
||||
@click="openReject(selectedListing)"
|
||||
>拒绝</el-button
|
||||
>
|
||||
<el-button
|
||||
:icon="Check"
|
||||
type="primary"
|
||||
:loading="submitting"
|
||||
@click="handleApprove(selectedListing)"
|
||||
>通过</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="risk-strip">
|
||||
<el-tag v-for="risk in activeRisks" :key="risk.label" :type="riskTagType(risk.level)" effect="light">
|
||||
<el-tag
|
||||
v-for="risk in activeRisks"
|
||||
:key="risk.label"
|
||||
:type="riskTagType(risk.level)"
|
||||
effect="light"
|
||||
>
|
||||
{{ risk.label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
@@ -612,14 +697,19 @@ function readError(error: unknown, fallback: string) {
|
||||
<h3>价格审核</h3>
|
||||
<p>核对卖家提交价格、平台加价规则和最终买家展示价。</p>
|
||||
</div>
|
||||
<el-button type="primary" plain @click="openPriceAdjust(selectedListing)">调整价格</el-button>
|
||||
<el-button type="primary" plain @click="openPriceAdjust(selectedListing)"
|
||||
>调整价格</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="price-decision-grid">
|
||||
<div class="price-decision-card seller">
|
||||
<span>卖家发布</span>
|
||||
<strong>{{ money(sellerTotalPrice(selectedListing)) }}</strong>
|
||||
<p>发布比例 {{ ratioText(sellerRatio(selectedListing)) }}</p>
|
||||
<small>纯币 {{ money(sellerCoinBasePrice(selectedListing)) }} / 物品 {{ money(getListingConsumablePrice(selectedListing)) }}</small>
|
||||
<small
|
||||
>纯币 {{ money(sellerCoinBasePrice(selectedListing)) }} / 物品
|
||||
{{ money(getListingConsumablePrice(selectedListing)) }}</small
|
||||
>
|
||||
</div>
|
||||
<div class="price-decision-card rule">
|
||||
<span>当前加价规则</span>
|
||||
@@ -648,29 +738,82 @@ function readError(error: unknown, fallback: string) {
|
||||
<h3>账号属性</h3>
|
||||
</div>
|
||||
<dl class="detail-list">
|
||||
<div><dt>上号方式</dt><dd>{{ selectedListing.login_platform || '-' }}</dd></div>
|
||||
<div><dt>区服</dt><dd>{{ selectedListing.server_region || '-' }}</dd></div>
|
||||
<div><dt>段位</dt><dd>{{ selectedListing.rank_level || '-' }}</dd></div>
|
||||
<div><dt>烽火等级</dt><dd>{{ assetNumberText(selectedListing, 'fire_level') }}</dd></div>
|
||||
<div><dt>保险格数</dt><dd>{{ assetText(selectedListing, 'season_insurance') }}</dd></div>
|
||||
<div><dt>绝密KD</dt><dd>{{ assetNumberText(selectedListing, 'secret_kd') }}</dd></div>
|
||||
<div><dt>体力/负重</dt><dd>{{ assetText(selectedListing, 'stamina_level') }} / {{ assetText(selectedListing, 'load_level') }}</dd></div>
|
||||
<div><dt>封禁记录</dt><dd>{{ banRecordText(selectedListing) }}</dd></div>
|
||||
<div>
|
||||
<dt>上号方式</dt>
|
||||
<dd>{{ selectedListing.login_platform || '-' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>区服</dt>
|
||||
<dd>{{ selectedListing.server_region || '-' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>段位</dt>
|
||||
<dd>{{ selectedListing.rank_level || '-' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>烽火等级</dt>
|
||||
<dd>{{ assetNumberText(selectedListing, 'fire_level') }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>保险格数</dt>
|
||||
<dd>{{ assetText(selectedListing, 'season_insurance') }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>绝密KD</dt>
|
||||
<dd>{{ assetNumberText(selectedListing, 'secret_kd') }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>体力/负重</dt>
|
||||
<dd>
|
||||
{{ assetText(selectedListing, 'stamina_level') }} /
|
||||
{{ assetText(selectedListing, 'load_level') }}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>封禁记录</dt>
|
||||
<dd>{{ banRecordText(selectedListing) }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="review-panel">
|
||||
<div class="panel-title">
|
||||
<h3>上传信息</h3>
|
||||
<el-tag v-if="isExternalUpload(selectedListing)" size="small" type="info">外部上传</el-tag>
|
||||
<el-tag v-if="isExternalUpload(selectedListing)" size="small" type="info"
|
||||
>外部上传</el-tag
|
||||
>
|
||||
</div>
|
||||
<dl class="detail-list">
|
||||
<div><dt>上传人</dt><dd>{{ uploaderName(selectedListing) }}</dd></div>
|
||||
<div><dt>号主</dt><dd>{{ selectedListing.owner_phone || selectedListing.owner_nickname || selectedListing.owner_id }}</dd></div>
|
||||
<div><dt>联系电话</dt><dd>{{ contactPhone(selectedListing) }}</dd></div>
|
||||
<div><dt>常用地区</dt><dd>{{ commonRegionText(selectedListing) }}</dd></div>
|
||||
<div><dt>在线时间</dt><dd>{{ ownerOnlineText(selectedListing) }}</dd></div>
|
||||
<div><dt>提交时间</dt><dd>{{ formatDateTime(selectedListing.updated_at) }}</dd></div>
|
||||
<div>
|
||||
<dt>上传人</dt>
|
||||
<dd>{{ uploaderName(selectedListing) }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>号主</dt>
|
||||
<dd>
|
||||
{{
|
||||
selectedListing.owner_phone ||
|
||||
selectedListing.owner_nickname ||
|
||||
selectedListing.owner_id
|
||||
}}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>联系电话</dt>
|
||||
<dd>{{ contactPhone(selectedListing) }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>常用地区</dt>
|
||||
<dd>{{ commonRegionText(selectedListing) }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>在线时间</dt>
|
||||
<dd>{{ ownerOnlineText(selectedListing) }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>提交时间</dt>
|
||||
<dd>{{ formatDateTime(selectedListing.updated_at) }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</section>
|
||||
@@ -681,9 +824,16 @@ function readError(error: unknown, fallback: string) {
|
||||
<span>额外消耗品约 {{ money(getListingConsumablePrice(selectedListing)) }}</span>
|
||||
</div>
|
||||
<div class="inventory-grid">
|
||||
<div><span>AWM子弹</span><strong>{{ getResourceQuantity(selectedListing, 'awmAmmo') }}</strong></div>
|
||||
<div><span>6头</span><strong>{{ getResourceQuantity(selectedListing, 'helmet6') }}</strong></div>
|
||||
<div><span>6甲</span><strong>{{ getResourceQuantity(selectedListing, 'armor6') }}</strong></div>
|
||||
<div>
|
||||
<span>AWM子弹</span
|
||||
><strong>{{ getResourceQuantity(selectedListing, 'awmAmmo') }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>6头</span><strong>{{ getResourceQuantity(selectedListing, 'helmet6') }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>6甲</span><strong>{{ getResourceQuantity(selectedListing, 'armor6') }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedResources.length" class="resource-table">
|
||||
<div v-for="resource in selectedResources" :key="resource.key">
|
||||
@@ -693,7 +843,9 @@ function readError(error: unknown, fallback: string) {
|
||||
</div>
|
||||
</div>
|
||||
<div class="skin-list">
|
||||
<el-tag v-for="skin in selectedSkins" :key="skin" type="success" effect="plain">{{ skin }}</el-tag>
|
||||
<el-tag v-for="skin in selectedSkins" :key="skin" type="success" effect="plain">{{
|
||||
skin
|
||||
}}</el-tag>
|
||||
<span v-if="!selectedSkins.length">暂无皮肤数据</span>
|
||||
</div>
|
||||
</section>
|
||||
@@ -701,10 +853,18 @@ function readError(error: unknown, fallback: string) {
|
||||
<section class="review-panel">
|
||||
<div class="panel-title">
|
||||
<h3>账号截图</h3>
|
||||
<el-button :icon="Picture" size="small" @click="openEvidence(selectedListing)">查看全部</el-button>
|
||||
<el-button :icon="Picture" size="small" @click="openEvidence(selectedListing)"
|
||||
>查看全部</el-button
|
||||
>
|
||||
</div>
|
||||
<div v-if="selectedListing.screenshot_urls?.length" class="screenshot-grid">
|
||||
<button v-for="url in selectedListing.screenshot_urls" :key="url" type="button" class="screenshot-tile" @click="openScreenshot(url)">
|
||||
<button
|
||||
v-for="url in selectedListing.screenshot_urls"
|
||||
:key="url"
|
||||
type="button"
|
||||
class="screenshot-tile"
|
||||
@click="openScreenshot(url)"
|
||||
>
|
||||
<img :src="previewURLs[url] || url" alt="账号截图" />
|
||||
<span v-if="isDefaultScreenshot(url)">默认图片</span>
|
||||
</button>
|
||||
@@ -721,15 +881,32 @@ function readError(error: unknown, fallback: string) {
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<el-dialog :model-value="!!activeListing" title="拒绝发布" width="620px" @update:model-value="activeListing = null">
|
||||
<el-dialog
|
||||
:model-value="!!activeListing"
|
||||
title="拒绝发布"
|
||||
width="620px"
|
||||
@update:model-value="activeListing = null"
|
||||
>
|
||||
<div v-if="activeListing" class="dialog-body reject-dialog">
|
||||
<p><strong>{{ activeListing.title }}</strong></p>
|
||||
<p>
|
||||
<strong>{{ activeListing.title }}</strong>
|
||||
</p>
|
||||
<div class="reject-reasons">
|
||||
<el-button v-for="reason in rejectReasonOptions" :key="reason" size="small" @click="appendRejectReason(reason)">
|
||||
<el-button
|
||||
v-for="reason in rejectReasonOptions"
|
||||
:key="reason"
|
||||
size="small"
|
||||
@click="appendRejectReason(reason)"
|
||||
>
|
||||
{{ reason }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-input v-model="rejectReason" type="textarea" :rows="5" placeholder="填写拒绝原因,号主会在通知中看到审核结果" />
|
||||
<el-input
|
||||
v-model="rejectReason"
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
placeholder="填写拒绝原因,号主会在通知中看到审核结果"
|
||||
/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="activeListing = null">取消</el-button>
|
||||
@@ -737,7 +914,12 @@ function readError(error: unknown, fallback: string) {
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog :model-value="!!priceAdjustListing" title="调整审核价格" width="560px" @update:model-value="priceAdjustListing = null">
|
||||
<el-dialog
|
||||
:model-value="!!priceAdjustListing"
|
||||
title="调整审核价格"
|
||||
width="560px"
|
||||
@update:model-value="priceAdjustListing = null"
|
||||
>
|
||||
<div v-if="priceAdjustListing" class="dialog-body price-adjust-dialog">
|
||||
<div class="adjust-current">
|
||||
<div>
|
||||
@@ -746,11 +928,15 @@ function readError(error: unknown, fallback: string) {
|
||||
</div>
|
||||
<div>
|
||||
<span>调整后买家价</span>
|
||||
<strong class="preview-value">{{ previewMoney(priceAdjustPreview?.buyerTotalPrice || 0) }}</strong>
|
||||
<strong class="preview-value">{{
|
||||
previewMoney(priceAdjustPreview?.buyerTotalPrice || 0)
|
||||
}}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>调整后买家比例</span>
|
||||
<strong class="preview-value">{{ ratioText(priceAdjustPreview?.buyerRatio || 0) }}</strong>
|
||||
<strong class="preview-value">{{
|
||||
ratioText(priceAdjustPreview?.buyerRatio || 0)
|
||||
}}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<el-radio-group v-model="priceAdjustMode" class="adjust-mode">
|
||||
@@ -759,28 +945,61 @@ function readError(error: unknown, fallback: string) {
|
||||
</el-radio-group>
|
||||
<label v-if="priceAdjustMode === 'ratio'" class="adjust-field">
|
||||
<span>加价后比例</span>
|
||||
<el-input-number v-model="priceAdjustForm.buyer_ratio" :min="0" :step="0.1" :controls="false" />
|
||||
<el-input-number
|
||||
v-model="priceAdjustForm.buyer_ratio"
|
||||
:min="0"
|
||||
:step="0.1"
|
||||
:controls="false"
|
||||
/>
|
||||
</label>
|
||||
<label v-else class="adjust-field">
|
||||
<span>加价后价格</span>
|
||||
<el-input-number v-model="priceAdjustForm.buyer_total_price" :min="0" :step="1" :controls="false" />
|
||||
<el-input-number
|
||||
v-model="priceAdjustForm.buyer_total_price"
|
||||
:min="0"
|
||||
:step="1"
|
||||
:controls="false"
|
||||
/>
|
||||
</label>
|
||||
<label class="adjust-field">
|
||||
<span>调价原因</span>
|
||||
<el-input v-model="priceAdjustForm.reason" type="textarea" :rows="3" placeholder="可填写调价原因,便于审计追踪" />
|
||||
<el-input
|
||||
v-model="priceAdjustForm.reason"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="可填写调价原因,便于审计追踪"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="priceAdjustListing = null">取消</el-button>
|
||||
<el-button type="primary" :loading="adjustingPrice" @click="handleSavePriceAdjust">保存调整</el-button>
|
||||
<el-button type="primary" :loading="adjustingPrice" @click="handleSavePriceAdjust"
|
||||
>保存调整</el-button
|
||||
>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog :model-value="!!evidenceListing" title="账号资产截图" width="860px" @update:model-value="evidenceListing = null">
|
||||
<el-dialog
|
||||
:model-value="!!evidenceListing"
|
||||
title="账号资产截图"
|
||||
width="860px"
|
||||
@update:model-value="evidenceListing = null"
|
||||
>
|
||||
<div v-if="evidenceListing" class="dialog-body">
|
||||
<p><strong>{{ evidenceListing.title }}</strong></p>
|
||||
<div v-if="evidenceListing.screenshot_urls?.length" class="screenshot-grid dialog-screenshots">
|
||||
<button v-for="url in evidenceListing.screenshot_urls" :key="url" type="button" class="screenshot-tile" @click="openScreenshot(url)">
|
||||
<p>
|
||||
<strong>{{ evidenceListing.title }}</strong>
|
||||
</p>
|
||||
<div
|
||||
v-if="evidenceListing.screenshot_urls?.length"
|
||||
class="screenshot-grid dialog-screenshots"
|
||||
>
|
||||
<button
|
||||
v-for="url in evidenceListing.screenshot_urls"
|
||||
:key="url"
|
||||
type="button"
|
||||
class="screenshot-tile"
|
||||
@click="openScreenshot(url)"
|
||||
>
|
||||
<img :src="previewURLs[url] || url" alt="账号截图" />
|
||||
<span v-if="isDefaultScreenshot(url)">默认图片</span>
|
||||
</button>
|
||||
@@ -911,7 +1130,10 @@ function readError(error: unknown, fallback: string) {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s,
|
||||
background 0.2s;
|
||||
}
|
||||
|
||||
.queue-item:hover,
|
||||
|
||||
Reference in New Issue
Block a user