修复平台代管订单流程
This commit is contained in:
@@ -33,7 +33,7 @@ import { adminPath } from '@/shared/utils/adminPath'
|
||||
import { centToYuan, formatCentWithSymbol, formatMoney } from '@/shared/utils/money'
|
||||
import { formatDateMinute, formatDateTime } from '@/shared/utils/time'
|
||||
import { formatListingNo } from '@/shared/utils/listingDisplay'
|
||||
import { handoffStatusLabel, orderStatusLabel } from '@/shared/utils/statusLabels'
|
||||
import { orderHandoffStatusLabel, orderStatusLabel } from '@/shared/utils/statusLabels'
|
||||
import TransferDialog from '../components/TransferDialog.vue'
|
||||
import QuickReplyDialog from '../components/QuickReplyDialog.vue'
|
||||
|
||||
@@ -590,11 +590,14 @@ function paymentBizTypeLabel(type: string) {
|
||||
function formatHandoffRecordType(type: string) {
|
||||
const typeMap: Record<string, string> = {
|
||||
owner_handoff: '卖家交接',
|
||||
platform_handoff: '客服代交接',
|
||||
renter_checkout: '买家结账',
|
||||
owner_counter_checkout: '卖家反驳结账',
|
||||
platform_checkout_counter: '客服修改结账',
|
||||
renter_confirm_checkout: '买家确认结账',
|
||||
owner_accept_checkout: '卖家接受结账',
|
||||
admin_arbitration: '客服仲裁',
|
||||
platform_checkout_dispute_opened: '客服发起结账争议',
|
||||
}
|
||||
return typeMap[type] || type
|
||||
}
|
||||
@@ -776,7 +779,7 @@ function firstQueryValue(value: unknown) {
|
||||
</div>
|
||||
<div>
|
||||
<span>交接状态</span>
|
||||
<strong>{{ handoffStatusLabel(activeOrder.handoff_status) }}</strong>
|
||||
<strong>{{ orderHandoffStatusLabel(activeOrder) }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>订单金额</span>
|
||||
|
||||
@@ -7,7 +7,12 @@ import { useRoute } from 'vue-router'
|
||||
import {
|
||||
adminCloseOrder,
|
||||
adminHoldDeposit,
|
||||
adminMarkOfflineSettlement,
|
||||
adminMarkOrderAbnormal,
|
||||
adminPlatformCheckoutCounter,
|
||||
adminPlatformCheckoutConfirm,
|
||||
adminPlatformCheckoutDispute,
|
||||
adminPlatformHandoff,
|
||||
adminRefundOrder,
|
||||
adminRefundStatus,
|
||||
adminReleaseDeposit,
|
||||
@@ -22,14 +27,15 @@ import {
|
||||
import { fetchAdminPayments, type AdminPayment } from '@/features/admin/api/adminPayments'
|
||||
import {
|
||||
getSnapshotHafCoinM,
|
||||
linesToList,
|
||||
readSnapshot,
|
||||
readSnapshotResources,
|
||||
} from '@/features/orders/composables/useOrderSnapshot'
|
||||
import { adminPath } from '@/shared/utils/adminPath'
|
||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
||||
import { centToYuan, formatCentWithSymbol } from '@/shared/utils/money'
|
||||
import {
|
||||
disputeStatusLabel,
|
||||
handoffStatusLabel,
|
||||
orderHandoffStatusLabel,
|
||||
orderStatusLabel,
|
||||
refundStatusLabel,
|
||||
settlementStatusLabel,
|
||||
@@ -48,12 +54,28 @@ type OrderActionType =
|
||||
| 'seal'
|
||||
| 'abnormal'
|
||||
| 'reset'
|
||||
| 'platform_checkout_confirm'
|
||||
| 'platform_checkout_dispute'
|
||||
| 'deposit_hold'
|
||||
| 'deposit_release'
|
||||
| ''
|
||||
const actionType = ref<OrderActionType>('')
|
||||
const reason = ref('')
|
||||
const refundStatus = ref<RefundStatus | null>(null)
|
||||
const platformHandoffVisible = ref(false)
|
||||
const platformHandoffContent = ref('')
|
||||
const platformHandoffReason = ref('')
|
||||
const platformCheckoutCounterVisible = ref(false)
|
||||
const platformCheckoutCounterForm = ref({
|
||||
consumableAmountYuan: 0,
|
||||
coin_consumed_m: 0,
|
||||
depositDeductAmountYuan: 0,
|
||||
reason: '',
|
||||
evidenceText: '',
|
||||
})
|
||||
const offlineSettlementVisible = ref(false)
|
||||
const offlineSettlementRemark = ref('')
|
||||
const platformSubmitting = ref(false)
|
||||
|
||||
type FundSplitRow = {
|
||||
label: string
|
||||
@@ -94,10 +116,40 @@ const canOperate = computed(
|
||||
() => !!order.value && !['completed', 'cancelled', 'closed'].includes(order.value.status)
|
||||
)
|
||||
const resetAction = computed(() => order.value?.admin_actions?.reset_handoff)
|
||||
const platformHandoffAction = computed(() => order.value?.admin_actions?.platform_handoff)
|
||||
const platformCheckoutConfirmAction = computed(
|
||||
() => order.value?.admin_actions?.platform_checkout_confirm
|
||||
)
|
||||
const platformCheckoutCounterAction = computed(
|
||||
() => order.value?.admin_actions?.platform_checkout_counter
|
||||
)
|
||||
const platformCheckoutDisputeAction = computed(
|
||||
() => order.value?.admin_actions?.platform_checkout_dispute
|
||||
)
|
||||
const offlineSettlementAction = computed(
|
||||
() => order.value?.admin_actions?.platform_offline_settlement
|
||||
)
|
||||
const resetActionLabel = computed(() => {
|
||||
return resetAction.value?.label || '重置'
|
||||
})
|
||||
const canResetHandoff = computed(() => resetAction.value?.enabled === true)
|
||||
const canPlatformHandoff = computed(() => platformHandoffAction.value?.enabled === true)
|
||||
const canPlatformCheckoutConfirm = computed(
|
||||
() => platformCheckoutConfirmAction.value?.enabled === true
|
||||
)
|
||||
const canPlatformCheckoutCounter = computed(
|
||||
() => platformCheckoutCounterAction.value?.enabled === true
|
||||
)
|
||||
const canPlatformCheckoutDispute = computed(
|
||||
() => platformCheckoutDisputeAction.value?.enabled === true
|
||||
)
|
||||
const canOfflineSettlement = computed(() => offlineSettlementAction.value?.enabled === true)
|
||||
const isPlatformManaged = computed(
|
||||
() =>
|
||||
order.value?.handoff_mode === 'platform' ||
|
||||
order.value?.settlement_mode === 'platform_managed'
|
||||
)
|
||||
const offlineSettlementStatus = computed(() => order.value?.offline_settlement_status || 'none')
|
||||
// 押金暂扣:仅进行中、有实付押金、且未暂扣过的订单可暂扣。
|
||||
const depositHoldStatus = computed(() => order.value?.deposit_hold_status || 'none')
|
||||
const depositHoldAmountCent = computed(() => Number(order.value?.deposit_hold_amount_cent || 0))
|
||||
@@ -123,13 +175,17 @@ const actionTitle = computed(() => {
|
||||
if (actionType.value === 'close') return '客服关闭订单'
|
||||
if (actionType.value === 'seal') return '封存订单'
|
||||
if (actionType.value === 'reset') return `${resetActionLabel.value}(恢复到对应待办)`
|
||||
if (actionType.value === 'platform_checkout_confirm') return '客服确认结账'
|
||||
if (actionType.value === 'platform_checkout_dispute') return '发起结账争议'
|
||||
if (actionType.value === 'deposit_hold') return '暂扣押金'
|
||||
if (actionType.value === 'deposit_release') return '归还暂扣押金'
|
||||
return '标记订单异常'
|
||||
})
|
||||
const actionConfirmButtonType = computed(() =>
|
||||
actionType.value === 'deposit_release' ? 'primary' : 'danger'
|
||||
)
|
||||
const actionConfirmButtonType = computed(() => {
|
||||
if (['deposit_release', 'platform_checkout_confirm'].includes(actionType.value)) return 'primary'
|
||||
if (actionType.value === 'platform_checkout_dispute') return 'warning'
|
||||
return 'danger'
|
||||
})
|
||||
const closeActionTip =
|
||||
'关闭订单并归档商品/账号;已支付订单会原路退款,押金已暂扣时押金部分会继续挂起。'
|
||||
const sealActionTip =
|
||||
@@ -341,6 +397,12 @@ async function submitAction() {
|
||||
} else if (actionType.value === 'reset') {
|
||||
await adminResetHandoff(order.value.id, reason.value)
|
||||
ElMessage.success(`${resetActionLabel.value}成功`)
|
||||
} else if (actionType.value === 'platform_checkout_confirm') {
|
||||
await adminPlatformCheckoutConfirm(order.value.id, reason.value)
|
||||
ElMessage.success('结账已确认')
|
||||
} else if (actionType.value === 'platform_checkout_dispute') {
|
||||
await adminPlatformCheckoutDispute(order.value.id, reason.value)
|
||||
ElMessage.success('已发起结账争议')
|
||||
} else if (actionType.value === 'deposit_hold') {
|
||||
await adminHoldDeposit(order.value.id, reason.value)
|
||||
ElMessage.success('押金已暂扣')
|
||||
@@ -360,6 +422,97 @@ async function submitAction() {
|
||||
}
|
||||
}
|
||||
|
||||
function openPlatformHandoff() {
|
||||
platformHandoffContent.value = ''
|
||||
platformHandoffReason.value = ''
|
||||
platformHandoffVisible.value = true
|
||||
}
|
||||
|
||||
async function submitPlatformHandoff() {
|
||||
if (!order.value) return
|
||||
if (!platformHandoffContent.value.trim() || !platformHandoffReason.value.trim()) {
|
||||
ElMessage.warning('请填写交接说明和操作原因')
|
||||
return
|
||||
}
|
||||
platformSubmitting.value = true
|
||||
try {
|
||||
await adminPlatformHandoff(
|
||||
order.value.id,
|
||||
platformHandoffContent.value.trim(),
|
||||
platformHandoffReason.value.trim()
|
||||
)
|
||||
ElMessage.success('客服代交接已提交')
|
||||
platformHandoffVisible.value = false
|
||||
await loadOrder()
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '代交接失败'))
|
||||
} finally {
|
||||
platformSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openPlatformCheckoutCounter() {
|
||||
const checkout = order.value?.checkout
|
||||
platformCheckoutCounterForm.value = {
|
||||
consumableAmountYuan: centToYuan(checkout?.consumable_amount_cent || 0),
|
||||
coin_consumed_m: Number(checkout?.coin_consumed_m || snapshotHafCoinM.value || 0),
|
||||
depositDeductAmountYuan: centToYuan(
|
||||
checkout?.deposit_deduct_amount_cent || checkout?.other_amount_cent || 0
|
||||
),
|
||||
reason: '',
|
||||
evidenceText: Array.isArray(checkout?.evidence_urls) ? checkout.evidence_urls.join('\n') : '',
|
||||
}
|
||||
platformCheckoutCounterVisible.value = true
|
||||
}
|
||||
|
||||
async function submitPlatformCheckoutCounter() {
|
||||
if (!order.value) return
|
||||
const form = platformCheckoutCounterForm.value
|
||||
if (!form.reason.trim()) {
|
||||
ElMessage.warning('请填写修改原因')
|
||||
return
|
||||
}
|
||||
platformSubmitting.value = true
|
||||
try {
|
||||
await adminPlatformCheckoutCounter(order.value.id, {
|
||||
content: form.reason.trim(),
|
||||
consumableAmountYuan: form.consumableAmountYuan,
|
||||
coin_consumed_m: form.coin_consumed_m,
|
||||
otherAmountYuan: form.depositDeductAmountYuan,
|
||||
depositDeductAmountYuan: form.depositDeductAmountYuan,
|
||||
reason: form.reason.trim(),
|
||||
evidence_urls: linesToList(form.evidenceText),
|
||||
})
|
||||
ElMessage.success('结账方案已修改,等待租客确认')
|
||||
platformCheckoutCounterVisible.value = false
|
||||
await loadOrder()
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '修改结账方案失败'))
|
||||
} finally {
|
||||
platformSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openOfflineSettlement() {
|
||||
offlineSettlementRemark.value = ''
|
||||
offlineSettlementVisible.value = true
|
||||
}
|
||||
|
||||
async function submitOfflineSettlement() {
|
||||
if (!order.value) return
|
||||
platformSubmitting.value = true
|
||||
try {
|
||||
await adminMarkOfflineSettlement(order.value.id, offlineSettlementRemark.value.trim())
|
||||
ElMessage.success('线下结算已确认')
|
||||
offlineSettlementVisible.value = false
|
||||
await loadOrder()
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '确认线下结算失败'))
|
||||
} finally {
|
||||
platformSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function orderRentedAt() {
|
||||
return order.value?.rented_at
|
||||
}
|
||||
@@ -462,15 +615,49 @@ function firstQueryValue(value: unknown) {
|
||||
function formatHandoffRecordType(type: string) {
|
||||
const typeMap: Record<string, string> = {
|
||||
owner_handoff: '卖家交接',
|
||||
platform_handoff: '客服代交接',
|
||||
renter_checkout: '买家结账',
|
||||
owner_counter_checkout: '卖家反驳结账',
|
||||
platform_checkout_counter: '客服修改结账',
|
||||
renter_confirm_checkout: '买家确认结账',
|
||||
owner_accept_checkout: '卖家接受结账',
|
||||
admin_arbitration: '客服仲裁',
|
||||
platform_checkout_dispute_opened: '客服发起结账争议',
|
||||
}
|
||||
return typeMap[type] || type
|
||||
}
|
||||
|
||||
function handoffModeLabel(mode?: string) {
|
||||
const map: Record<string, string> = {
|
||||
owner: '号主交接',
|
||||
platform: '平台代管',
|
||||
}
|
||||
return map[mode || 'owner'] || mode || '-'
|
||||
}
|
||||
|
||||
function settlementModeLabel(mode?: string) {
|
||||
const map: Record<string, string> = {
|
||||
owner_wallet: '号主钱包',
|
||||
platform_managed: '线下结算',
|
||||
}
|
||||
return map[mode || 'owner_wallet'] || mode || '-'
|
||||
}
|
||||
|
||||
function offlineSettlementStatusLabel(status?: string) {
|
||||
const map: Record<string, string> = {
|
||||
none: '无需线下结算',
|
||||
pending: '待线下结算',
|
||||
settled: '已线下结算',
|
||||
}
|
||||
return map[status || 'none'] || status || '-'
|
||||
}
|
||||
|
||||
function offlineSettlementStatusType(status?: string) {
|
||||
if (status === 'settled') return 'success'
|
||||
if (status === 'pending') return 'warning'
|
||||
return 'info'
|
||||
}
|
||||
|
||||
function orderStatusType(status: string) {
|
||||
if (['completed', 'renting'].includes(status)) return 'success'
|
||||
if (['overdue', 'abnormal', 'checkout_disputing'].includes(status)) return 'danger'
|
||||
@@ -527,6 +714,13 @@ function userDisplay(phone: string | undefined, id: number) {
|
||||
return phone ? `${phone} / ID ${id}` : `ID ${id}`
|
||||
}
|
||||
|
||||
function sellerDisplay(row: Order) {
|
||||
if (row.handoff_mode === 'platform' || row.settlement_mode === 'platform_managed') {
|
||||
return row.managed_admin_id ? `平台代管 / 客服ID ${row.managed_admin_id}` : '平台代管'
|
||||
}
|
||||
return userDisplay(row.owner_phone, row.owner_id)
|
||||
}
|
||||
|
||||
function displayValue(value: unknown) {
|
||||
if (value === undefined || value === null || value === '') return '-'
|
||||
if (Array.isArray(value))
|
||||
@@ -574,6 +768,34 @@ function paymentPaidAt(record: AdminPayment) {
|
||||
<el-button v-if="canResetHandoff" type="success" @click="openAction('reset')">
|
||||
{{ resetActionLabel }}
|
||||
</el-button>
|
||||
<el-button v-if="canPlatformHandoff" type="primary" plain @click="openPlatformHandoff">
|
||||
{{ platformHandoffAction?.label || '客服代交接' }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canPlatformCheckoutConfirm"
|
||||
type="primary"
|
||||
@click="openAction('platform_checkout_confirm')"
|
||||
>
|
||||
{{ platformCheckoutConfirmAction?.label || '客服确认结账' }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canPlatformCheckoutCounter"
|
||||
type="warning"
|
||||
plain
|
||||
@click="openPlatformCheckoutCounter"
|
||||
>
|
||||
{{ platformCheckoutCounterAction?.label || '客服修改结账方案' }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canPlatformCheckoutDispute"
|
||||
type="warning"
|
||||
@click="openAction('platform_checkout_dispute')"
|
||||
>
|
||||
{{ platformCheckoutDisputeAction?.label || '发起结账争议' }}
|
||||
</el-button>
|
||||
<el-button v-if="canOfflineSettlement" type="success" @click="openOfflineSettlement">
|
||||
{{ offlineSettlementAction?.label || '确认线下结算' }}
|
||||
</el-button>
|
||||
<el-button type="warning" :disabled="!canOperate" @click="openAction('abnormal')"
|
||||
>标记异常</el-button
|
||||
>
|
||||
@@ -627,13 +849,18 @@ function paymentPaidAt(record: AdminPayment) {
|
||||
<div class="metric-card">
|
||||
<span>订单状态</span>
|
||||
<strong>{{ orderStatusLabel(order.status) }}</strong>
|
||||
<small>{{ handoffStatusLabel(order.handoff_status) }}</small>
|
||||
<small>{{ orderHandoffStatusLabel(order) }}</small>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>结算状态</span>
|
||||
<strong>{{ settlementStatusLabel(order.settlement_status) }}</strong>
|
||||
<small>更新 {{ formatDateTime(order.updated_at) }}</small>
|
||||
</div>
|
||||
<div v-if="isPlatformManaged" class="metric-card">
|
||||
<span>线下结算</span>
|
||||
<strong>{{ offlineSettlementStatusLabel(offlineSettlementStatus) }}</strong>
|
||||
<small>{{ moneyCent(order.offline_settlement_amount_cent) }}</small>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>订单总额</span>
|
||||
<strong>{{ moneyCent(orderTotalCent) }}</strong>
|
||||
@@ -717,7 +944,7 @@ function paymentPaidAt(record: AdminPayment) {
|
||||
</div>
|
||||
<div>
|
||||
<dt>号主</dt>
|
||||
<dd>{{ userDisplay(order.owner_phone, order.owner_id) }}</dd>
|
||||
<dd>{{ sellerDisplay(order) }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>创建时间</dt>
|
||||
@@ -738,6 +965,45 @@ function paymentPaidAt(record: AdminPayment) {
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<section v-if="isPlatformManaged" class="dashboard-panel detail-panel">
|
||||
<div class="panel-heading">
|
||||
<h2>平台代管</h2>
|
||||
<el-tag :type="offlineSettlementStatusType(offlineSettlementStatus)" effect="light">
|
||||
{{ offlineSettlementStatusLabel(offlineSettlementStatus) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<dl class="detail-list">
|
||||
<div>
|
||||
<dt>交接模式</dt>
|
||||
<dd>{{ handoffModeLabel(order.handoff_mode) }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>结算模式</dt>
|
||||
<dd>{{ settlementModeLabel(order.settlement_mode) }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>负责客服</dt>
|
||||
<dd>{{ order.managed_admin_id ? `ID ${order.managed_admin_id}` : '-' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>待打款金额</dt>
|
||||
<dd>{{ moneyCent(order.offline_settlement_amount_cent) }}</dd>
|
||||
</div>
|
||||
<div v-if="order.offline_settled_by">
|
||||
<dt>确认客服</dt>
|
||||
<dd>ID {{ order.offline_settled_by }}</dd>
|
||||
</div>
|
||||
<div v-if="order.offline_settled_at">
|
||||
<dt>确认时间</dt>
|
||||
<dd>{{ formatDateTime(order.offline_settled_at) }}</dd>
|
||||
</div>
|
||||
<div v-if="order.offline_settlement_remark" class="wide">
|
||||
<dt>线下备注</dt>
|
||||
<dd>{{ order.offline_settlement_remark }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<section class="dashboard-panel detail-panel">
|
||||
<div class="panel-heading">
|
||||
<h2>资金拆分</h2>
|
||||
@@ -999,6 +1265,131 @@ function paymentPaidAt(record: AdminPayment) {
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="platformHandoffVisible"
|
||||
title="客服代交接"
|
||||
width="560px"
|
||||
destroy-on-close
|
||||
>
|
||||
<div v-if="order" class="dialog-body">
|
||||
<p>
|
||||
<strong>{{ order.order_no }}</strong> · 商品编号 {{ listingCode }} · {{ order.title }}
|
||||
</p>
|
||||
<el-input
|
||||
v-model="platformHandoffContent"
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
placeholder="填写发给租客的交接说明"
|
||||
/>
|
||||
<el-input
|
||||
v-model="platformHandoffReason"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="填写客服操作原因"
|
||||
/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="platformHandoffVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="platformSubmitting" @click="submitPlatformHandoff">
|
||||
提交交接
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="platformCheckoutCounterVisible"
|
||||
title="客服修改结账方案"
|
||||
width="620px"
|
||||
destroy-on-close
|
||||
>
|
||||
<div v-if="order" class="dialog-body">
|
||||
<p>
|
||||
<strong>{{ order.order_no }}</strong> · 当前号主收入
|
||||
{{ moneyCent(order.checkout?.owner_income_amount_cent) }}
|
||||
</p>
|
||||
<div class="form-grid">
|
||||
<label>
|
||||
<span>消耗品金额(元)</span>
|
||||
<el-input-number
|
||||
v-model="platformCheckoutCounterForm.consumableAmountYuan"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
controls-position="right"
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
<span>哈夫币消耗(M)</span>
|
||||
<el-input-number
|
||||
v-model="platformCheckoutCounterForm.coin_consumed_m"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
controls-position="right"
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
<span>押金赔付扣除(元)</span>
|
||||
<el-input-number
|
||||
v-model="platformCheckoutCounterForm.depositDeductAmountYuan"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
controls-position="right"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<el-input
|
||||
v-model="platformCheckoutCounterForm.reason"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="填写修改原因,将同步给租客并写入审计日志"
|
||||
/>
|
||||
<el-input
|
||||
v-model="platformCheckoutCounterForm.evidenceText"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="证据链接,一行一个,可留空"
|
||||
/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="platformCheckoutCounterVisible = false">取消</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="platformSubmitting"
|
||||
@click="submitPlatformCheckoutCounter"
|
||||
>
|
||||
提交修改
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="offlineSettlementVisible"
|
||||
title="确认线下结算"
|
||||
width="520px"
|
||||
destroy-on-close
|
||||
>
|
||||
<div v-if="order" class="dialog-body">
|
||||
<p>
|
||||
待打款金额
|
||||
<strong>{{ moneyCent(order.offline_settlement_amount_cent) }}</strong>
|
||||
</p>
|
||||
<el-input
|
||||
v-model="offlineSettlementRemark"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="填写线下转账备注,可留空"
|
||||
/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="offlineSettlementVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="platformSubmitting" @click="submitOfflineSettlement">
|
||||
确认已结算
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -1250,6 +1641,35 @@ function paymentPaidAt(record: AdminPayment) {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.dialog-body {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.dialog-body p {
|
||||
margin: 0;
|
||||
color: #52616f;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.form-grid label {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
color: #52616f;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-grid :deep(.el-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.order-detail-grid {
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { onMounted, reactive, ref } from 'vue'
|
||||
|
||||
import { fetchAdminOrders, type AdminOrderQuery, type Order } from '@/features/orders'
|
||||
import {
|
||||
handoffStatusLabel,
|
||||
orderHandoffStatusLabel,
|
||||
orderStatusLabel,
|
||||
settlementStatusLabel,
|
||||
} from '@/shared/utils/statusLabels'
|
||||
@@ -233,7 +233,7 @@ function userText(value: string | number | undefined) {
|
||||
<template #default="{ row }">
|
||||
<div class="stacked-cell compact">
|
||||
<strong>{{ orderStatusLabel(row.status) }}</strong>
|
||||
<span>{{ handoffStatusLabel(row.handoff_status) }}</span>
|
||||
<span>{{ orderHandoffStatusLabel(row) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
@@ -33,7 +33,15 @@ export interface Order {
|
||||
counter_info?: string
|
||||
status: OrderStatus
|
||||
handoff_status: HandoffStatus
|
||||
handoff_mode?: string
|
||||
settlement_mode?: string
|
||||
managed_admin_id?: number
|
||||
settlement_status: SettlementStatus
|
||||
offline_settlement_status?: string
|
||||
offline_settlement_amount_cent?: number
|
||||
offline_settlement_remark?: string
|
||||
offline_settled_by?: number
|
||||
offline_settled_at?: string
|
||||
refund_status?: string
|
||||
refund_amount_cent?: number
|
||||
deposit_hold_status?: string
|
||||
@@ -51,6 +59,11 @@ export interface Order {
|
||||
|
||||
export interface AdminActions {
|
||||
reset_handoff?: AdminAction
|
||||
platform_handoff?: AdminAction
|
||||
platform_checkout_confirm?: AdminAction
|
||||
platform_checkout_counter?: AdminAction
|
||||
platform_checkout_dispute?: AdminAction
|
||||
platform_offline_settlement?: AdminAction
|
||||
}
|
||||
|
||||
export interface AdminAction {
|
||||
@@ -373,6 +386,46 @@ export async function adminResetHandoff(id: number, reason: string) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function adminPlatformHandoff(id: number, content: string, reason: string) {
|
||||
const { data } = await apiClient.post<ApiResponse<HandoffRecord>>(
|
||||
`/admin/orders/${id}/platform-handoff`,
|
||||
{ content, reason }
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function adminPlatformCheckoutConfirm(id: number, reason: string) {
|
||||
const { data } = await apiClient.post<ApiResponse<{ confirmed: boolean }>>(
|
||||
`/admin/orders/${id}/platform-checkout/confirm`,
|
||||
{ reason }
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function adminPlatformCheckoutCounter(id: number, payload: SubmitCheckoutPayload) {
|
||||
const { data } = await apiClient.post<ApiResponse<Checkout>>(
|
||||
`/admin/orders/${id}/platform-checkout/counter`,
|
||||
toCheckoutRequest(payload)
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function adminPlatformCheckoutDispute(id: number, reason: string) {
|
||||
const { data } = await apiClient.post<ApiResponse<{ disputed: boolean }>>(
|
||||
`/admin/orders/${id}/platform-checkout/dispute`,
|
||||
{ reason }
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function adminMarkOfflineSettlement(id: number, remark: string) {
|
||||
const { data } = await apiClient.post<ApiResponse<{ settled: boolean }>>(
|
||||
`/admin/orders/${id}/offline-settlement`,
|
||||
{ remark }
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function adminRefundStatus(id: number) {
|
||||
const { data } = await apiClient.get<ApiResponse<RefundStatus>>(
|
||||
`/admin/orders/${id}/refund-status`
|
||||
|
||||
@@ -234,13 +234,16 @@ export function ownerActualIncome(item: Order, userID: number | undefined | null
|
||||
export function formatHandoffRecordType(type: string) {
|
||||
const typeMap: Record<string, string> = {
|
||||
owner_handoff: '卖家交接',
|
||||
platform_handoff: '客服代交接',
|
||||
renter_checkout: '买家结账',
|
||||
owner_counter_checkout: '卖家反驳结账',
|
||||
platform_checkout_counter: '客服修改结账',
|
||||
renter_confirm_checkout: '买家确认结账',
|
||||
owner_accept_checkout: '卖家接受结账',
|
||||
admin_arbitration: '客服仲裁',
|
||||
dispute_opened: '发起申诉',
|
||||
checkout_dispute_opened: '发起结账争议',
|
||||
platform_checkout_dispute_opened: '客服发起结账争议',
|
||||
dispute_cancelled: '取消申诉',
|
||||
checkout_dispute_cancelled: '取消结账争议',
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
OrderHandoffTimeline,
|
||||
OrderResourceUsageEditor,
|
||||
} from '@/features/orders'
|
||||
import { handoffStatusLabel, orderStatusLabel } from '@/shared/utils/statusLabels'
|
||||
import { orderHandoffStatusLabel, orderStatusLabel } from '@/shared/utils/statusLabels'
|
||||
import { formatDateTime } from '@/shared/utils/time'
|
||||
|
||||
// 移动端支付收银台(基于通用 useOrderPaymentCashier 的薄封装:注入 vant toast + App 浏览器跳转)。
|
||||
@@ -202,7 +202,7 @@ async function copyListingCode() {
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<span class="meta-label">交接状态</span>
|
||||
<strong class="meta-value">{{ handoffStatusLabel(order.handoff_status) }}</strong>
|
||||
<strong class="meta-value">{{ orderHandoffStatusLabel(order) }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
import { useOrderActions } from '@/features/orders/composables/useOrderActions'
|
||||
import { useOrderPaymentCashier } from '@/features/orders/composables/useOrderPaymentCashier'
|
||||
import { formatCent } from '@/shared/utils/money'
|
||||
import { handoffStatusLabel, orderStatusLabel } from '@/shared/utils/statusLabels'
|
||||
import { orderHandoffStatusLabel, orderStatusLabel } from '@/shared/utils/statusLabels'
|
||||
import { formatDateTime } from '@/shared/utils/time'
|
||||
import type { PaymentPayWay } from '@/features/orders/api/orders'
|
||||
|
||||
@@ -302,7 +302,7 @@ watch([() => route.query.focus, order, loading], () => {
|
||||
<el-step
|
||||
title="待交接"
|
||||
:description="
|
||||
order.status === 'pending_handoff' ? handoffStatusLabel(order.handoff_status) : ''
|
||||
order.status === 'pending_handoff' ? orderHandoffStatusLabel(order) : ''
|
||||
"
|
||||
/>
|
||||
<el-step
|
||||
@@ -383,7 +383,7 @@ watch([() => route.query.focus, order, loading], () => {
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span class="metric-label">交接状态</span>
|
||||
<strong class="metric-value">{{ handoffStatusLabel(order.handoff_status) }}</strong>
|
||||
<strong class="metric-value">{{ orderHandoffStatusLabel(order) }}</strong>
|
||||
</div>
|
||||
<div class="metric-card highlight">
|
||||
<span class="metric-label">{{ orderAmountLabel }}</span>
|
||||
|
||||
@@ -160,6 +160,24 @@ export function handoffStatusLabel(status: string) {
|
||||
return readLabel(handoffStatusMap, status)
|
||||
}
|
||||
|
||||
export function orderHandoffStatusLabel(order?: {
|
||||
handoff_status?: string
|
||||
handoff_mode?: string
|
||||
settlement_mode?: string
|
||||
} | null) {
|
||||
const status = order?.handoff_status || ''
|
||||
if (order?.handoff_mode !== 'platform' && order?.settlement_mode !== 'platform_managed') {
|
||||
return handoffStatusLabel(status)
|
||||
}
|
||||
const platformMap: Record<string, string> = {
|
||||
pending_owner: '待客服交接',
|
||||
owner_timeout: '客服交接超时',
|
||||
pending_owner_checkout: '待客服确认结账',
|
||||
owner_checkout_confirm_timeout: '客服确认结账超时',
|
||||
}
|
||||
return platformMap[status] || handoffStatusLabel(status)
|
||||
}
|
||||
|
||||
export function settlementStatusLabel(status: string) {
|
||||
return readLabel(settlementStatusMap, status)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user