贯通商品编号全流程
This commit is contained in:
@@ -6,6 +6,7 @@ import { arbitrateDispute, fetchAdminDisputes, type Dispute } from '@/features/d
|
||||
import { fetchAdminFileBlob } from '@/shared/api/files'
|
||||
import { disputeStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import { formatListingNo } from '@/utils/listingDisplay'
|
||||
import AdminTablePagination from '../components/AdminTablePagination.vue'
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -114,6 +115,9 @@ function readError(error: unknown, fallback: string) {
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" class="table-panel" :data="disputes">
|
||||
<el-table-column label="商品编号" width="140">
|
||||
<template #default="{ row }">{{ formatListingNo(row.listing_no) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="order_no" label="订单号" min-width="210" />
|
||||
<el-table-column prop="title" label="账号" min-width="160" />
|
||||
<el-table-column prop="type" label="类型" width="150" />
|
||||
@@ -164,7 +168,8 @@ function readError(error: unknown, fallback: string) {
|
||||
>
|
||||
<div v-if="activeDispute" class="dialog-body">
|
||||
<p>
|
||||
<strong>{{ activeDispute.order_no }}</strong> · {{ activeDispute.title }}
|
||||
<strong>{{ activeDispute.order_no }}</strong> · 商品编号
|
||||
{{ formatListingNo(activeDispute.listing_no) }} · {{ activeDispute.title }}
|
||||
</p>
|
||||
<p>{{ activeDispute.description }}</p>
|
||||
<el-select v-model="result" class="full-control" placeholder="选择裁决结果">
|
||||
@@ -215,7 +220,8 @@ function readError(error: unknown, fallback: string) {
|
||||
>
|
||||
<div v-if="evidenceDispute" class="dialog-body">
|
||||
<p>
|
||||
<strong>{{ evidenceDispute.order_no }}</strong> · {{ evidenceDispute.title }}
|
||||
<strong>{{ evidenceDispute.order_no }}</strong> · 商品编号
|
||||
{{ formatListingNo(evidenceDispute.listing_no) }} · {{ evidenceDispute.title }}
|
||||
</p>
|
||||
<div v-for="item in evidenceItems(evidenceDispute)" :key="item" class="evidence-row">
|
||||
<span>{{ item }}</span>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { CopyDocument } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
@@ -12,6 +13,7 @@ import {
|
||||
} from '@/features/listings'
|
||||
import { listingReviewStatusLabel, listingStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import { formatListingCode } from '@/utils/listingDisplay'
|
||||
|
||||
const route = useRoute()
|
||||
const loading = ref(false)
|
||||
@@ -41,6 +43,16 @@ async function loadListing() {
|
||||
}
|
||||
}
|
||||
|
||||
async function copyListingCode() {
|
||||
if (!listing.value) return
|
||||
try {
|
||||
await navigator.clipboard.writeText(formatListingCode(listing.value))
|
||||
ElMessage.success('商品编号已复制')
|
||||
} catch {
|
||||
ElMessage.error('复制失败')
|
||||
}
|
||||
}
|
||||
|
||||
function openAction(type: 'offline' | 'abnormal') {
|
||||
actionType.value = type
|
||||
reason.value = ''
|
||||
@@ -104,11 +116,12 @@ function readError(error: unknown, fallback: string) {
|
||||
<section class="page" v-loading="loading">
|
||||
<div v-if="listing" class="page-header-row">
|
||||
<div class="page-header">
|
||||
<p class="eyebrow">Listing #{{ listing.id }}</p>
|
||||
<p class="eyebrow">商品编号:{{ formatListingCode(listing) }}</p>
|
||||
<h1>商品详情</h1>
|
||||
<p>{{ listing.title }} · {{ listing.server_region }} / {{ listing.login_platform }}</p>
|
||||
</div>
|
||||
<div class="toolbar-actions">
|
||||
<el-button :icon="CopyDocument" @click="copyListingCode">复制编号</el-button>
|
||||
<RouterLink to="/admin/listings">
|
||||
<el-button>返回列表</el-button>
|
||||
</RouterLink>
|
||||
@@ -143,6 +156,7 @@ function readError(error: unknown, fallback: string) {
|
||||
<div v-if="listing" class="dashboard-panels">
|
||||
<div class="order-panel dashboard-panel">
|
||||
<h2>账号信息</h2>
|
||||
<p>商品编号:{{ formatListingCode(listing) }}</p>
|
||||
<p>账号 ID:{{ listing.account_id }}</p>
|
||||
<p>游戏:{{ listing.game_name }}</p>
|
||||
<p>区服:{{ listing.server_region }}</p>
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from '@/features/listings'
|
||||
import {
|
||||
assetRegions,
|
||||
formatListingCode,
|
||||
formatHafCoinM,
|
||||
getCoinWan,
|
||||
getListingConsumablePrice,
|
||||
@@ -483,6 +484,9 @@ function riskTagType(level: RiskLevel) {
|
||||
|
||||
function reviewSearchText(row: Listing) {
|
||||
return [
|
||||
row.listing_no,
|
||||
row.id,
|
||||
row.account_id,
|
||||
row.title,
|
||||
row.owner_phone,
|
||||
row.owner_nickname,
|
||||
@@ -606,7 +610,7 @@ function readError(error: unknown, fallback: string) {
|
||||
v-model="filters.keyword"
|
||||
:prefix-icon="Search"
|
||||
clearable
|
||||
placeholder="搜索标题、客服、段位、皮肤"
|
||||
placeholder="搜索编号、标题、客服、段位、皮肤"
|
||||
/>
|
||||
<el-select v-model="filters.risk" placeholder="风险筛选">
|
||||
<el-option label="全部待审" value="all" />
|
||||
@@ -626,7 +630,10 @@ function readError(error: unknown, fallback: string) {
|
||||
@click="selectListing(item)"
|
||||
>
|
||||
<div class="queue-title-row">
|
||||
<strong>{{ item.title }}</strong>
|
||||
<div>
|
||||
<span class="queue-code">编号 {{ formatListingCode(item) }}</span>
|
||||
<strong>{{ item.title }}</strong>
|
||||
</div>
|
||||
<span>{{ formatHafCoinM(getCoinWan(item)) }}</span>
|
||||
</div>
|
||||
<div class="queue-meta">
|
||||
@@ -656,7 +663,7 @@ function readError(error: unknown, fallback: string) {
|
||||
<section class="review-hero-panel">
|
||||
<div class="hero-title">
|
||||
<div>
|
||||
<p>商品 #{{ selectedListing.id }}</p>
|
||||
<p>商品编号 {{ formatListingCode(selectedListing) }}</p>
|
||||
<h2>{{ selectedListing.title }}</h2>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
@@ -1154,6 +1161,7 @@ function readError(error: unknown, fallback: string) {
|
||||
}
|
||||
|
||||
.queue-title-row strong {
|
||||
display: block;
|
||||
min-width: 0;
|
||||
color: #1b2559;
|
||||
font-size: 14px;
|
||||
@@ -1167,6 +1175,15 @@ function readError(error: unknown, fallback: string) {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.queue-title-row .queue-code {
|
||||
display: inline-flex;
|
||||
margin-bottom: 4px;
|
||||
padding: 2px 7px;
|
||||
border-radius: 999px;
|
||||
background: #eff6ff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.queue-meta,
|
||||
.risk-strip,
|
||||
.skin-list,
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from '@/features/orders'
|
||||
import { handoffStatusLabel, orderStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import { formatListingNo } from '@/utils/listingDisplay'
|
||||
|
||||
const route = useRoute()
|
||||
const loading = ref(false)
|
||||
@@ -25,6 +26,9 @@ const handoffRecords = ref<HandoffRecord[]>([])
|
||||
const actionType = ref<'close' | 'abnormal' | ''>('')
|
||||
const reason = ref('')
|
||||
const refundStatus = ref<RefundStatus | null>(null)
|
||||
const listingCode = computed(() =>
|
||||
order.value ? formatListingNo(order.value.listing_no, order.value.listing_id) : '-'
|
||||
)
|
||||
const refunding = ref(false)
|
||||
|
||||
const snapshotText = computed(() => JSON.stringify(order.value?.account_snapshot || {}, null, 2))
|
||||
@@ -144,7 +148,10 @@ function formatHandoffRecordType(type: string) {
|
||||
<div class="page-header">
|
||||
<p class="eyebrow">{{ order.order_no }}</p>
|
||||
<h1>订单详情</h1>
|
||||
<p>{{ order.title }} · {{ order.server_region }} / {{ order.login_platform }}</p>
|
||||
<p>
|
||||
商品编号 {{ listingCode }} · {{ order.title }} · {{ order.server_region }} /
|
||||
{{ order.login_platform }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="toolbar-actions">
|
||||
<RouterLink to="/admin/orders">
|
||||
@@ -200,6 +207,7 @@ function formatHandoffRecordType(type: string) {
|
||||
<div v-if="order" class="dashboard-panels">
|
||||
<div class="order-panel dashboard-panel">
|
||||
<h2>用户信息</h2>
|
||||
<p>商品编号:{{ listingCode }}</p>
|
||||
<p>租客:{{ order.renter_phone || order.renter_id }}</p>
|
||||
<p>号主:{{ order.owner_phone || order.owner_id }}</p>
|
||||
<p>开始:{{ formatDateTime(orderRentedAt(), '未开始') }}</p>
|
||||
@@ -230,7 +238,7 @@ function formatHandoffRecordType(type: string) {
|
||||
>
|
||||
<div v-if="order" class="dialog-body">
|
||||
<p>
|
||||
<strong>{{ order.order_no }}</strong> · {{ order.title }}
|
||||
<strong>{{ order.order_no }}</strong> · 商品编号 {{ listingCode }} · {{ order.title }}
|
||||
</p>
|
||||
<el-input
|
||||
v-model="reason"
|
||||
|
||||
@@ -4,6 +4,7 @@ import { computed, onMounted, ref } from 'vue'
|
||||
import { fetchAdminOrders, type Order } from '@/features/orders'
|
||||
import { handoffStatusLabel, orderStatusLabel, settlementStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import { formatListingNo } from '@/utils/listingDisplay'
|
||||
import AdminTablePagination from '../components/AdminTablePagination.vue'
|
||||
|
||||
const status = ref('')
|
||||
@@ -65,6 +66,11 @@ const filteredOrders = computed(() => {
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" class="table-panel" :data="filteredOrders">
|
||||
<el-table-column label="商品编号" width="140">
|
||||
<template #default="{ row }">{{
|
||||
formatListingNo(row.listing_no, row.listing_id)
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="order_no" label="订单号" min-width="230" />
|
||||
<el-table-column prop="title" label="账号" min-width="170" />
|
||||
<el-table-column prop="renter_phone" label="租客" min-width="130" />
|
||||
|
||||
Reference in New Issue
Block a user