1362 lines
42 KiB
Vue
1362 lines
42 KiB
Vue
<template>
|
||
<ArtTableFullScreen>
|
||
<div class="agent-recharge-page" id="table-full-screen">
|
||
<!-- 搜索栏 -->
|
||
<ArtSearchBar
|
||
v-model:filter="searchForm"
|
||
:items="searchFormItems"
|
||
:show-expand="false"
|
||
@reset="handleReset"
|
||
@search="handleSearch"
|
||
></ArtSearchBar>
|
||
|
||
<ElCard shadow="never" class="art-table-card">
|
||
<!-- 表格头部 -->
|
||
<ArtTableHeader
|
||
:columnList="columnOptions"
|
||
v-model:columns="columnChecks"
|
||
@refresh="handleRefresh"
|
||
>
|
||
<template #left>
|
||
<ElButton
|
||
type="primary"
|
||
@click="showCreateDialog"
|
||
v-if="hasAuth('agent_recharge:create') && canCreateRecharge"
|
||
>{{ createButtonLabel }}</ElButton
|
||
>
|
||
<ElButton v-if="hasAuth('agent_recharge:export')" @click="exportDialogVisible = true">
|
||
导出
|
||
</ElButton>
|
||
</template>
|
||
</ArtTableHeader>
|
||
|
||
<!-- 表格 -->
|
||
<ArtTable
|
||
ref="tableRef"
|
||
row-key="id"
|
||
:loading="loading"
|
||
:data="rechargeList"
|
||
:currentPage="pagination.page"
|
||
:pageSize="pagination.page_size"
|
||
:total="pagination.total"
|
||
:marginTop="10"
|
||
:actions="getActions"
|
||
:inlineActionsCount="2"
|
||
:actionsWidth="200"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
>
|
||
<template #default>
|
||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||
</template>
|
||
</ArtTable>
|
||
|
||
<!-- 创建充值订单对话框 -->
|
||
<ElDialog
|
||
v-model="createDialogVisible"
|
||
:title="createDialogTitle"
|
||
width="500px"
|
||
@closed="handleCreateDialogClosed"
|
||
>
|
||
<ElForm ref="createFormRef" :model="createForm" :rules="createRules" label-width="100px">
|
||
<ElFormItem label="充值金额" prop="amount">
|
||
<ElInputNumber
|
||
v-model="createForm.amount"
|
||
:min="minimumAmountYuan"
|
||
:max="maximumAmountYuan"
|
||
:precision="2"
|
||
:step="0.01"
|
||
style="width: 100%"
|
||
placeholder="请输入充值金额(元)"
|
||
/>
|
||
<div style="margin-top: 8px; font-size: 12px; color: var(--el-text-color-secondary)">
|
||
金额范围:¥{{ minimumAmountYuan.toFixed(2) }} - ¥{{
|
||
maximumAmountYuan.toLocaleString('zh-CN', { minimumFractionDigits: 2 })
|
||
}}
|
||
</div>
|
||
</ElFormItem>
|
||
<ElFormItem label="支付方式" prop="payment_method">
|
||
<ElSelect
|
||
v-model="createForm.payment_method"
|
||
placeholder="请选择支付方式"
|
||
style="width: 100%"
|
||
:loading="paymentMethodsLoading"
|
||
>
|
||
<ElOption
|
||
v-for="option in availablePaymentMethodOptions"
|
||
:key="option.value"
|
||
:label="option.label"
|
||
:value="option.value"
|
||
/>
|
||
</ElSelect>
|
||
<div
|
||
v-if="
|
||
createMode === 'online' &&
|
||
!paymentMethodsLoading &&
|
||
onlinePaymentMethods.length === 0
|
||
"
|
||
class="online-recharge-empty-hint"
|
||
>
|
||
当前暂无可用在线支付方式,暂时无法提交充值。
|
||
</div>
|
||
</ElFormItem>
|
||
<ElFormItem v-if="createMode === 'offline'" label="店铺" prop="shop_id">
|
||
<ElCascader
|
||
v-model="createForm.shop_id"
|
||
:options="shopCascadeOptions"
|
||
:props="shopCascadeProps"
|
||
placeholder="请选择店铺"
|
||
filterable
|
||
clearable
|
||
style="width: 100%"
|
||
@change="handleShopChange"
|
||
/>
|
||
</ElFormItem>
|
||
<ElFormItem
|
||
v-if="createForm.payment_method === 'offline'"
|
||
label="支付凭证"
|
||
prop="payment_voucher_key"
|
||
>
|
||
<VoucherUpload
|
||
ref="uploadRef"
|
||
v-model="createForm.payment_voucher_key"
|
||
voucher-name="支付凭证"
|
||
@uploading-change="voucherUploading = $event"
|
||
@change="createFormRef?.validateField('payment_voucher_key')"
|
||
/>
|
||
</ElFormItem>
|
||
<ElFormItem v-if="createMode === 'offline'" label="运营备注" prop="remark">
|
||
<ElInput
|
||
v-model="createForm.remark"
|
||
type="textarea"
|
||
:rows="3"
|
||
maxlength="1000"
|
||
show-word-limit
|
||
placeholder="请输入运营备注(可选)"
|
||
/>
|
||
</ElFormItem>
|
||
</ElForm>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<ElButton @click="createDialogVisible = false">取消</ElButton>
|
||
<ElButton
|
||
type="primary"
|
||
@click="handleCreateRecharge"
|
||
:loading="createLoading || voucherUploading || paymentMethodsLoading"
|
||
:disabled="createSubmitDisabled"
|
||
>
|
||
{{ voucherUploading ? '凭证上传中...' : createButtonLabel }}
|
||
</ElButton>
|
||
</div>
|
||
</template>
|
||
</ElDialog>
|
||
|
||
<!-- 在线充值二维码对话框 -->
|
||
<ElDialog
|
||
v-model="onlineQrDialogVisible"
|
||
title="扫码完成充值"
|
||
width="430px"
|
||
align-center
|
||
@closed="handleQrDialogClosed"
|
||
>
|
||
<div class="online-recharge-qr-dialog">
|
||
<QrcodeVue
|
||
v-if="qrContent"
|
||
:value="qrContent"
|
||
:size="240"
|
||
level="H"
|
||
render-as="canvas"
|
||
/>
|
||
<ElEmpty v-else description="暂未获取到支付二维码" />
|
||
<div v-if="onlineQrRecharge" class="online-recharge-qr-dialog__summary">
|
||
<div>充值单号:{{ onlineQrRecharge.recharge_no || '-' }}</div>
|
||
<div>充值金额:{{ formatCurrency(onlineQrRecharge.amount) }}</div>
|
||
<div v-if="onlineWalletBalance !== null">
|
||
当前主钱包余额:{{ formatCurrency(onlineWalletBalance) }}
|
||
</div>
|
||
<ElTag :type="getStatusType(onlinePaymentStatus?.status || onlineQrRecharge.status)">
|
||
{{ onlinePaymentStatus?.status_name || onlineQrRecharge.status_name || '-' }}
|
||
</ElTag>
|
||
<div class="online-recharge-qr-dialog__hint">
|
||
{{ onlinePaymentStatusMessage }}
|
||
</div>
|
||
<div v-if="paymentStatusLoading" class="online-recharge-qr-dialog__loading">
|
||
正在查询支付状态...
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<template #footer>
|
||
<ElButton @click="onlineQrDialogVisible = false">关闭</ElButton>
|
||
</template>
|
||
</ElDialog>
|
||
|
||
<!-- 导出任务对话框 -->
|
||
<ExportTaskCreateDialog
|
||
v-model="exportDialogVisible"
|
||
scene="agent_recharge"
|
||
:query="exportQuery"
|
||
confirm-permission="agent_recharge:export"
|
||
title="导出代理充值"
|
||
/>
|
||
|
||
<!-- 确认线下支付对话框 -->
|
||
<ElDialog
|
||
v-model="confirmPayDialogVisible"
|
||
title="确认线下充值"
|
||
width="25%"
|
||
@closed="handleConfirmPayDialogClosed"
|
||
>
|
||
<ElForm
|
||
ref="confirmPayFormRef"
|
||
:model="confirmPayForm"
|
||
:rules="confirmPayRules"
|
||
label-width="80"
|
||
>
|
||
<ElFormItem label="充值单号">
|
||
<span>{{ currentRecharge?.recharge_no }}</span>
|
||
</ElFormItem>
|
||
<ElFormItem label="充值金额">
|
||
<span>{{ formatCurrency(currentRecharge?.amount || 0) }}</span>
|
||
</ElFormItem>
|
||
<ElFormItem label="操作密码" prop="operation_password">
|
||
<ElInput
|
||
v-model="confirmPayForm.operation_password"
|
||
type="password"
|
||
placeholder="请输入超级管理员统一设置的操作密码"
|
||
show-password
|
||
/>
|
||
</ElFormItem>
|
||
</ElForm>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<ElButton @click="confirmPayDialogVisible = false">取消</ElButton>
|
||
<ElButton type="primary" @click="handleConfirmPay" :loading="confirmPayLoading">
|
||
确认支付
|
||
</ElButton>
|
||
</div>
|
||
</template>
|
||
</ElDialog>
|
||
|
||
<!-- 拒绝充值订单对话框 -->
|
||
<ElDialog
|
||
v-model="rejectDialogVisible"
|
||
title="拒绝充值订单"
|
||
width="500px"
|
||
@closed="handleRejectDialogClosed"
|
||
>
|
||
<ElForm ref="rejectFormRef" :model="rejectForm" :rules="rejectRules" label-width="100px">
|
||
<ElFormItem label="充值单号">
|
||
<span>{{ currentRecharge?.recharge_no }}</span>
|
||
</ElFormItem>
|
||
<ElFormItem label="拒绝原因" prop="rejection_reason">
|
||
<ElInput
|
||
v-model="rejectForm.rejection_reason"
|
||
type="textarea"
|
||
:rows="3"
|
||
maxlength="500"
|
||
show-word-limit
|
||
placeholder="请输入拒绝原因"
|
||
/>
|
||
</ElFormItem>
|
||
</ElForm>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<ElButton @click="rejectDialogVisible = false">取消</ElButton>
|
||
<ElButton type="danger" @click="handleRejectRecharge" :loading="rejectLoading">
|
||
确认拒绝
|
||
</ElButton>
|
||
</div>
|
||
</template>
|
||
</ElDialog>
|
||
|
||
<!-- 支付凭证预览 -->
|
||
<PaymentVoucherDialog
|
||
:file-keys="paymentVoucherFileKeys"
|
||
@close="paymentVoucherFileKeys = []"
|
||
/>
|
||
</ElCard>
|
||
</div>
|
||
</ArtTableFullScreen>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { h } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import QrcodeVue from 'qrcode.vue'
|
||
import { AgentRechargeService, CommissionService, ShopService } from '@/api/modules'
|
||
import {
|
||
ElMessage,
|
||
ElTag,
|
||
ElButton,
|
||
ElCascader,
|
||
ElInput,
|
||
ElInputNumber,
|
||
ElSelect,
|
||
ElOption
|
||
} from 'element-plus'
|
||
import type { FormInstance, FormRules } from 'element-plus'
|
||
import type {
|
||
AgentRecharge,
|
||
AgentRechargeQueryParams,
|
||
AgentRechargeStatus,
|
||
AgentRechargeOnlinePaymentMethod,
|
||
AgentRechargePaymentMethod,
|
||
AgentRechargePaymentStatusResponse,
|
||
CreateAgentRechargeRequest,
|
||
ConfirmOfflinePaymentRequest,
|
||
RejectAgentRechargeRequest
|
||
} from '@/types/api'
|
||
import type { SearchFormItem } from '@/types'
|
||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||
import { formatDateTime } from '@/utils/business/format'
|
||
import { normalizeApiError } from '@/utils/business/apiError'
|
||
import {
|
||
getApprovalStatusText,
|
||
getCurrentApproverSummaryText,
|
||
getProcessingStatusText
|
||
} from '@/utils/business/approvalSummary'
|
||
import { hasVoucherKeys, toVoucherKeyList } from '@/utils/business'
|
||
import { useAuth } from '@/composables/useAuth'
|
||
import { useUserStore } from '@/store/modules/user'
|
||
import PaymentVoucherDialog from '@/components/business/PaymentVoucherDialog.vue'
|
||
import VoucherUpload from '@/components/business/VoucherUpload.vue'
|
||
import ExportTaskCreateDialog from '@/components/business/ExportTaskCreateDialog.vue'
|
||
import { buildAgentRechargeActions } from './agentRechargeActions'
|
||
import { formatRejectionReason } from './agentRechargeDisplay'
|
||
import {
|
||
amountYuanToFen,
|
||
createOnlineRechargeRequestId,
|
||
isOnlineRechargeTerminal,
|
||
shouldRetryOnlineCreate
|
||
} from './agentRechargeOnline'
|
||
|
||
defineOptions({ name: 'AgentRechargeList' })
|
||
|
||
const router = useRouter()
|
||
const { hasAuth } = useAuth()
|
||
const userStore = useUserStore()
|
||
|
||
const isAgentAccount = computed(() => Number(userStore.info.user_type) === 3)
|
||
const isPlatformAccount = computed(() => [1, 2].includes(Number(userStore.info.user_type)))
|
||
const canViewRecharge = computed(() => [1, 2, 3].includes(Number(userStore.info.user_type)))
|
||
const canCreateRecharge = computed(() => isAgentAccount.value || isPlatformAccount.value)
|
||
const createMode = ref<'online' | 'offline'>('offline')
|
||
const createDialogTitle = computed(() =>
|
||
createMode.value === 'online' ? '代理钱包在线扫码充值' : '创建平台线下代充'
|
||
)
|
||
const createButtonLabel = computed(() =>
|
||
createMode.value === 'online' ? '立即充值' : '创建充值订单'
|
||
)
|
||
|
||
const loading = ref(false)
|
||
const createLoading = ref(false)
|
||
const voucherUploading = ref(false)
|
||
const confirmPayLoading = ref(false)
|
||
const rejectLoading = ref(false)
|
||
const tableRef = ref()
|
||
const createDialogVisible = ref(false)
|
||
const exportDialogVisible = ref(false)
|
||
const confirmPayDialogVisible = ref(false)
|
||
const rejectDialogVisible = ref(false)
|
||
const onlineQrDialogVisible = ref(false)
|
||
const currentRecharge = ref<AgentRecharge | null>(null)
|
||
const onlineQrRecharge = ref<AgentRecharge | null>(null)
|
||
const onlinePaymentStatus = ref<AgentRechargePaymentStatusResponse | null>(null)
|
||
const onlineWalletBalance = ref<number | null>(null)
|
||
const onlinePaymentMethods = ref<AgentRechargeOnlinePaymentMethod[]>([])
|
||
const paymentMethodsLoading = ref(false)
|
||
const paymentStatusLoading = ref(false)
|
||
const qrContent = ref('')
|
||
const onlineRequestId = ref<string | null>(null)
|
||
const onlineCreateRetried = ref(false)
|
||
const paymentStatusTimer = ref<ReturnType<typeof setInterval> | null>(null)
|
||
const paymentMethodsBounds = reactive({
|
||
min_amount: 10000,
|
||
max_amount: 100000000
|
||
})
|
||
const paymentVoucherFileKeys = ref<string[]>([])
|
||
|
||
// 搜索表单初始值
|
||
const initialSearchState: AgentRechargeQueryParams = {
|
||
shop_id: undefined,
|
||
status: undefined,
|
||
recharge_source: undefined,
|
||
dateRange: [],
|
||
start_date: '',
|
||
end_date: ''
|
||
}
|
||
|
||
// 搜索表单
|
||
const searchForm = reactive<AgentRechargeQueryParams>({ ...initialSearchState })
|
||
|
||
// 店铺选项
|
||
const shopOptions = ref<any[]>([])
|
||
// 店铺级联选择相关
|
||
const shopCascadeOptions = ref<any[]>([])
|
||
const shopCascadeProps = {
|
||
lazy: true,
|
||
checkStrictly: true,
|
||
lazyLoad: async (node: any, resolve: any) => {
|
||
const { level, value } = node
|
||
const parentId = level === 0 ? undefined : value
|
||
|
||
try {
|
||
const res = await ShopService.getShopsCascade({ parent_id: parentId })
|
||
if (res.code === 0) {
|
||
const nodes = (res.data || []).map((item: any) => ({
|
||
value: item.id,
|
||
label: item.shop_name,
|
||
leaf: !item.has_children
|
||
}))
|
||
resolve(nodes)
|
||
} else {
|
||
resolve([])
|
||
}
|
||
} catch (error) {
|
||
console.error('加载店铺级联数据失败:', error)
|
||
resolve([])
|
||
}
|
||
},
|
||
value: 'value',
|
||
label: 'label',
|
||
children: 'children'
|
||
}
|
||
|
||
// 搜索表单配置
|
||
const searchFormItems = computed<SearchFormItem[]>(() => {
|
||
const items: SearchFormItem[] = []
|
||
|
||
if (isPlatformAccount.value) {
|
||
items.push({
|
||
label: '店铺名称',
|
||
prop: 'shop_id',
|
||
type: 'select',
|
||
placeholder: '请选择店铺',
|
||
options: () =>
|
||
shopOptions.value.map((shop) => ({
|
||
label: shop.shop_name,
|
||
value: shop.id
|
||
})),
|
||
config: {
|
||
clearable: true,
|
||
filterable: true,
|
||
remote: true,
|
||
remoteMethod: (query: string) => searchShops(query)
|
||
}
|
||
})
|
||
}
|
||
|
||
items.push(
|
||
{
|
||
label: '充值状态',
|
||
prop: 'status',
|
||
type: 'select',
|
||
placeholder: '请选择状态',
|
||
options: [
|
||
{ label: '待支付', value: 1 },
|
||
{ label: '已支付', value: 2 },
|
||
{ label: '已完成', value: 3 },
|
||
{ label: '已关闭', value: 4 },
|
||
{ label: '已退款', value: 5 },
|
||
{ label: '已驳回', value: 6 }
|
||
],
|
||
config: { clearable: true }
|
||
},
|
||
{
|
||
label: '充值来源',
|
||
prop: 'recharge_source',
|
||
type: 'select',
|
||
placeholder: '请选择充值来源',
|
||
options: [
|
||
{ label: '代理在线自充', value: 'agent_online' },
|
||
{ label: '平台线下代充', value: 'platform_offline' }
|
||
],
|
||
config: { clearable: true }
|
||
},
|
||
{
|
||
label: '起止时间',
|
||
prop: 'dateRange',
|
||
type: 'date',
|
||
config: {
|
||
type: 'daterange',
|
||
rangeSeparator: '至',
|
||
startPlaceholder: '开始日期',
|
||
endPlaceholder: '结束日期',
|
||
valueFormat: 'YYYY-MM-DD'
|
||
}
|
||
}
|
||
)
|
||
|
||
return items
|
||
})
|
||
|
||
// 分页
|
||
const pagination = reactive({
|
||
page: 1,
|
||
page_size: 20,
|
||
total: 0
|
||
})
|
||
|
||
// 列配置
|
||
const columnOptions = [
|
||
{ label: '充值单号', prop: 'recharge_no' },
|
||
{ label: '店铺名称', prop: 'shop_name' },
|
||
{ label: '充值来源', prop: 'recharge_source' },
|
||
{ label: '充值金额', prop: 'amount' },
|
||
{ label: '状态', prop: 'status' },
|
||
{ label: '审批渠道', prop: 'approval_provider' },
|
||
{ label: '提交人', prop: 'submitter_name' },
|
||
{ label: '审批状态', prop: 'approval_status' },
|
||
{ label: '当前审批人摘要', prop: 'current_approver_summary' },
|
||
{ label: '业务处理状态', prop: 'processing_status_name' },
|
||
{ label: '支付方式', prop: 'payment_method' },
|
||
{ label: '支付通道', prop: 'payment_channel' },
|
||
{ label: '运营备注', prop: 'remark' },
|
||
{ label: '驳回原因', prop: 'rejection_reason' },
|
||
{ label: '创建时间', prop: 'created_at' },
|
||
{ label: '支付时间', prop: 'paid_at' },
|
||
{ label: '完成时间', prop: 'completed_at' },
|
||
{ label: '更新时间', prop: 'updated_at' }
|
||
]
|
||
|
||
const createFormRef = ref<FormInstance>()
|
||
const confirmPayFormRef = ref<FormInstance>()
|
||
const rejectFormRef = ref<FormInstance>()
|
||
const uploadRef = ref<InstanceType<typeof VoucherUpload>>()
|
||
const OFFLINE_MIN_RECHARGE_AMOUNT = 0.01
|
||
const OFFLINE_MAX_RECHARGE_AMOUNT = 1_000_000
|
||
|
||
const minimumAmountYuan = computed(() =>
|
||
createMode.value === 'online'
|
||
? paymentMethodsBounds.min_amount / 100
|
||
: OFFLINE_MIN_RECHARGE_AMOUNT
|
||
)
|
||
const maximumAmountYuan = computed(() =>
|
||
createMode.value === 'online'
|
||
? paymentMethodsBounds.max_amount / 100
|
||
: OFFLINE_MAX_RECHARGE_AMOUNT
|
||
)
|
||
const availablePaymentMethodOptions = computed(() => {
|
||
if (createMode.value === 'offline') return [{ label: '线下转账', value: 'offline' }]
|
||
|
||
return onlinePaymentMethods.value.map((method) => ({
|
||
label: method === 'wechat' ? '微信支付' : '支付宝',
|
||
value: method
|
||
}))
|
||
})
|
||
const createSubmitDisabled = computed(
|
||
() =>
|
||
voucherUploading.value ||
|
||
paymentMethodsLoading.value ||
|
||
(createMode.value === 'online' && onlinePaymentMethods.value.length === 0)
|
||
)
|
||
const onlinePaymentStatusMessage = computed(() => {
|
||
const status = onlinePaymentStatus.value?.status ?? onlineQrRecharge.value?.status
|
||
if (status === 1) return '请使用对应支付方式扫码完成支付'
|
||
if (status === 2) return '支付已成功,钱包正在入账,请稍候'
|
||
if (status === 3) return '充值成功,钱包已到账'
|
||
if (status === 4) return '充值订单已关闭,请重新发起充值'
|
||
if (status === 5) return '充值订单已退款'
|
||
if (status === 6) return '充值订单已驳回'
|
||
return '正在获取支付状态'
|
||
})
|
||
|
||
const createRules = computed<FormRules>(() => {
|
||
const rules: FormRules = {
|
||
amount: [
|
||
{ required: true, message: '请输入充值金额', trigger: 'blur' },
|
||
{
|
||
validator: (_rule, value, callback) => {
|
||
if (value == null || value === '') {
|
||
callback()
|
||
return
|
||
}
|
||
if (Number(value) < minimumAmountYuan.value) {
|
||
callback(new Error(`充值金额最小为 ¥${minimumAmountYuan.value.toFixed(2)}`))
|
||
return
|
||
}
|
||
if (Number(value) > maximumAmountYuan.value) {
|
||
callback(
|
||
new Error(
|
||
`充值金额最大为 ¥${maximumAmountYuan.value.toLocaleString('zh-CN', { minimumFractionDigits: 2 })}`
|
||
)
|
||
)
|
||
return
|
||
}
|
||
callback()
|
||
},
|
||
trigger: 'blur'
|
||
}
|
||
],
|
||
payment_method: [{ required: true, message: '请选择支付方式', trigger: 'change' }],
|
||
shop_id: [{ required: true, message: '请选择目标店铺', trigger: 'change' }]
|
||
}
|
||
if (createMode.value === 'offline') {
|
||
rules.payment_voucher_key = [{ required: true, message: '请上传支付凭证', trigger: 'change' }]
|
||
}
|
||
if (createMode.value === 'online') delete rules.shop_id
|
||
return rules
|
||
})
|
||
|
||
const confirmPayRules = reactive<FormRules>({
|
||
operation_password: [
|
||
{ required: true, message: '请输入超级管理员统一设置的操作密码', trigger: 'blur' }
|
||
]
|
||
})
|
||
|
||
const rejectRules = reactive<FormRules>({
|
||
rejection_reason: [{ required: true, message: '请输入拒绝原因', trigger: 'blur' }]
|
||
})
|
||
|
||
const createForm = reactive<{
|
||
amount: number | null
|
||
payment_method: AgentRechargePaymentMethod | ''
|
||
shop_id: number | null
|
||
payment_voucher_key: string[]
|
||
remark: string
|
||
}>({
|
||
amount: OFFLINE_MIN_RECHARGE_AMOUNT,
|
||
payment_method: '',
|
||
shop_id: null,
|
||
payment_voucher_key: [],
|
||
remark: ''
|
||
})
|
||
|
||
const confirmPayForm = reactive<ConfirmOfflinePaymentRequest>({
|
||
operation_password: ''
|
||
})
|
||
|
||
const rejectForm = reactive<RejectAgentRechargeRequest>({
|
||
rejection_reason: ''
|
||
})
|
||
|
||
const rechargeList = ref<AgentRecharge[]>([])
|
||
|
||
// 格式化货币 - 将分转换为元
|
||
const formatCurrency = (amount: number): string => {
|
||
return `¥${(amount / 100).toFixed(2)}`
|
||
}
|
||
|
||
// 获取状态标签类型
|
||
const getStatusType = (
|
||
status: AgentRechargeStatus
|
||
): 'warning' | 'success' | 'info' | 'danger' => {
|
||
const statusMap: Record<AgentRechargeStatus, 'warning' | 'success' | 'info' | 'danger'> = {
|
||
1: 'warning', // 待支付
|
||
2: 'success', // 已支付
|
||
3: 'success', // 已完成
|
||
4: 'info', // 已关闭
|
||
5: 'danger', // 已退款
|
||
6: 'danger' // 已驳回
|
||
}
|
||
return statusMap[status] || 'info'
|
||
}
|
||
|
||
// 获取支付方式文本
|
||
const getPaymentMethodText = (method: AgentRechargePaymentMethod): string => {
|
||
const methodMap: Record<AgentRechargePaymentMethod, string> = {
|
||
wechat: '微信在线支付',
|
||
alipay: '支付宝在线支付',
|
||
offline: '线下转账'
|
||
}
|
||
return methodMap[method] || method
|
||
}
|
||
|
||
const getRechargeSourceText = (row: AgentRecharge): string => {
|
||
if (row.recharge_source_name) return row.recharge_source_name
|
||
if (row.recharge_source === 'agent_online') return '代理在线自充'
|
||
if (row.recharge_source === 'platform_offline') return '平台线下代充'
|
||
return '-'
|
||
}
|
||
|
||
// 动态列配置
|
||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||
{
|
||
prop: 'recharge_no',
|
||
label: '充值单号',
|
||
minWidth: 240,
|
||
formatter: (row: AgentRecharge) => {
|
||
return h(
|
||
'span',
|
||
{
|
||
style: 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;',
|
||
onClick: (e: MouseEvent) => {
|
||
e.stopPropagation()
|
||
handleNameClick(row)
|
||
}
|
||
},
|
||
row.recharge_no
|
||
)
|
||
}
|
||
},
|
||
{
|
||
prop: 'shop_name',
|
||
label: '店铺名称',
|
||
minWidth: 150,
|
||
showOverflowTooltip: true
|
||
},
|
||
{
|
||
prop: 'recharge_source',
|
||
label: '充值来源',
|
||
width: 140,
|
||
formatter: (row: AgentRecharge) => getRechargeSourceText(row)
|
||
},
|
||
{
|
||
prop: 'amount',
|
||
label: '充值金额',
|
||
width: 120,
|
||
formatter: (row: AgentRecharge) => formatCurrency(row.amount)
|
||
},
|
||
{
|
||
prop: 'status',
|
||
label: '状态',
|
||
width: 100,
|
||
formatter: (row: AgentRecharge) => {
|
||
return h(ElTag, { type: getStatusType(row.status) }, () => row.status_name || '-')
|
||
}
|
||
},
|
||
{
|
||
prop: 'approval_provider',
|
||
label: '审批渠道',
|
||
width: 110,
|
||
formatter: (row: AgentRecharge) => {
|
||
if (row.approval_provider === 'wecom' || row.approval_source === 'wecom') return '企微'
|
||
if (row.approval_source === 'legacy') return '历史审批'
|
||
return row.approval_provider || row.approval_source || '-'
|
||
}
|
||
},
|
||
{
|
||
prop: 'submitter_name',
|
||
label: '提交人',
|
||
width: 120,
|
||
showOverflowTooltip: true,
|
||
formatter: (row: AgentRecharge) => row.submitter_name || '-'
|
||
},
|
||
{
|
||
prop: 'approval_status',
|
||
label: '审批状态',
|
||
width: 120,
|
||
formatter: (row: AgentRecharge) => getApprovalStatusText(row)
|
||
},
|
||
{
|
||
prop: 'current_approver_summary',
|
||
label: '当前审批人摘要',
|
||
minWidth: 180,
|
||
showOverflowTooltip: true,
|
||
formatter: (row: AgentRecharge) => getCurrentApproverSummaryText(row)
|
||
},
|
||
{
|
||
prop: 'processing_status_name',
|
||
label: '业务处理状态',
|
||
width: 140,
|
||
showOverflowTooltip: true,
|
||
formatter: (row: AgentRecharge) => getProcessingStatusText(row)
|
||
},
|
||
{
|
||
prop: 'payment_method',
|
||
label: '支付方式',
|
||
width: 120,
|
||
formatter: (row: AgentRecharge) => getPaymentMethodText(row.payment_method)
|
||
},
|
||
{
|
||
prop: 'payment_channel',
|
||
label: '支付通道',
|
||
width: 120,
|
||
formatter: (row: AgentRecharge) => row.payment_channel || '-'
|
||
},
|
||
{
|
||
prop: 'remark',
|
||
label: '运营备注',
|
||
minWidth: 180,
|
||
showOverflowTooltip: true,
|
||
formatter: (row: AgentRecharge) => row.remark || '-'
|
||
},
|
||
{
|
||
prop: 'rejection_reason',
|
||
label: '驳回原因',
|
||
minWidth: 180,
|
||
showOverflowTooltip: true,
|
||
formatter: (row: AgentRecharge) => formatRejectionReason(row.rejection_reason)
|
||
},
|
||
{
|
||
prop: 'created_at',
|
||
label: '创建时间',
|
||
width: 180,
|
||
formatter: (row: AgentRecharge) => formatDateTime(row.created_at)
|
||
},
|
||
{
|
||
prop: 'paid_at',
|
||
label: '支付时间',
|
||
width: 180,
|
||
formatter: (row: AgentRecharge) => (row.paid_at ? formatDateTime(row.paid_at) : '-')
|
||
},
|
||
{
|
||
prop: 'completed_at',
|
||
label: '完成时间',
|
||
width: 180,
|
||
formatter: (row: AgentRecharge) => (row.completed_at ? formatDateTime(row.completed_at) : '-')
|
||
},
|
||
{
|
||
prop: 'updated_at',
|
||
label: '更新时间',
|
||
width: 180,
|
||
formatter: (row: AgentRecharge) => formatDateTime(row.updated_at)
|
||
}
|
||
])
|
||
|
||
onMounted(() => {
|
||
getTableData()
|
||
if (isPlatformAccount.value) loadShops()
|
||
document.addEventListener('visibilitychange', handleDocumentVisibilityChange)
|
||
})
|
||
|
||
onBeforeUnmount(() => {
|
||
stopPaymentStatusPolling()
|
||
document.removeEventListener('visibilitychange', handleDocumentVisibilityChange)
|
||
})
|
||
|
||
onDeactivated(() => {
|
||
stopPaymentStatusPolling()
|
||
})
|
||
|
||
let isFirstActivation = true
|
||
onActivated(() => {
|
||
if (!isFirstActivation) {
|
||
getTableData()
|
||
}
|
||
if (onlineQrDialogVisible.value && document.visibilityState === 'visible') {
|
||
startPaymentStatusPolling()
|
||
}
|
||
isFirstActivation = false
|
||
})
|
||
|
||
// 加载店铺列表 - 改用级联查询
|
||
const loadShops = async () => {
|
||
try {
|
||
// 加载顶级店铺用于级联选择
|
||
const res2 = await ShopService.getShopsCascade({ parent_id: undefined })
|
||
if (res2.code === 0) {
|
||
shopCascadeOptions.value = (res2.data || []).map((item: any) => ({
|
||
value: item.id,
|
||
label: item.shop_name,
|
||
leaf: !item.has_children
|
||
}))
|
||
}
|
||
} catch (error) {
|
||
console.error('Load shops failed:', error)
|
||
}
|
||
}
|
||
|
||
// 搜索店铺(用于搜索表单远程搜索)
|
||
const searchShops = async (query: string) => {
|
||
try {
|
||
const params: any = {
|
||
page: 1,
|
||
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('Search shops failed:', error)
|
||
}
|
||
}
|
||
|
||
// 处理店铺选择变化
|
||
const handleShopChange = (value: any) => {
|
||
if (Array.isArray(value) && value.length > 0) {
|
||
createForm.shop_id = value[value.length - 1]
|
||
} else {
|
||
createForm.shop_id = null
|
||
}
|
||
}
|
||
|
||
// 获取充值订单列表
|
||
const getTableData = async () => {
|
||
if (!canViewRecharge.value) {
|
||
rechargeList.value = []
|
||
pagination.total = 0
|
||
return
|
||
}
|
||
|
||
loading.value = true
|
||
try {
|
||
const params: AgentRechargeQueryParams = {
|
||
page: pagination.page,
|
||
page_size: pagination.page_size,
|
||
shop_id: isPlatformAccount.value ? searchForm.shop_id : undefined,
|
||
status: searchForm.status,
|
||
recharge_source: searchForm.recharge_source,
|
||
start_date: searchForm.start_date || undefined,
|
||
end_date: searchForm.end_date || undefined
|
||
}
|
||
const res = await AgentRechargeService.getAgentRecharges(params)
|
||
if (res.code === 0) {
|
||
rechargeList.value = res.data.items || []
|
||
pagination.total = res.data.total || 0
|
||
}
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 重置搜索
|
||
const handleReset = () => {
|
||
Object.assign(searchForm, { ...initialSearchState })
|
||
pagination.page = 1
|
||
getTableData()
|
||
}
|
||
|
||
// 搜索
|
||
const handleSearch = () => {
|
||
// 处理日期范围
|
||
if (searchForm.dateRange && Array.isArray(searchForm.dateRange)) {
|
||
searchForm.start_date = searchForm.dateRange[0]
|
||
searchForm.end_date = searchForm.dateRange[1]
|
||
} else {
|
||
searchForm.start_date = ''
|
||
searchForm.end_date = ''
|
||
}
|
||
pagination.page = 1
|
||
getTableData()
|
||
}
|
||
|
||
const exportQuery = computed(() => ({
|
||
shop_id: isPlatformAccount.value ? searchForm.shop_id : undefined,
|
||
status: searchForm.status,
|
||
recharge_source: searchForm.recharge_source,
|
||
start_date: searchForm.start_date || searchForm.dateRange?.[0],
|
||
end_date: searchForm.end_date || searchForm.dateRange?.[1]
|
||
}))
|
||
|
||
// 刷新表格
|
||
const handleRefresh = () => {
|
||
getTableData()
|
||
}
|
||
|
||
// 处理表格分页变化
|
||
const handleSizeChange = (newPageSize: number) => {
|
||
pagination.page_size = newPageSize
|
||
getTableData()
|
||
}
|
||
|
||
const handleCurrentChange = (newCurrentPage: number) => {
|
||
pagination.page = newCurrentPage
|
||
getTableData()
|
||
}
|
||
|
||
// 显示创建订单对话框
|
||
const showCreateDialog = async () => {
|
||
createMode.value = isAgentAccount.value ? 'online' : 'offline'
|
||
resetCreateForm()
|
||
|
||
if (createMode.value === 'online') {
|
||
await loadPaymentMethods()
|
||
} else {
|
||
// 重新加载店铺列表,确保获取最新数据
|
||
await loadShops()
|
||
}
|
||
|
||
createDialogVisible.value = true
|
||
}
|
||
|
||
const resetCreateForm = () => {
|
||
createForm.amount = minimumAmountYuan.value
|
||
createForm.payment_method = ''
|
||
createForm.shop_id = null
|
||
createForm.payment_voucher_key = []
|
||
createForm.remark = ''
|
||
onlineRequestId.value = null
|
||
onlineCreateRetried.value = false
|
||
voucherUploading.value = false
|
||
uploadRef.value?.clearFiles(false)
|
||
}
|
||
|
||
// 对话框关闭后的清理
|
||
const handleCreateDialogClosed = () => {
|
||
createFormRef.value?.resetFields()
|
||
resetCreateForm()
|
||
}
|
||
|
||
// 加载代理在线充值可用支付方式
|
||
const loadPaymentMethods = async () => {
|
||
paymentMethodsLoading.value = true
|
||
onlinePaymentMethods.value = []
|
||
try {
|
||
const res = await AgentRechargeService.getPaymentMethods()
|
||
if (res.code === 0) {
|
||
onlinePaymentMethods.value = Array.isArray(res.data?.methods) ? res.data.methods : []
|
||
paymentMethodsBounds.min_amount = Number(res.data?.min_amount) || 10000
|
||
paymentMethodsBounds.max_amount = Number(res.data?.max_amount) || 100000000
|
||
createForm.amount = minimumAmountYuan.value
|
||
} else {
|
||
ElMessage.warning(res.msg || '当前暂无可用在线支付方式')
|
||
}
|
||
} catch (error) {
|
||
console.error('加载在线支付方式失败:', error)
|
||
} finally {
|
||
paymentMethodsLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 创建充值订单
|
||
const handleCreateRecharge = async () => {
|
||
const formRef = createFormRef.value
|
||
if (!formRef) return
|
||
if (voucherUploading.value) {
|
||
ElMessage.warning('支付凭证上传中,请稍候')
|
||
return
|
||
}
|
||
|
||
const valid = await formRef.validate().catch(() => false)
|
||
if (!valid || createForm.amount == null || !createForm.payment_method) return
|
||
|
||
createLoading.value = true
|
||
try {
|
||
if (createMode.value === 'online') {
|
||
await handleOnlineRechargeCreate(createForm.amount, createForm.payment_method)
|
||
return
|
||
}
|
||
|
||
if (!createForm.shop_id) {
|
||
ElMessage.warning('请选择目标店铺')
|
||
return
|
||
}
|
||
|
||
const voucherKeys = toVoucherKeyList(createForm.payment_voucher_key)
|
||
if (!hasVoucherKeys(voucherKeys)) {
|
||
ElMessage.warning('请上传支付凭证')
|
||
return
|
||
}
|
||
|
||
const data: CreateAgentRechargeRequest = {
|
||
amount: amountYuanToFen(createForm.amount),
|
||
payment_method: 'offline',
|
||
shop_id: createForm.shop_id,
|
||
payment_voucher_key: voucherKeys,
|
||
remark: createForm.remark || undefined
|
||
}
|
||
|
||
const res = await AgentRechargeService.createAgentRecharge(data)
|
||
if (res.code !== 0) {
|
||
ElMessage.error(res.msg || '充值订单创建失败')
|
||
return
|
||
}
|
||
|
||
ElMessage.success('充值订单创建成功')
|
||
createDialogVisible.value = false
|
||
await getTableData()
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
createLoading.value = false
|
||
}
|
||
}
|
||
|
||
const handleOnlineRechargeCreate = async (
|
||
amountYuan: number,
|
||
paymentMethod: AgentRechargePaymentMethod
|
||
) => {
|
||
if (paymentMethod === 'offline') return
|
||
|
||
const requestId = onlineRequestId.value || createOnlineRechargeRequestId()
|
||
onlineRequestId.value = requestId
|
||
onlineCreateRetried.value = false
|
||
|
||
const request: CreateAgentRechargeRequest = {
|
||
amount: amountYuanToFen(amountYuan),
|
||
payment_method: paymentMethod,
|
||
request_id: requestId
|
||
}
|
||
|
||
let attempt = 0
|
||
while (attempt < 2) {
|
||
try {
|
||
const res = await AgentRechargeService.createAgentRecharge(request)
|
||
if (res.code !== 0) {
|
||
ElMessage.error(res.msg || '在线充值创建失败')
|
||
onlineRequestId.value = null
|
||
return
|
||
}
|
||
|
||
if (!res.data?.qr_content) {
|
||
ElMessage.error('支付接口未返回有效二维码,请刷新后重试')
|
||
return
|
||
}
|
||
|
||
onlineQrRecharge.value = res.data
|
||
onlinePaymentStatus.value = null
|
||
qrContent.value = res.data.qr_content
|
||
onlineQrDialogVisible.value = true
|
||
createDialogVisible.value = false
|
||
onlineRequestId.value = null
|
||
await getTableData()
|
||
return
|
||
} catch (error) {
|
||
if (attempt === 0 && shouldRetryOnlineCreate(error)) {
|
||
attempt += 1
|
||
onlineCreateRetried.value = true
|
||
continue
|
||
}
|
||
|
||
const normalized = normalizeApiError(error)
|
||
if (normalized.kind === 'validation' || normalized.kind === 'conflict') {
|
||
ElMessage.error(normalized.message)
|
||
} else {
|
||
ElMessage.warning('在线充值请求结果未知,请勿重复提交;可关闭后刷新列表确认')
|
||
}
|
||
onlineRequestId.value = null
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
const stopPaymentStatusPolling = () => {
|
||
if (paymentStatusTimer.value) {
|
||
clearInterval(paymentStatusTimer.value)
|
||
paymentStatusTimer.value = null
|
||
}
|
||
}
|
||
|
||
const loadOnlinePaymentStatus = async () => {
|
||
const rechargeId = onlineQrRecharge.value?.id
|
||
if (!rechargeId || !onlineQrDialogVisible.value || document.visibilityState !== 'visible')
|
||
return
|
||
|
||
paymentStatusLoading.value = true
|
||
try {
|
||
const res = await AgentRechargeService.getPaymentStatus(rechargeId)
|
||
if (res.code !== 0) return
|
||
|
||
onlinePaymentStatus.value = res.data
|
||
if (onlineQrRecharge.value) {
|
||
onlineQrRecharge.value = {
|
||
...onlineQrRecharge.value,
|
||
status: res.data.status,
|
||
status_name: res.data.status_name || onlineQrRecharge.value.status_name,
|
||
paid_at: res.data.paid_at,
|
||
completed_at: res.data.completed_at
|
||
}
|
||
}
|
||
|
||
if (isOnlineRechargeTerminal(res.data.status)) {
|
||
stopPaymentStatusPolling()
|
||
if (res.data.status === 3) {
|
||
await Promise.all([getTableData(), refreshAgentWalletBalance()])
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('查询在线充值状态失败:', error)
|
||
} finally {
|
||
paymentStatusLoading.value = false
|
||
}
|
||
}
|
||
|
||
const startPaymentStatusPolling = () => {
|
||
stopPaymentStatusPolling()
|
||
void loadOnlinePaymentStatus()
|
||
paymentStatusTimer.value = setInterval(() => {
|
||
if (!onlineQrDialogVisible.value || document.visibilityState !== 'visible') {
|
||
stopPaymentStatusPolling()
|
||
return
|
||
}
|
||
void loadOnlinePaymentStatus()
|
||
}, 3000)
|
||
}
|
||
|
||
const handleDocumentVisibilityChange = () => {
|
||
if (document.visibilityState === 'visible' && onlineQrDialogVisible.value) {
|
||
startPaymentStatusPolling()
|
||
} else if (document.visibilityState === 'hidden') {
|
||
stopPaymentStatusPolling()
|
||
}
|
||
}
|
||
|
||
watch(onlineQrDialogVisible, (visible) => {
|
||
if (visible) {
|
||
startPaymentStatusPolling()
|
||
} else {
|
||
stopPaymentStatusPolling()
|
||
}
|
||
})
|
||
|
||
const handleQrDialogClosed = () => {
|
||
stopPaymentStatusPolling()
|
||
qrContent.value = ''
|
||
onlineQrRecharge.value = null
|
||
onlinePaymentStatus.value = null
|
||
onlineWalletBalance.value = null
|
||
paymentStatusLoading.value = false
|
||
}
|
||
|
||
const refreshAgentWalletBalance = async () => {
|
||
if (!isAgentAccount.value) return
|
||
|
||
try {
|
||
const res = await CommissionService.getShopFundSummary({ page: 1, page_size: 100 })
|
||
const currentShopId = Number(userStore.info.shop_id)
|
||
const currentShop =
|
||
res.code === 0 ? res.data.items?.find((item) => item.shop_id === currentShopId) : null
|
||
if (currentShop) onlineWalletBalance.value = currentShop.main_balance
|
||
} catch (error) {
|
||
console.error('刷新代理钱包余额失败:', error)
|
||
}
|
||
}
|
||
|
||
// 显示确认支付对话框
|
||
const handleShowConfirmPay = (row: AgentRecharge) => {
|
||
currentRecharge.value = row
|
||
confirmPayDialogVisible.value = true
|
||
}
|
||
|
||
// 确认支付对话框关闭后的清理
|
||
const handleConfirmPayDialogClosed = () => {
|
||
confirmPayFormRef.value?.resetFields()
|
||
confirmPayForm.operation_password = ''
|
||
currentRecharge.value = null
|
||
}
|
||
|
||
// 确认线下支付
|
||
const handleConfirmPay = async () => {
|
||
const formRef = confirmPayFormRef.value
|
||
const recharge = currentRecharge.value
|
||
if (!formRef || !recharge) return
|
||
|
||
await formRef.validate(async (valid) => {
|
||
if (valid) {
|
||
confirmPayLoading.value = true
|
||
try {
|
||
await AgentRechargeService.confirmOfflinePayment(recharge.id, {
|
||
operation_password: confirmPayForm.operation_password
|
||
})
|
||
ElMessage.success('确认支付成功')
|
||
confirmPayDialogVisible.value = false
|
||
formRef.resetFields()
|
||
await getTableData()
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
confirmPayLoading.value = false
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 显示拒绝对话框
|
||
const handleShowReject = (row: AgentRecharge) => {
|
||
currentRecharge.value = row
|
||
rejectDialogVisible.value = true
|
||
}
|
||
|
||
// 拒绝对话框关闭后的清理
|
||
const handleRejectDialogClosed = () => {
|
||
rejectFormRef.value?.resetFields()
|
||
rejectForm.rejection_reason = ''
|
||
currentRecharge.value = null
|
||
}
|
||
|
||
// 拒绝代理充值订单
|
||
const handleRejectRecharge = async () => {
|
||
const formRef = rejectFormRef.value
|
||
const recharge = currentRecharge.value
|
||
if (!formRef || !recharge) return
|
||
|
||
await formRef.validate(async (valid) => {
|
||
if (valid) {
|
||
rejectLoading.value = true
|
||
try {
|
||
await AgentRechargeService.rejectAgentRecharge(recharge.id, {
|
||
rejection_reason: rejectForm.rejection_reason
|
||
})
|
||
ElMessage.success('拒绝成功')
|
||
rejectDialogVisible.value = false
|
||
await getTableData()
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
rejectLoading.value = false
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 处理名称点击
|
||
const handleNameClick = (row: AgentRecharge) => {
|
||
if (hasAuth('agent_recharge:detail_page')) {
|
||
handleViewDetail(row)
|
||
} else {
|
||
ElMessage.warning('您没有查看详情的权限')
|
||
}
|
||
}
|
||
|
||
// 查看详情
|
||
const handleViewDetail = (row: AgentRecharge) => {
|
||
router.push({
|
||
name: 'AgentRechargeDetailRoute',
|
||
params: { id: row.id }
|
||
})
|
||
}
|
||
|
||
// 获取操作按钮
|
||
const getActions = (row: AgentRecharge) => {
|
||
return buildAgentRechargeActions(row, {
|
||
hasAuth,
|
||
onViewPaymentVoucher: handleViewPaymentVoucher,
|
||
onConfirmPayment: handleShowConfirmPay,
|
||
onReject: handleShowReject
|
||
})
|
||
}
|
||
|
||
// 查看支付凭证
|
||
const handleViewPaymentVoucher = (row: AgentRecharge) => {
|
||
if (!hasVoucherKeys(row.payment_voucher_key)) return
|
||
paymentVoucherFileKeys.value = toVoucherKeyList(row.payment_voucher_key)
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.agent-recharge-page {
|
||
height: 100%;
|
||
}
|
||
|
||
.online-recharge-empty-hint {
|
||
margin-top: 8px;
|
||
color: var(--el-color-danger);
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.online-recharge-qr-dialog {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 16px;
|
||
|
||
&__summary {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 8px;
|
||
width: 100%;
|
||
color: var(--el-text-color-regular);
|
||
font-size: 14px;
|
||
text-align: center;
|
||
}
|
||
|
||
&__hint {
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
|
||
&__loading {
|
||
color: var(--el-color-primary);
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
</style>
|