第 5 阶段:纠纷、通知与后台-1

This commit is contained in:
yml
2026-05-22 16:34:32 +08:00
parent 9ebdfab078
commit 99f9df7bcd
32 changed files with 1711 additions and 8 deletions
@@ -3,6 +3,7 @@ import { ElMessage } from 'element-plus'
import { computed, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { createDispute } from '@/api/disputes'
import {
cancelOrder,
confirmReceive,
@@ -25,13 +26,21 @@ const handoffing = ref(false)
const confirming = ref(false)
const returning = ref(false)
const completing = ref(false)
const disputing = ref(false)
const order = ref<Order | null>(null)
const handoffRecords = ref<HandoffRecord[]>([])
const handoffContent = ref('')
const returnContent = ref('')
const disputeType = ref('cannot_login')
const disputeDescription = ref('')
const disputeEvidenceText = ref('')
const isOwner = computed(() => order.value?.owner_id === session.userId)
const isRenter = computed(() => order.value?.renter_id === session.userId)
const canOpenDispute = computed(() => {
if (!order.value || (!isOwner.value && !isRenter.value)) return false
return !['completed', 'cancelled', 'closed', 'disputing'].includes(order.value.status)
})
onMounted(loadOrder)
@@ -117,6 +126,30 @@ async function handleConfirmReturn() {
}
}
async function handleCreateDispute() {
if (!order.value) return
disputing.value = true
try {
const evidence_urls = disputeEvidenceText.value
.split('\n')
.map((item) => item.trim())
.filter(Boolean)
await createDispute(order.value.id, {
type: disputeType.value,
description: disputeDescription.value,
evidence_urls,
})
disputeDescription.value = ''
disputeEvidenceText.value = ''
ElMessage.success('申诉已提交,订单进入仲裁处理')
await loadOrder()
} catch (error) {
ElMessage.error(readError(error, '提交申诉失败'))
} finally {
disputing.value = false
}
}
function readError(error: unknown, fallback: string) {
if (typeof error === 'object' && error && 'response' in error) {
const response = (error as { response?: { data?: { message?: string } } }).response
@@ -198,5 +231,33 @@ function readError(error: unknown, fallback: string) {
<p>确认账号状态无误后订单会完成账号重新上架</p>
<el-button type="primary" :loading="completing" @click="handleConfirmReturn">确认归还并完成订单</el-button>
</div>
<div v-if="order && canOpenDispute" class="order-panel">
<h2>发起申诉</h2>
<el-select v-model="disputeType" class="full-control" placeholder="选择申诉类型">
<el-option label="无法登录" value="cannot_login" />
<el-option label="虚假描述" value="false_description" />
<el-option label="账号被封" value="account_banned" />
<el-option label="资产损失" value="asset_loss" />
<el-option label="哈夫币争议" value="haf_coin_dispute" />
<el-option label="超时未交接" value="handoff_timeout" />
<el-option label="超时未归还" value="return_timeout" />
</el-select>
<el-input
v-model="disputeDescription"
class="panel-action"
type="textarea"
:rows="4"
placeholder="说明争议经过、时间点和希望客服核查的证据"
/>
<el-input
v-model="disputeEvidenceText"
class="panel-action"
type="textarea"
:rows="3"
placeholder="证据链接,一行一个。开发阶段可先填截图地址或备注链接"
/>
<el-button class="panel-action" type="warning" :loading="disputing" @click="handleCreateDispute">提交申诉</el-button>
</div>
</section>
</template>