fix: bug
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m9s

This commit is contained in:
sexygoat
2026-04-23 14:59:05 +08:00
parent a9467e8a0c
commit a5e76313cb
28 changed files with 1284 additions and 702 deletions

View File

@@ -44,8 +44,7 @@
const loading = ref(false)
const detailData = ref<AgentRecharge | null>(null)
const rechargeId = computed(() => Number(route.params.id))
const pageTitle = computed(() => `充值订单详情 #${rechargeId.value}`)
const pageTitle = computed(() => `充值订单详情`)
// 格式化货币 - 将分转换为元
const formatCurrency = (amount: number): string => {
@@ -159,7 +158,7 @@
const loadDetailData = async () => {
loading.value = true
try {
const res = await AgentRechargeService.getAgentRechargeById(rechargeId.value)
const res = await AgentRechargeService.getAgentRechargeById(Number(route.params.id))
if (res.code === 0) {
detailData.value = res.data
} else {

View File

@@ -6,6 +6,7 @@
v-model:filter="searchForm"
:items="searchFormItems"
:show-expand="false"
label-width="100"
@reset="handleReset"
@search="handleSearch"
></ArtSearchBar>
@@ -214,6 +215,7 @@
const initialSearchState: AgentRechargeQueryParams = {
shop_id: undefined,
status: undefined,
dateRange: [],
start_date: '',
end_date: ''
}
@@ -288,11 +290,12 @@
}
},
{
label: '创建时间',
label: '开始至结束',
prop: 'dateRange',
type: 'daterange',
type: 'date',
config: {
clearable: true,
type: 'daterange',
rangeSeparator: '至',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
valueFormat: 'YYYY-MM-DD'
@@ -414,7 +417,7 @@
style: 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;',
onClick: (e: MouseEvent) => {
e.stopPropagation()
handleViewDetail(row)
handleNameClick(row)
}
},
row.recharge_no
@@ -733,6 +736,15 @@
})
}
// 处理名称点击
const handleNameClick = (row: AgentRecharge) => {
if (hasAuth('agent_recharge:detail_page')) {
handleViewDetail(row)
} else {
ElMessage.warning('您没有查看详情的权限')
}
}
// 查看详情
const handleViewDetail = (row: AgentRecharge) => {
router.push({

View File

@@ -1,77 +1,24 @@
<template>
<div class="refund-detail-page">
<ElCard shadow="never" v-loading="loading">
<template #header>
<div class="card-header">
<span>退款详情</span>
<ElButton @click="handleGoBack">返回</ElButton>
</div>
</template>
<ElCard shadow="never">
<!-- 页面头部 -->
<div class="detail-header">
<ElButton @click="handleBack">
<template #icon>
<ElIcon><ArrowLeft /></ElIcon>
</template>
返回
</ElButton>
<h2 class="detail-title">{{ pageTitle }}</h2>
</div>
<ElDescriptions :column="2" border v-if="refund">
<ElDescriptionsItem label="退款单号">{{ refund.refund_no }}</ElDescriptionsItem>
<ElDescriptionsItem label="状态">
<ElTag :type="getStatusType(refund.status)">{{ getStatusText(refund.status) }}</ElTag>
</ElDescriptionsItem>
<!-- 详情内容 -->
<DetailPage v-if="refund" :sections="detailSections" :data="refund" />
<ElDescriptionsItem label="申请退款金额">
{{ formatCurrency(refund.requested_refund_amount) }}
</ElDescriptionsItem>
<ElDescriptionsItem label="实际退款金额">
{{ refund.approved_refund_amount ? formatCurrency(refund.approved_refund_amount) : '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="实收金额">
{{ formatCurrency(refund.actual_received_amount) }}
</ElDescriptionsItem>
<ElDescriptionsItem label="资产重置">
<ElTag :type="refund.asset_reset ? 'success' : 'info'">
{{ refund.asset_reset ? '是' : '否' }}
</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="佣金扣除">
<ElTag :type="refund.commission_deducted ? 'success' : 'info'">
{{ refund.commission_deducted ? '是' : '否' }}
</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="退款原因">
{{ refund.refund_reason || '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="拒绝原因">
{{ refund.reject_reason || '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="审批时间">
{{ refund.processed_at ? formatDateTime(refund.processed_at) : '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="审批备注">
{{ refund.remark || '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="创建时间">
{{ formatDateTime(refund.created_at) }}
</ElDescriptionsItem>
<ElDescriptionsItem label="更新时间">
{{ formatDateTime(refund.updated_at) }}
</ElDescriptionsItem>
</ElDescriptions>
<div class="action-buttons" v-if="refund">
<!-- 待审批状态显示审批操作 -->
<template v-if="refund.status === 1">
<ElButton type="primary" @click="handleShowApprove">审批通过</ElButton>
<ElButton type="danger" @click="handleShowReject">审批拒绝</ElButton>
<ElButton type="warning" @click="handleShowReturn">退回</ElButton>
</template>
<!-- 已拒绝或已退回状态显示重新提交 -->
<template v-if="refund.status === 3 || refund.status === 4">
<ElButton type="primary" @click="handleShowResubmit">重新提交</ElButton>
</template>
<!-- 加载中 -->
<div v-if="loading" class="loading-container">
<ElIcon class="is-loading"><Loading /></ElIcon>
<span>加载中...</span>
</div>
</ElCard>
@@ -247,11 +194,13 @@
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ref, onMounted, computed, h } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElCard, ElButton, ElIcon, ElMessage, ElTag } from 'element-plus'
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
import DetailPage from '@/components/common/DetailPage.vue'
import type { DetailSection } from '@/components/common/DetailPage.vue'
import { RefundService } from '@/api/modules'
import { ElMessage, ElTag } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import type {
Refund,
RefundStatus,
@@ -261,38 +210,39 @@
ResubmitRefundRequest
} from '@/types/api'
import { formatDateTime } from '@/utils/business/format'
import { RoutesAlias } from '@/router/routesAlias'
defineOptions({ name: 'RefundDetail' })
const router = useRouter()
const route = useRoute()
const router = useRouter()
const loading = ref(false)
const approveLoading = ref(false)
const rejectLoading = ref(false)
const returnLoading = ref(false)
const resubmitLoading = ref(false)
const refund = ref<Refund | null>(null)
const pageTitle = computed(() => `退款详情`)
const approveDialogVisible = ref(false)
const rejectDialogVisible = ref(false)
const returnDialogVisible = ref(false)
const resubmitDialogVisible = ref(false)
const approveFormRef = ref<FormInstance>()
const rejectFormRef = ref<FormInstance>()
const returnFormRef = ref<FormInstance>()
const resubmitFormRef = ref<FormInstance>()
const approveLoading = ref(false)
const rejectLoading = ref(false)
const returnLoading = ref(false)
const resubmitLoading = ref(false)
const approveRules = reactive<FormRules>({})
const approveFormRef = ref()
const rejectFormRef = ref()
const returnFormRef = ref()
const resubmitFormRef = ref()
const rejectRules = reactive<FormRules>({
const approveRules = ref()
const rejectRules = ref({
reject_reason: [{ required: true, message: '请输入拒绝原因', trigger: 'blur' }]
})
const returnRules = reactive<FormRules>({})
const resubmitRules = reactive<FormRules>({})
const returnRules = ref()
const resubmitRules = ref()
const approveForm = reactive<ApproveRefundRequest>({
approved_refund_amount: undefined,
@@ -317,23 +267,20 @@
refund_reason: ''
})
// 格式化货币 - 将分转换为元
const formatCurrency = (amount: number): string => {
return `¥${(amount / 100).toFixed(2)}`
}
// 获取状态标签类型
const getStatusType = (status: RefundStatus): 'warning' | 'success' | 'danger' | 'info' => {
const statusMap: Record<RefundStatus, 'warning' | 'success' | 'danger' | 'info'> = {
1: 'warning', // 待审批
2: 'success', // 已通过
3: 'danger', // 已拒绝
4: 'info' // 已退回
1: 'warning',
2: 'success',
3: 'danger',
4: 'info'
}
return statusMap[status] || 'info'
}
// 获取状态文本
const getStatusText = (status: RefundStatus): string => {
const statusMap: Record<RefundStatus, string> = {
1: '待审批',
@@ -344,14 +291,94 @@
return statusMap[status] || '-'
}
onMounted(() => {
const id = route.params.id as string
if (id) {
fetchRefundDetail(Number(id))
const detailSections = computed((): DetailSection[] => [
{
title: '退款信息',
fields: [
{ label: '退款单号', prop: 'refund_no' },
{ label: '店铺名称', prop: 'shop_name' },
{ label: '订单号', prop: 'order_no' },
{ label: '资产标识符', prop: 'asset_identifier' },
{ label: '资产类型', prop: 'asset_type' },
{
label: '申请退款金额',
formatter: (_, data) => formatCurrency(data.requested_refund_amount)
},
{
label: '实际退款金额',
formatter: (_, data) =>
data.approved_refund_amount ? formatCurrency(data.approved_refund_amount) : '-'
},
{
label: '实收金额',
formatter: (_, data) => formatCurrency(data.actual_received_amount)
},
{
label: '状态',
render: (data) =>
h(ElTag, { type: getStatusType(data.status) }, () => getStatusText(data.status))
},
{
label: '资产重置',
render: (data) =>
h(ElTag, { type: data.asset_reset ? 'success' : 'info' }, () =>
data.asset_reset ? '是' : '否'
)
},
{
label: '佣金扣除',
render: (data) =>
h(ElTag, { type: data.commission_deducted ? 'success' : 'info' }, () =>
data.commission_deducted ? '是' : '否'
)
}
]
},
{
title: '退款原因',
fields: [
{
label: '退款原因',
prop: 'refund_reason',
formatter: (value) => value || '-',
fullWidth: true
},
{
label: '拒绝原因',
prop: 'reject_reason',
formatter: (value) => value || '-',
fullWidth: true
},
{
label: '审批备注',
prop: 'remark',
formatter: (value) => value || '-',
fullWidth: true
}
]
},
{
title: '时间信息',
fields: [
{
label: '创建时间',
prop: 'created_at',
formatter: (value) => formatDateTime(value)
},
{
label: '审批时间',
prop: 'processed_at',
formatter: (value) => (value ? formatDateTime(value) : '-')
},
{
label: '更新时间',
prop: 'updated_at',
formatter: (value) => formatDateTime(value)
}
]
}
})
])
// 获取退款详情
const fetchRefundDetail = async (id: number) => {
loading.value = true
try {
@@ -366,24 +393,40 @@
}
}
// 返回
const handleGoBack = () => {
router.back()
const handleBack = () => {
router.push(RoutesAlias.RefundManagement)
}
// 显示审批通过对话框
const handleShowApprove = () => {
approveDialogVisible.value = true
}
onMounted(() => {
const id = route.params.id as string
if (id) {
fetchRefundDetail(Number(id))
}
})
// 审批通过对话框关闭后的清理
const handleApproveDialogClosed = () => {
approveFormRef.value?.resetFields()
approveForm.approved_refund_amount = undefined
approveForm.remark = ''
}
// 审批通过
const handleRejectDialogClosed = () => {
rejectFormRef.value?.resetFields()
rejectForm.reject_reason = ''
}
const handleReturnDialogClosed = () => {
returnFormRef.value?.resetFields()
returnForm.remark = ''
}
const handleResubmitDialogClosed = () => {
resubmitFormRef.value?.resetFields()
resubmitForm.requested_refund_amount = undefined
resubmitForm.actual_received_amount = undefined
resubmitForm.refund_reason = ''
}
const handleApproveRefund = async () => {
if (!approveFormRef.value || !refund.value) return
@@ -411,18 +454,6 @@
})
}
// 显示审批拒绝对话框
const handleShowReject = () => {
rejectDialogVisible.value = true
}
// 审批拒绝对话框关闭后的清理
const handleRejectDialogClosed = () => {
rejectFormRef.value?.resetFields()
rejectForm.reject_reason = ''
}
// 审批拒绝
const handleRejectRefund = async () => {
if (!rejectFormRef.value || !refund.value) return
@@ -443,18 +474,6 @@
})
}
// 显示退回对话框
const handleShowReturn = () => {
returnDialogVisible.value = true
}
// 退回对话框关闭后的清理
const handleReturnDialogClosed = () => {
returnFormRef.value?.resetFields()
returnForm.remark = ''
}
// 退回
const handleReturnRefund = async () => {
if (!returnFormRef.value || !refund.value) return
@@ -475,25 +494,6 @@
})
}
// 显示重新提交对话框
const handleShowResubmit = () => {
if (!refund.value) return
// 预填充原有数据
resubmitForm.requested_refund_amount = refund.value.requested_refund_amount / 100
resubmitForm.actual_received_amount = refund.value.actual_received_amount / 100
resubmitForm.refund_reason = refund.value.refund_reason
resubmitDialogVisible.value = true
}
// 重新提交对话框关闭后的清理
const handleResubmitDialogClosed = () => {
resubmitFormRef.value?.resetFields()
resubmitForm.requested_refund_amount = undefined
resubmitForm.actual_received_amount = undefined
resubmitForm.refund_reason = ''
}
// 重新提交
const handleResubmitRefund = async () => {
if (!resubmitFormRef.value || !refund.value) return
@@ -529,17 +529,32 @@
.refund-detail-page {
padding: 20px;
.card-header {
.detail-header {
display: flex;
gap: 16px;
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
.detail-title {
margin: 0;
font-size: 20px;
font-weight: 600;
color: var(--el-text-color-primary);
}
}
.action-buttons {
.loading-container {
display: flex;
gap: 10px;
justify-content: flex-end;
margin-top: 20px;
flex-direction: column;
gap: 12px;
align-items: center;
justify-content: center;
padding: 60px 0;
color: var(--el-text-color-secondary);
.el-icon {
font-size: 32px;
}
}
}
</style>

View File

@@ -62,7 +62,6 @@
:loading="orderSearchLoading"
placeholder="请输入订单号搜索"
style="width: 100%"
@focus="handleOrderSelectFocus"
@change="handleOrderSelectChange"
>
<ElOption
@@ -84,11 +83,7 @@
/>
</ElFormItem>
<ElFormItem label="实收金额">
<ElInput
:model-value="selectedOrderActualPaid"
disabled
style="width: 100%"
/>
<ElInput :model-value="selectedOrderActualPaid" disabled style="width: 100%" />
</ElFormItem>
<ElFormItem label="退款原因">
<ElInput
@@ -315,7 +310,6 @@
defineOptions({ name: 'RefundList' })
const router = useRouter()
const userStore = useUserStore()
const { hasAuth } = useAuth()
const loading = ref(false)
@@ -364,7 +358,26 @@
})),
config: {
clearable: true,
filterable: true
filterable: true,
remote: true,
remoteMethod: (query: string) => searchShops(query)
}
},
{
label: '订单号',
prop: 'order_id',
type: 'select',
placeholder: '请选择订单号',
options: () =>
orderOptions.value.map((order) => ({
label: `${order.order_no}`,
value: order.id
})),
config: {
clearable: true,
filterable: true,
remote: true,
remoteMethod: (query: string) => searchOrdersForFilter(query)
}
},
{
@@ -381,21 +394,6 @@
config: {
clearable: true
}
},
{
label: '订单',
prop: 'order_id',
type: 'select',
placeholder: '请选择订单',
options: () =>
orderOptions.value.map((order) => ({
label: `订单号: ${order.order_no} (ID: ${order.id})`,
value: order.id
})),
config: {
clearable: true,
filterable: true
}
}
]
@@ -409,8 +407,10 @@
// 列配置
const columnOptions = [
{ label: '退款单号', prop: 'refund_no' },
{ label: '订单ID', prop: 'order_id' },
{ label: '店铺ID', prop: 'shop_id' },
{ label: '店铺名称', prop: 'shop_name' },
{ label: '订单号', prop: 'order_no' },
{ label: '资产标识符', prop: 'asset_identifier' },
{ label: '资产类型', prop: 'asset_type' },
{ label: '申请退款金额', prop: 'requested_refund_amount' },
{ label: '实际退款金额', prop: 'approved_refund_amount' },
{ label: '实收金额', prop: 'actual_received_amount' },
@@ -523,7 +523,7 @@
{
prop: 'refund_no',
label: '退款单号',
minWidth: 240,
minWidth: 210,
formatter: (row: Refund) => {
return h(
'span',
@@ -531,7 +531,7 @@
style: 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;',
onClick: (e: MouseEvent) => {
e.stopPropagation()
handleViewDetail(row)
handleNameClick(row)
}
},
row.refund_no
@@ -539,14 +539,30 @@
}
},
{
prop: 'order_id',
label: '订单ID',
width: 120
prop: 'shop_name',
label: '店铺名称',
width: 160
},
{
prop: 'shop_id',
label: '店铺ID',
width: 120
prop: 'order_no',
label: '订单号',
width: 220
},
{
prop: 'asset_identifier',
label: '资产标识符',
width: 180
},
{
prop: 'asset_type',
label: '资产类型',
width: 100,
formatter: (row: Refund) =>
row.asset_type === 'device'
? '设备'
: row.asset_type === 'iot_card'
? 'IoT卡'
: row.asset_type || '-'
},
{
prop: 'requested_refund_amount',
@@ -629,39 +645,45 @@
onMounted(() => {
getTableData()
loadShops()
loadOrders()
searchShops('')
searchOrdersForFilter('')
})
// 加载店铺列表
const loadShops = async () => {
// 搜索店铺(用于搜索表单)
const searchShops = async (query: string) => {
try {
const params: any = {
page: 1,
page_size: 9999
page_size: 20
}
if (query) {
params.shop_name = query
}
const res = await ShopService.getShops(params)
if (res.code === 0) {
shopOptions.value = res.data.items || []
}
} catch (error) {
console.error('Load shops failed:', error)
console.error('Search shops failed:', error)
}
}
// 加载订单列表
const loadOrders = async () => {
// 搜索订单(用于搜索表单)
const searchOrdersForFilter = async (query: string) => {
try {
const params: any = {
page: 1,
page_size: 9999
page_size: 20
}
if (query) {
params.order_no = query
}
const res = await OrderService.getOrders(params)
if (res.code === 0) {
orderOptions.value = res.data.items || []
}
} catch (error) {
console.error('Load orders failed:', error)
console.error('Search orders failed:', error)
}
}
@@ -759,14 +781,6 @@
createDialogVisible.value = true
}
// 订单选择框获取焦点时加载默认数据
const handleOrderSelectFocus = () => {
// 如果还没有数据则加载默认的20条
if (orderSearchOptions.value.length === 0) {
searchOrders('')
}
}
// 对话框关闭后的清理
const handleCreateDialogClosed = () => {
createFormRef.value?.resetFields()
@@ -965,6 +979,15 @@
})
}
// 处理名称点击
const handleNameClick = (row: Refund) => {
if (hasAuth('refund:detail')) {
handleViewDetail(row)
} else {
ElMessage.warning('您没有查看详情的权限')
}
}
// 查看详情
const handleViewDetail = (row: Refund) => {
router.push({