完成了基本调整调整

This commit is contained in:
2026-09-18 20:55:21 +08:00
parent 864187e105
commit 57e0854a0e
56 changed files with 3122 additions and 105 deletions
@@ -0,0 +1,235 @@
<template>
<a-modal
title="订单退款"
:width="760"
:visible="visible"
:footer="null"
:maskClosable="false"
@cancel="handleCancel"
>
<a-spin :spinning="isLoading">
<div class="info">
<p>油卡编号:{{ record.oilCardNo }}</p>
<p>司机:{{ record.driver_name || '-' }}&nbsp;&nbsp;{{ record.mobile }}</p>
<p>订单金额:¥{{ record.total_price }}&nbsp;&nbsp;已加油:¥{{ record.used_amount || '0.00' }}({{ record.used_num || 0 }} 次)</p>
<p>
退款金额:<b class="amount">¥{{ refundAmount }}</b>
<span v-if="status === 2">(实际退款)</span>
<span v-else>(剩余未加油金额,固定不可修改)</span>
</p>
<p>当前状态:<a-tag :color="statusColor">{{ statusText }}</a-tag></p>
<p v-if="record.refund_text" class="sub">{{ record.refund_text }}</p>
</div>
<a-alert v-if="(status === 0 || status === 3) && Number(refundAmount) <= 0" type="warning" show-icon class="block" message="订单金额已全部加油,没有可退金额" />
<!-- 可发起:未退款 / 退款失败,且还有剩余未加油金额 -->
<template v-if="(status === 0 || status === 3) && Number(refundAmount) > 0">
<a-alert type="info" show-icon class="block">
<div slot="message">
一张订单可以分多次加油,<b>退款金额固定为剩余未加油金额</b>,已加油的部分不退,每单只能成功退一次。
<br>退款会先用企油通 7.17 查询司机支付凭证,再用 7.16 把凭证额度调低退款金额;成功后原路回补合作商余额,并推送油卡变动通知。
<br>额度在凭证上按司机累计,若凭证可用余额不足退款金额(被该司机其他订单用掉),会直接拒绝。
</div>
</a-alert>
<a-textarea v-model="reason" :rows="2" :maxLength="100" placeholder="退款原因(选填,会写入企油通调额记录)" />
<div class="btns">
<a-button type="primary" :loading="isLoading" @click="handleRefund">确认退款</a-button>
</div>
</template>
<!-- 待人工确认 -->
<template v-if="status === 4">
<a-alert type="warning" show-icon class="block">
<div slot="message">
调额请求已发给企油通但没有拿到明确结果。企油通调额接口<b>没有幂等保护</b>,重复发起会被重复扣减,所以这里不允许直接重试。
<br>请先点「向企油通取证」:系统会查司机钱包流水(找退款单号)和凭证额度变化自动判定;判定不了再人工核对后提交。
</div>
</a-alert>
<div class="btns">
<a-button type="primary" :loading="isLoading" @click="handleConfirm">向企油通取证</a-button>
</div>
<a-divider orientation="left">人工判定</a-divider>
<a-radio-group v-model="resolveResult">
<a-radio value="success">企油通已调低额度(退款成功)</a-radio>
<a-radio value="failed">企油通未调额(退款失败,可重新发起)</a-radio>
</a-radio-group>
<a-textarea v-model="resolveRemark" class="mt-10" :rows="2" :maxLength="100" placeholder="判定依据(必填),如:已在企油通后台核对凭证 xxx 总额度由 300 变为 200" />
<div class="btns">
<a-button :loading="isLoading" @click="handleResolve">提交人工判定</a-button>
</div>
</template>
<a-divider orientation="left">退款流水</a-divider>
<a-table
size="small"
rowKey="refund_id"
:columns="columns"
:dataSource="logs"
:pagination="false"
>
<span slot="status" slot-scope="text, row">
<a-tag :color="logColor(row.status)">{{ row.status_text }}</a-tag>
</span>
</a-table>
</a-spin>
</a-modal>
</template>
<script>
import * as Api from '@/api/partners/order'
const STATUS_TEXT = { 0: '未退款', 1: '退款中', 2: '已退款', 3: '退款失败', 4: '待人工确认' }
const STATUS_COLOR = { 1: 'blue', 2: 'green', 3: 'red', 4: 'orange' }
export default {
data () {
return {
visible: false,
isLoading: false,
record: {},
reason: '',
resolveResult: 'success',
resolveRemark: '',
logs: [],
columns: [
{ title: '退款单号', dataIndex: 'refund_no' },
{ title: '状态', scopedSlots: { customRender: 'status' } },
{ title: '凭证', dataIndex: 'quota_id' },
{ title: '调额前可用', dataIndex: 'available_before' },
{ title: '说明', dataIndex: 'message' },
{ title: '操作人', dataIndex: 'operator' },
{ title: '时间', dataIndex: 'create_time_text' }
]
}
},
computed: {
status () {
return Number(this.record.refund_status || 0)
},
statusText () {
return STATUS_TEXT[this.status] || '-'
},
statusColor () {
return STATUS_COLOR[this.status] || ''
},
// 已退款显示实际退款金额;否则为剩余未加油金额(后端同口径计算)
refundAmount () {
if (this.status === 2) {
return Number(this.record.refund_amount || 0).toFixed(2)
}
const remain = Number(this.record.total_price || 0) - Number(this.record.used_amount || 0)
return Math.max(0, remain).toFixed(2)
}
},
methods: {
show (record) {
this.visible = true
this.record = { ...record }
this.reason = ''
this.resolveResult = 'success'
this.resolveRemark = ''
this.loadLogs()
},
handleCancel () {
this.visible = false
},
loadLogs () {
Api.refundLog({ orderId: this.record.order_id }).then(result => {
this.logs = result.data.list
// 流水状态码与订单退款状态一致:用最新一条同步弹窗状态,失败 / 转人工后界面跟着切换
if (this.logs.length) {
this.record = { ...this.record, refund_status: Number(this.logs[0].status), refund_text: this.logs[0].message }
}
})
},
logColor (status) {
return STATUS_COLOR[Number(status)] || ''
},
// 退款 / 取证 / 判定之后统一刷新:弹窗里的状态 + 父列表
afterAction (result, status) {
this.$message.success(result.message, 2)
if (status !== undefined) {
this.record = { ...this.record, refund_status: status, refund_text: result.message }
}
this.loadLogs()
this.$emit('handleSubmit')
},
// 业务失败时后端返回错误,request 拦截器已弹出提示;这里仍需刷新状态(可能已变成失败/待确认)
afterError () {
this.loadLogs()
this.$emit('handleSubmit')
},
handleRefund () {
this.$confirm({
title: '确认退款 ¥' + this.refundAmount + '?',
content: '退还剩余未加油金额:将调低该司机企油通凭证额度,成功后回补合作商余额。',
onOk: () => {
this.isLoading = true
return Api.refund({ orderId: this.record.order_id, reason: this.reason })
.then(result => this.afterAction(result, 2))
.catch(() => this.afterError())
.finally(() => {
this.isLoading = false
})
}
})
},
handleConfirm () {
this.isLoading = true
Api.refundConfirm({ orderId: this.record.order_id })
.then(result => this.afterAction(result, result.data.refundStatus))
.catch(() => this.afterError())
.finally(() => {
this.isLoading = false
})
},
handleResolve () {
if (!this.resolveRemark.trim()) {
this.$message.warning('请填写判定依据')
return
}
this.isLoading = true
Api.refundResolve({ orderId: this.record.order_id, result: this.resolveResult, remark: this.resolveRemark })
.then(result => this.afterAction(result, result.data.refundStatus))
.catch(() => this.afterError())
.finally(() => {
this.isLoading = false
})
}
}
}
</script>
<style lang="less" scoped>
.info p {
margin-bottom: 6px;
}
.amount {
color: #f5222d;
}
.sub {
color: #999;
font-size: 12px;
}
.block {
margin: 12px 0;
}
.btns {
margin-top: 12px;
text-align: right;
}
.mt-10 {
margin-top: 10px;
}
</style>