feat: 7月迭代
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m21s

This commit is contained in:
luo
2026-07-28 14:00:22 +08:00
parent f0a2b84e53
commit 2706c52a47
63 changed files with 4113 additions and 3945 deletions

View File

@@ -19,6 +19,11 @@ export const buildAgentRechargeActions = (
options: BuildAgentRechargeActionsOptions
): AgentRechargeAction[] => {
const actions: AgentRechargeAction[] = []
const hasApprovalRecord =
row.approval_provider === 'wecom' ||
row.approval_source === 'wecom' ||
row.approval_source === 'legacy' ||
(row.approval_instance_id !== undefined && row.approval_instance_id !== null)
if (
row.payment_method === 'offline' &&
@@ -33,6 +38,7 @@ export const buildAgentRechargeActions = (
}
if (
!hasApprovalRecord &&
row.status === AgentRechargeStatus.PENDING &&
row.payment_method === 'offline' &&
options.hasAuth('agent_recharge:confirm_payment')
@@ -44,7 +50,11 @@ export const buildAgentRechargeActions = (
})
}
if (row.status === AgentRechargeStatus.PENDING && options.hasAuth('agent_recharge:reject')) {
if (
!hasApprovalRecord &&
row.status === AgentRechargeStatus.PENDING &&
options.hasAuth('agent_recharge:reject')
) {
actions.push({
label: '拒绝',
handler: () => options.onReject(row),

View File

@@ -68,26 +68,12 @@
2: 'success', // 已支付
3: 'success', // 已完成
4: 'info', // 已关闭
5: 'danger', // 已退款
6: 'danger' // 已驳回
5: 'danger', // 已退款
6: 'danger' // 已驳回
}
return statusMap[status] || 'info'
}
// 获取状态文本(优先使用 status_name否则使用本地映射
const getStatusText = (status: AgentRechargeStatus, statusName?: string): string => {
if (statusName) return statusName
const statusMap: Record<AgentRechargeStatus, string> = {
1: '待支付',
2: '已支付',
3: '已完成',
4: '已关闭',
5: '已退款',
6: '已驳回'
}
return statusMap[status] || '-'
}
// 获取支付方式文本
const getPaymentMethodText = (method: AgentRechargePaymentMethod): string => {
const methodMap: Record<AgentRechargePaymentMethod, string> = {
@@ -97,6 +83,12 @@
return methodMap[method] || method
}
const getApprovalProviderText = (data: AgentRecharge) => {
if (data.approval_provider === 'wecom' || data.approval_source === 'wecom') return '企微'
if (data.approval_source === 'legacy') return '历史审批'
return data.approval_provider || data.approval_source || '-'
}
// 详情配置
const detailSections = computed((): DetailSection[] => [
{
@@ -104,6 +96,7 @@
fields: [
{ label: '充值单号', prop: 'recharge_no' },
{ label: '店铺名称', prop: 'shop_name' },
{ label: '提交人', prop: 'submitter_name', formatter: (value) => value || '-' },
{
label: '充值金额',
formatter: (_, data) => formatCurrency(data.amount)
@@ -111,9 +104,7 @@
{
label: '状态',
render: (data) =>
h(ElTag, { type: getStatusType(data.status) }, () =>
getStatusText(data.status, data.status_name)
)
h(ElTag, { type: getStatusType(data.status) }, () => data.status_name || '-')
},
{
label: '驳回原因',
@@ -123,6 +114,30 @@
}
]
},
{
title: '企微审批信息',
fields: [
{ label: '审批渠道', formatter: (_, data) => getApprovalProviderText(data) },
{
label: '审批状态',
formatter: (_, data) => data.approval_status_name || '-'
},
{
label: '当前审批人摘要',
formatter: (_, data) => data.current_approver_summary || '-',
fullWidth: true
}
]
},
{
title: '业务处理结果',
fields: [
{
label: '处理状态',
formatter: (_, data) => data.processing_status_name || '-'
}
]
},
{
title: '支付信息',
fields: [

View File

@@ -24,6 +24,9 @@
v-if="hasAuth('agent_recharge:create')"
>创建充值订单</ElButton
>
<ElButton v-if="hasAuth('agent_recharge:export')" @click="exportDialogVisible = true">
导出
</ElButton>
</template>
</ArtTableHeader>
@@ -66,7 +69,7 @@
placeholder="请输入充值金额(元)"
/>
<div style="margin-top: 8px; font-size: 12px; color: var(--el-text-color-secondary)">
最小: ¥0.01最大: 不限制
最小: ¥0.01最大: ¥1,000,000.00
</div>
</ElFormItem>
<ElFormItem label="支付方式" prop="payment_method">
@@ -129,6 +132,15 @@
</template>
</ElDialog>
<!-- 导出任务对话框 -->
<ExportTaskCreateDialog
v-model="exportDialogVisible"
scene="agent_recharge"
:query="exportQuery"
confirm-permission="agent_recharge:export"
title="导出代理充值"
/>
<!-- 确认线下支付对话框 -->
<ElDialog
v-model="confirmPayDialogVisible"
@@ -245,6 +257,7 @@
import { useAuth } from '@/composables/useAuth'
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'
@@ -260,6 +273,7 @@
const rejectLoading = ref(false)
const tableRef = ref()
const createDialogVisible = ref(false)
const exportDialogVisible = ref(false)
const confirmPayDialogVisible = ref(false)
const rejectDialogVisible = ref(false)
const currentRecharge = ref<AgentRecharge | null>(null)
@@ -336,8 +350,11 @@
placeholder: '请选择状态',
options: [
{ label: '待支付', value: 1 },
{ label: '已完成', value: 2 },
{ label: '已取消', value: 3 }
{ label: '已支付', value: 2 },
{ label: '已完成', value: 3 },
{ label: '已关闭', value: 4 },
{ label: '已退款', value: 5 },
{ label: '已驳回', value: 6 }
],
config: {
clearable: true
@@ -370,16 +387,19 @@
{ label: '店铺名称', prop: 'shop_name' },
{ 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: 'completed_at' },
{ label: '更新时间', prop: 'updated_at' }
]
const createFormRef = ref<FormInstance>()
@@ -387,6 +407,7 @@
const rejectFormRef = ref<FormInstance>()
const uploadRef = ref<InstanceType<typeof VoucherUpload>>()
const MIN_RECHARGE_AMOUNT = 0.01
const MAX_RECHARGE_AMOUNT = 1_000_000
const createRules = computed<FormRules>(() => {
const rules: FormRules = {
@@ -402,6 +423,10 @@
callback(new Error(`充值金额最小为 ¥${MIN_RECHARGE_AMOUNT.toFixed(2)}`))
return
}
if (Number(value) > MAX_RECHARGE_AMOUNT) {
callback(new Error(`充值金额最大为 ¥${MAX_RECHARGE_AMOUNT.toFixed(2)}`))
return
}
callback()
},
trigger: 'blur'
@@ -464,26 +489,12 @@
2: 'success', // 已支付
3: 'success', // 已完成
4: 'info', // 已关闭
5: 'danger', // 已退款
6: 'danger' // 已驳回
5: 'danger', // 已退款
6: 'danger' // 已驳回
}
return statusMap[status] || 'info'
}
// 获取状态文本(优先使用 status_name否则使用本地映射
const getStatusText = (status: AgentRechargeStatus, statusName?: string): string => {
if (statusName) return statusName
const statusMap: Record<AgentRechargeStatus, string> = {
1: '待支付',
2: '已支付',
3: '已完成',
4: '已关闭',
5: '已退款',
6: '已驳回'
}
return statusMap[status] || '-'
}
// 获取支付方式文本
const getPaymentMethodText = (method: AgentRechargePaymentMethod): string => {
const methodMap: Record<AgentRechargePaymentMethod, string> = {
@@ -530,9 +541,17 @@
label: '状态',
width: 100,
formatter: (row: AgentRecharge) => {
return h(ElTag, { type: getStatusType(row.status) }, () =>
getStatusText(row.status, row.status_name)
)
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 || '-'
}
},
{
@@ -605,6 +624,12 @@
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)
}
])
@@ -711,6 +736,13 @@
getTableData()
}
const exportQuery = computed(() => ({
shop_id: searchForm.shop_id,
status: searchForm.status,
start_date: searchForm.start_date || searchForm.dateRange?.[0],
end_date: searchForm.end_date || searchForm.dateRange?.[1]
}))
// 刷新表格
const handleRefresh = () => {
getTableData()

View File

@@ -162,6 +162,34 @@
return `¥${(amount / 100).toFixed(2)}`
}
const getApprovalProviderText = (item: Refund) => {
const provider = item.approval_provider || item.approval_source || item.approval?.source
if (provider === 'wecom') return '企微'
if (provider === 'legacy') return '历史审批'
if (provider === 'none') return '无'
return provider || '-'
}
const getRefundApprovalStatusText = (item: Refund) => {
return item.approval_status_name || item.approval?.status_name || item.approval?.status || '-'
}
const isHiddenIdKey = (key: string) => {
const normalizedKey = key.toLowerCase()
return normalizedKey === 'id' || normalizedKey === 'userid' || normalizedKey.endsWith('_id')
}
const sanitizeStructuredValue = (value: unknown): unknown => {
if (Array.isArray(value)) return value.map((item) => sanitizeStructuredValue(item))
if (!value || typeof value !== 'object') return value
return Object.fromEntries(
Object.entries(value)
.filter(([key]) => !isHiddenIdKey(key))
.map(([key, item]) => [key, sanitizeStructuredValue(item)])
)
}
const formatStructuredValue = (value: unknown) => {
if (value === undefined || value === null || value === '') return '-'
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
@@ -171,7 +199,7 @@
}
const renderStructuredValue = (value: unknown) =>
h('pre', { class: 'structured-value' }, formatStructuredValue(value))
h('pre', { class: 'structured-value' }, formatStructuredValue(sanitizeStructuredValue(value)))
const renderTimeline = (timeline: unknown) => {
if (!Array.isArray(timeline) || timeline.length === 0) return h('span', '-')
@@ -181,7 +209,7 @@
{ class: 'approval-timeline' },
timeline.map((item: any) => {
const title = item.status_name || item.status || item.content || '审批节点'
const operator = item.operator_name || item.operator || ''
const operator = item.operator_name || ''
const time = item.time || item.timestamp || ''
const comment = item.comment || item.content || ''
return h('div', { class: 'approval-timeline__item' }, [
@@ -207,6 +235,8 @@
{ label: '订单号', prop: 'order_no' },
{ label: '资产标识符', prop: 'asset_identifier' },
{ label: '资产类型', prop: 'asset_type' },
{ label: '退款状态', prop: 'status_name', formatter: (value) => value || '-' },
{ label: '提交人', prop: 'submitter_name', formatter: (value) => value || '-' },
{
label: '申请退款金额',
formatter: (_, data) => formatCurrency(data.requested_refund_amount)
@@ -225,6 +255,12 @@
formatter: (value) => value || '-',
fullWidth: true
},
{
label: '拒绝原因',
prop: 'reject_reason',
formatter: (value) => value || '-',
fullWidth: true
},
{
label: '备注',
prop: 'remark',
@@ -258,17 +294,30 @@
formatter: (_, data) => (data.commission_deducted ? '是' : '否')
},
{ 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) }
]
},
{
title: '企微审批信息',
fields: [
{ label: '审批来源', prop: 'approval.source' },
{ label: '审批渠道', formatter: (_, data) => getApprovalProviderText(data) },
{
label: '审批来源',
formatter: (_, data) => data.approval?.source || data.approval_source || '-'
},
{ label: '审批单号', prop: 'approval.sp_no' },
{
label: '审批状态',
formatter: (_, data) => data.approval?.status_name || data.approval?.status || '-'
formatter: (_, data) => getRefundApprovalStatusText(data)
},
{
label: '当前审批人摘要',
formatter: (_, data) => data.current_approver_summary || '-'
},
{ label: '模板版本', prop: 'approval.template_version' },
{

View File

@@ -21,6 +21,9 @@
<ElButton type="primary" @click="showCreateDialog" v-if="hasAuth('refund:create')"
>创建退款申请</ElButton
>
<ElButton v-if="hasAuth('refund:export')" @click="exportDialogVisible = true">
导出
</ElButton>
</template>
</ArtTableHeader>
@@ -48,6 +51,15 @@
<!-- 创建退款申请对话框 -->
<CreateRefundDialog v-model="createDialogVisible" @success="handleCreateSuccess" />
<!-- 导出任务对话框 -->
<ExportTaskCreateDialog
v-model="exportDialogVisible"
scene="refund"
:query="exportQuery"
confirm-permission="refund:export"
title="导出退款"
/>
<!-- 退款凭证预览 -->
<PaymentVoucherDialog
:file-keys="refundVoucherFileKeys"
@@ -147,7 +159,6 @@
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { fenToYuan, formatDateTime, yuanToFen } from '@/utils/business/format'
import {
getApprovalStatusText,
getCurrentApproverSummaryText,
getProcessingStatusText
} from '@/utils/business/approvalSummary'
@@ -155,6 +166,7 @@
import { RoutesAlias } from '@/router/routesAlias'
import PaymentVoucherDialog from '@/components/business/PaymentVoucherDialog.vue'
import VoucherUpload from '@/components/business/VoucherUpload.vue'
import ExportTaskCreateDialog from '@/components/business/ExportTaskCreateDialog.vue'
import { useAuth } from '@/composables/useAuth'
@@ -170,6 +182,7 @@
const tableRef = ref()
const resubmitUploadRef = ref<InstanceType<typeof VoucherUpload>>()
const createDialogVisible = ref(false)
const exportDialogVisible = ref(false)
const resubmitDialogVisible = ref(false)
const currentRefund = ref<Refund | null>(null)
const refundVoucherFileKeys = ref<string[]>([])
@@ -269,6 +282,7 @@
{ label: '实际退款金额', prop: 'approved_refund_amount' },
{ label: '实收金额', prop: 'actual_received_amount' },
{ label: '状态', prop: 'status' },
{ label: '审批渠道', prop: 'approval_provider' },
{ label: '提交人', prop: 'submitter_name' },
{ label: '审批状态', prop: 'approval_status' },
{ label: '当前审批人摘要', prop: 'current_approver_summary' },
@@ -279,7 +293,8 @@
{ label: '资产重置', prop: 'asset_reset' },
{ label: '佣金扣除', prop: 'commission_deducted' },
{ label: '创建时间', prop: 'created_at' },
{ label: '审批时间', prop: 'processed_at' }
{ label: '审批时间', prop: 'processed_at' },
{ label: '更新时间', prop: 'updated_at' }
]
const resubmitFormRef = ref<FormInstance>()
@@ -320,17 +335,6 @@
return statusMap[status] || 'info'
}
// 获取状态文本
const getStatusText = (status: RefundStatus): string => {
const statusMap: Record<RefundStatus, string> = {
1: '待审批',
2: '已通过',
3: '已拒绝',
4: '已退回'
}
return statusMap[status] || '-'
}
// 动态列配置
const { columnChecks, columns } = useCheckedColumns(() => [
{
@@ -404,7 +408,17 @@
label: '状态',
width: 100,
formatter: (row: Refund) => {
return h(ElTag, { type: getStatusType(row.status) }, () => getStatusText(row.status))
return h(ElTag, { type: getStatusType(row.status) }, () => row.status_name || '-')
}
},
{
prop: 'approval_provider',
label: '审批渠道',
width: 110,
formatter: (row: Refund) => {
if (row.approval_provider === 'wecom' || row.approval_source === 'wecom') return '企微'
if (row.approval_source === 'legacy') return '历史审批'
return row.approval_provider || row.approval_source || '-'
}
},
{
@@ -418,7 +432,7 @@
prop: 'approval_status',
label: '审批状态',
width: 120,
formatter: (row: Refund) => getApprovalStatusText(row)
formatter: (row: Refund) => row.approval_status_name || '-'
},
{
prop: 'current_approver_summary',
@@ -483,6 +497,12 @@
label: '审批时间',
width: 180,
formatter: (row: Refund) => (row.processed_at ? formatDateTime(row.processed_at) : '-')
},
{
prop: 'updated_at',
label: '更新时间',
width: 180,
formatter: (row: Refund) => formatDateTime(row.updated_at)
}
])
@@ -564,6 +584,13 @@
}
}
const exportQuery = computed(() => ({
status: searchForm.status,
order_id: searchForm.order_id,
shop_id: searchForm.shop_id,
asset_identifier: searchForm.asset_identifier?.trim() || undefined
}))
// 重置搜索
const handleReset = () => {
Object.assign(searchForm, { ...initialSearchState })