feat: adapt admin payment configuration and refunds
Build and Deploy Vue3 / build (push) Successful in 1m42s
Build and Deploy Vue3 / deploy (push) Successful in 46s

This commit is contained in:
shiran
2026-07-17 17:18:14 +08:00
parent fa3bdcbc7e
commit 9b369a4dd5
7 changed files with 744 additions and 15 deletions
+9
View File
@@ -41,3 +41,12 @@ export const retryOrderHook = (data) => {
}
})
}
/**订单退款 */
export const refundOrder = (data) => {
return http2.post('/api/v1/admin/order/refund', data, {
headers:{
'Content-Type':'multipart/form-data'
}
})
}
+15
View File
@@ -0,0 +1,15 @@
import { http2 } from '@/utils/request.js'
/** 获取 007pay 支付配置 */
export const getPay007Config = () => {
return http2.get('/api/v1/admin/pay007/config')
}
/** 更新 007pay 支付配置 */
export const updatePay007Config = (data) => {
return http2.post('/api/v1/admin/pay007/config/update', data, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
+5 -1
View File
@@ -68,6 +68,10 @@ export const menus = [
{
path: '/order/list',
title: '订单列表'
},
{
path: '/order/payment-config',
title: '支付配置'
}
]
},
@@ -227,4 +231,4 @@ export const menus = [
}
]
}
]
]
+9 -1
View File
@@ -313,6 +313,14 @@ const routes = [
meta: {
title: '订单列表'
}
},
{
path: 'payment-config',
name: 'PaymentConfig',
component: () => import('../views/order/PaymentConfig.vue'),
meta: {
title: '支付配置'
}
}
]
},
@@ -806,4 +814,4 @@ router.afterEach(() => {
window.scrollTo(0, 0)
})
export default router
export default router
+323 -9
View File
@@ -130,7 +130,15 @@
</el-table-column>
<el-table-column label="支付方式" width="100">
<template #default="{ row }">
<span>{{ row.payType || '-' }}</span>
<span>{{ getPayTypeText(row.payType) }}</span>
</template>
</el-table-column>
<el-table-column label="退款状态" width="120">
<template #default="{ row }">
<el-tag v-if="row.refundStatus" :type="getRefundStatusType(row.refundStatus)" size="small">
{{ getRefundStatusText(row.refundStatus) }}
</el-tag>
<span v-else class="text-muted">-</span>
</template>
</el-table-column>
<el-table-column label="过期时间" width="170">
@@ -143,11 +151,12 @@
<span>{{ formatDate(row.CreatedAt) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="250" fixed="right">
<el-table-column label="操作" width="310" fixed="right">
<template #default="{ row }">
<div class="action-buttons">
<el-button type="primary" link @click="handleView(row)">查看</el-button>
<el-button type="warning" link @click="handleEdit(row)">编辑</el-button>
<el-button type="success" link :disabled="!canRefund(row)" @click="handleOpenRefund(row)">退款</el-button>
<el-button type="danger" link @click="handleRetryOrder(row)">重试流程</el-button>
</div>
</template>
@@ -187,6 +196,9 @@
{{ getStatusText(orderDetail.state) }}
</el-tag>
<el-tag type="info" size="small" effect="plain">{{ getTypeText(orderDetail.type) }}</el-tag>
<el-tag v-if="orderDetail.refundStatus" :type="getRefundStatusType(orderDetail.refundStatus)" size="small" effect="plain">
{{ getRefundStatusText(orderDetail.refundStatus) }}
</el-tag>
</div>
<div class="od-hero-sub">
<span>订单号 #{{ orderDetail.id }}</span>
@@ -202,7 +214,16 @@
<!-- 订单信息 -->
<div class="od-section">
<div class="od-section-title"><el-icon><Document /></el-icon><span>订单信息</span></div>
<div class="od-section-title">
<el-icon><Document /></el-icon><span>订单信息</span>
<el-button
v-if="canRefund(orderDetail)"
type="success"
link
class="od-section-action"
@click="handleOpenRefund(orderDetail)"
>发起退款</el-button>
</div>
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="订单ID">{{ orderDetail.id }}</el-descriptions-item>
<el-descriptions-item label="订单类型">
@@ -217,7 +238,12 @@
<span class="od-mono">{{ orderDetail.paymentOrderId || '-' }}</span>
</el-descriptions-item>
<el-descriptions-item label="到期时间">{{ formatDate(orderDetail.expireTime) }}</el-descriptions-item>
<el-descriptions-item label="退款时间">{{ orderDetail.refundTime ? formatDate(orderDetail.refundTime) : '-' }}</el-descriptions-item>
<el-descriptions-item label="退款状态">
<el-tag v-if="orderDetail.refundStatus" :type="getRefundStatusType(orderDetail.refundStatus)" size="small">
{{ getRefundStatusText(orderDetail.refundStatus) }}
</el-tag>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ formatDate(orderDetail.createdAt || orderDetail.CreatedAt) }}</el-descriptions-item>
<el-descriptions-item label="更新时间">{{ formatDate(orderDetail.updatedAt || orderDetail.UpdatedAt) }}</el-descriptions-item>
<el-descriptions-item label="参数信息" :span="2">
@@ -231,6 +257,26 @@
</el-descriptions>
</div>
<!-- 退款信息 -->
<div class="od-section" v-if="hasRefundInfo(orderDetail)">
<div class="od-section-title">
<el-icon><Money /></el-icon><span>退款信息</span>
</div>
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="退款状态">
<el-tag :type="getRefundStatusType(orderDetail.refundStatus)" size="small">
{{ getRefundStatusText(orderDetail.refundStatus) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="退款金额">¥{{ formatYuan(orderDetail.refundAmount) }}</el-descriptions-item>
<el-descriptions-item label="退款单号">
<span class="od-mono">{{ orderDetail.refundNo || '-' }}</span>
</el-descriptions-item>
<el-descriptions-item label="退款时间">{{ orderDetail.refundTime ? formatDate(orderDetail.refundTime) : '-' }}</el-descriptions-item>
<el-descriptions-item label="退款原因" :span="2">{{ orderDetail.refundReason || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
<!-- 用户信息 -->
<div class="od-section">
<div class="od-section-title">
@@ -514,9 +560,12 @@
</el-form-item>
<el-form-item label="支付方式">
<el-select v-model="orderForm.pay_type" placeholder="请选择" clearable style="width: 100%">
<el-option label="默认余额" value="default" />
<el-option label="支付宝" value="ali" />
<el-option label="微信" value="wx" />
<el-option label="默认/余额" value="default" />
<el-option label="余额" value="balance" />
<el-option label="007pay" value="007pay" />
<el-option label="管理员" value="admin" />
<el-option label="支付宝(旧)" value="ali" />
<el-option label="微信(旧)" value="wx" />
</el-select>
</el-form-item>
<el-row :gutter="16">
@@ -568,6 +617,79 @@
</template>
</el-dialog>
<!-- 退款对话框 -->
<el-dialog
v-model="refundDialogVisible"
title="订单退款"
width="560px"
append-to-body
destroy-on-close
>
<div v-if="refundOrderInfo" class="refund-dialog-body">
<div class="refund-summary">
<div class="refund-summary-main">
<div class="refund-order-name">{{ refundOrderInfo.name || '未命名订单' }}</div>
<div class="refund-order-meta">
<span>订单 #{{ refundOrderInfo.id }}</span>
<el-divider direction="vertical" />
<span>{{ getPayTypeText(refundOrderInfo.payType) }}</span>
</div>
</div>
<div class="refund-order-amount">¥{{ formatYuan(refundOrderInfo.price) }}</div>
</div>
<el-form ref="refundFormRef" :model="refundForm" :rules="refundRules" label-width="110px">
<el-form-item label="退款方式" prop="refund_method">
<el-radio-group v-model="refundForm.refund_method">
<el-radio-button value="original" :disabled="!canOriginalRefund(refundOrderInfo)">原路退款</el-radio-button>
<el-radio-button value="balance" :disabled="!canBalanceRefund(refundOrderInfo)">退到余额</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="退款金额" prop="amount">
<div class="unit-input-row">
<el-input-number
v-model="refundForm.amount"
:min="0"
:max="Number(formatYuan(refundOrderInfo.price))"
:precision="2"
:step="0.01"
style="flex: 1"
/>
<span class="unit-text"></span>
</div>
<div class="form-tip">金额为 0 时退订单全额</div>
</el-form-item>
<el-form-item v-if="refundForm.refund_method === 'balance'" label="余额类型">
<el-select v-model="refundForm.balance_type" style="width: 100%">
<el-option label="云币" value="general" />
<el-option label="云钻" value="entity" />
<el-option label="云点" value="withdraw" />
</el-select>
</el-form-item>
<el-form-item label="退款原因">
<el-input
v-model="refundForm.reason"
type="textarea"
:rows="3"
maxlength="120"
show-word-limit
placeholder="请输入退款原因"
/>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="wizard-footer">
<el-button @click="refundDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="refundSubmitLoading" @click="submitRefund">确认退款</el-button>
</div>
</template>
</el-dialog>
<!-- 用户选择器 -->
<UserListSelector
v-model="userSelectorVisible"
@@ -603,7 +725,7 @@ import { ref, reactive, onMounted, onActivated, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Delete, Search, Download, Refresh, User, ShoppingCart, Ticket, Money, Close, Setting, Loading, Lock, Document, ArrowRight, Goods, Box } from '@element-plus/icons-vue'
import { getOrderList, getOrderDetail, createOrder, updateOrder, deleteOrder, retryOrderHook } from '@/api/admin/order'
import { getOrderList, getOrderDetail, createOrder, updateOrder, deleteOrder, retryOrderHook, refundOrder } from '@/api/admin/order'
import { getProductPlanList, getProductParameterList, getProductParameterDetail } from '@/api/admin/product'
import UserListSelector from '@/components/admin/UserListSelector.vue'
import ProductSelector from '@/components/admin/ProductSelector.vue'
@@ -688,6 +810,10 @@ const selectedRows = ref([])
const dialogVisible = ref(false)
const detailDialogVisible = ref(false)
const dialogType = ref('add')
const refundDialogVisible = ref(false)
const refundSubmitLoading = ref(false)
const refundFormRef = ref(null)
const refundOrderInfo = ref(null)
// 选择器弹窗状态
const userSelectorVisible = ref(false)
@@ -701,6 +827,34 @@ const selectedProductInfo = ref(null)
const selectedDiscountCodeInfo = ref(null)
const selectedVoucherInfo = ref(null)
// 退款表单
const refundForm = reactive({
order_id: undefined,
refund_method: 'balance',
amount: 0,
reason: '订单退款',
balance_type: 'general'
})
const validateRefundAmount = (rule, value, callback) => {
const priceYuan = (Number(refundOrderInfo.value?.price) || 0) / 100
const amount = Number(value) || 0
if (amount < 0) {
callback(new Error('退款金额不能小于 0'))
return
}
if (priceYuan > 0 && amount > priceYuan) {
callback(new Error('退款金额不能超过订单金额'))
return
}
callback()
}
const refundRules = {
refund_method: [{ required: true, message: '请选择退款方式', trigger: 'change' }],
amount: [{ validator: validateRefundAmount, trigger: 'blur' }]
}
// 获取订单列表
const fetchOrderList = async () => {
loading.value = true
@@ -765,10 +919,49 @@ const getTypeText = (type) => {
// 获取支付方式文本
const getPayTypeText = (payType) => {
const map = { ali: '支付宝', wx: '微信', default: '余额/默认' }
const map = {
default: '默认/余额',
balance: '余额',
'007pay': '007pay',
admin: '管理员',
ali: '支付宝',
wx: '微信'
}
return map[payType] || payType || '-'
}
// 获取退款状态文本
const getRefundStatusText = (status) => {
const map = { pending: '退款中', success: '已退款', failed: '退款失败' }
return map[status] || status || '未退款'
}
// 获取退款状态标签类型
const getRefundStatusType = (status) => {
const map = { pending: 'warning', success: 'success', failed: 'danger' }
return map[status] || 'info'
}
const hasRefundInfo = (order) => {
return Boolean(order?.refundStatus || order?.refundAmount || order?.refundNo || order?.refundReason || order?.refundTime)
}
const isRefundLocked = (order) => {
return Boolean(order?.refundTime || order?.refundStatus === 'pending' || order?.refundStatus === 'success')
}
const canOriginalRefund = (order) => {
return Boolean(order?.state === 1 && order?.payType === '007pay' && order?.paymentOrderId)
}
const canBalanceRefund = (order) => {
return Boolean(order?.state === 1 && order?.table !== 'userBalance')
}
const canRefund = (order) => {
return Boolean(order?.state === 1 && !isRefundLocked(order) && (canOriginalRefund(order) || canBalanceRefund(order)))
}
// 分转元
const formatYuan = (fen) => {
return ((Number(fen) || 0) / 100).toFixed(2)
@@ -1002,6 +1195,80 @@ const handleRetryOrder = (row) => {
}).catch(() => {})
}
// 打开退款弹窗
const handleOpenRefund = (row) => {
if (!canRefund(row)) {
ElMessage.warning('当前订单不满足退款条件')
return
}
const refundMethod = canOriginalRefund(row) ? 'original' : 'balance'
refundOrderInfo.value = row
Object.assign(refundForm, {
order_id: row.id,
refund_method: refundMethod,
amount: Number(formatYuan(row.price)),
reason: '订单退款',
balance_type: 'general'
})
refundDialogVisible.value = true
refundFormRef.value?.clearValidate()
}
// 提交退款
const submitRefund = async () => {
const formEl = refundFormRef.value
if (formEl) {
const valid = await formEl.validate().catch(() => false)
if (!valid) return
}
const methodText = refundForm.refund_method === 'original' ? '原路退款' : '退到余额'
const amountText = Number(refundForm.amount) > 0 ? `¥${Number(refundForm.amount).toFixed(2)}` : '订单全额'
try {
await ElMessageBox.confirm(
`确认将订单「${refundOrderInfo.value?.name || refundForm.order_id}${methodText} ${amountText} 吗?`,
'订单退款',
{
confirmButtonText: '确认退款',
cancelButtonText: '取消',
type: 'warning'
}
)
} catch {
return
}
refundSubmitLoading.value = true
try {
const submitData = {
order_id: Number(refundForm.order_id),
refund_method: refundForm.refund_method,
amount: Number(refundForm.amount) || 0,
reason: refundForm.reason || '订单退款'
}
if (refundForm.refund_method === 'balance') {
submitData.balance_type = refundForm.balance_type || 'general'
}
const res = await refundOrder(submitData)
if (res.data.code === 200) {
ElMessage.success('退款成功')
refundDialogVisible.value = false
await fetchOrderList()
if (detailDialogVisible.value && orderDetail.value?.id === submitData.order_id) {
await handleView(submitData.order_id)
}
} else {
ElMessage.error(res.data.message || '退款失败')
}
} catch (error) {
console.error('订单退款失败:', error)
ElMessage.error(error.response?.data?.message || '订单退款失败')
} finally {
refundSubmitLoading.value = false
}
}
// 删除订单
const handleDelete = (row) => {
ElMessageBox.confirm(`确认删除订单 ${row.name} 吗?`, '警告', {
@@ -1696,6 +1963,9 @@ watch(() => route.query.order_id, (newId) => {
font-size: 13px;
font-weight: 400;
}
.od-section-action {
margin-left: auto;
}
.od-section-link .el-icon {
color: inherit;
margin-left: 2px;
@@ -1707,4 +1977,48 @@ watch(() => route.query.order_id, (newId) => {
.od-args {
word-break: break-all;
}
.refund-dialog-body {
display: flex;
flex-direction: column;
gap: 18px;
}
.refund-summary {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
padding: 14px 16px;
background: #f7f8fa;
border: 1px solid #ebeef5;
border-radius: 8px;
}
.refund-summary-main {
min-width: 0;
}
.refund-order-name {
font-weight: 600;
color: #303133;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.refund-order-meta {
display: flex;
align-items: center;
margin-top: 6px;
color: #909399;
font-size: 12px;
}
.refund-order-amount {
color: #f56c6c;
font-size: 20px;
font-weight: 700;
flex-shrink: 0;
}
</style>
+346
View File
@@ -0,0 +1,346 @@
<template>
<div class="payment-config-page">
<div class="page-toolbar">
<div class="title-block">
<div class="title-icon">
<el-icon><Money /></el-icon>
</div>
<div>
<h2>007pay 支付配置</h2>
<p>管理 007pay 收银台回调与支付通道参数</p>
</div>
</div>
<div class="toolbar-actions">
<el-button :loading="loading" @click="fetchConfig">
<el-icon><Refresh /></el-icon>刷新
</el-button>
<el-button type="primary" :loading="saving" @click="submitForm">
<el-icon><Check /></el-icon>保存配置
</el-button>
</div>
</div>
<div class="summary-grid">
<div class="summary-item">
<div class="summary-label">配置状态</div>
<div class="summary-value">
<el-tag :type="isConfigured ? 'success' : 'warning'" effect="plain">
{{ isConfigured ? '已配置' : '待完善' }}
</el-tag>
</div>
</div>
<div class="summary-item">
<div class="summary-label">商户 PID</div>
<div class="summary-value mono">{{ form.pid || '-' }}</div>
</div>
<div class="summary-item">
<div class="summary-label">通道类型</div>
<div class="summary-value">
<el-tag type="info" effect="plain">{{ getChannelText(form.channel_type) }}</el-tag>
</div>
</div>
</div>
<div class="config-panel" v-loading="loading">
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="150px"
class="config-form"
>
<el-form-item label="API 地址" prop="base_url">
<el-input v-model.trim="form.base_url" placeholder="https://pay.example.com" clearable>
<template #prefix><el-icon><Connection /></el-icon></template>
</el-input>
</el-form-item>
<el-form-item label="商户 PID" prop="pid">
<el-input v-model.trim="form.pid" placeholder="请输入商户 PID" clearable>
<template #prefix><el-icon><Setting /></el-icon></template>
</el-input>
</el-form-item>
<el-form-item label="商户密钥" prop="key">
<el-input v-model.trim="form.key" placeholder="请输入商户密钥" show-password clearable>
<template #prefix><el-icon><Key /></el-icon></template>
</el-input>
</el-form-item>
<el-form-item label="异步回调地址" prop="notify_url">
<el-input v-model.trim="form.notify_url" placeholder="https://api.example.com/api/v1/callback/007pay/pay" clearable>
<template #prefix><el-icon><Connection /></el-icon></template>
</el-input>
</el-form-item>
<el-form-item label="同步跳转地址" prop="return_url">
<el-input v-model.trim="form.return_url" placeholder="https://example.com/pay/return" clearable>
<template #prefix><el-icon><Connection /></el-icon></template>
</el-input>
</el-form-item>
<el-form-item label="通道类型" prop="channel_type">
<el-select
v-model="form.channel_type"
placeholder="请选择或输入通道类型"
filterable
allow-create
default-first-option
clearable
style="width: 100%"
>
<el-option label="支付宝" value="alipay" />
<el-option label="微信支付" value="wxpay" />
</el-select>
</el-form-item>
</el-form>
<div class="panel-footer">
<el-button @click="resetForm">重置</el-button>
<el-button type="primary" :loading="saving" @click="submitForm">保存配置</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { computed, onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { Check, Connection, Key, Money, Refresh, Setting } from '@element-plus/icons-vue'
import { getPay007Config, updatePay007Config } from '@/api/admin/pay007'
const formRef = ref(null)
const loading = ref(false)
const saving = ref(false)
const emptyForm = {
base_url: '',
pid: '',
key: '',
notify_url: '',
return_url: '',
channel_type: ''
}
const form = reactive({ ...emptyForm })
const originalForm = ref({ ...emptyForm })
const optionalUrlValidator = (rule, value, callback) => {
if (!value) {
callback()
return
}
try {
const url = new URL(value)
if (!['http:', 'https:'].includes(url.protocol)) {
callback(new Error('请输入 http 或 https 地址'))
return
}
callback()
} catch {
callback(new Error('请输入有效地址'))
}
}
const rules = {
base_url: [{ validator: optionalUrlValidator, trigger: 'blur' }],
notify_url: [{ validator: optionalUrlValidator, trigger: 'blur' }],
return_url: [{ validator: optionalUrlValidator, trigger: 'blur' }]
}
const isConfigured = computed(() => {
return Boolean(form.base_url && form.pid && form.key && form.notify_url)
})
const getChannelText = (channel) => {
const map = {
alipay: '支付宝',
wxpay: '微信支付'
}
return map[channel] || channel || '-'
}
const assignForm = (data = {}) => {
Object.assign(form, {
base_url: data.base_url || '',
pid: data.pid || '',
key: data.key || '',
notify_url: data.notify_url || '',
return_url: data.return_url || '',
channel_type: data.channel_type || ''
})
originalForm.value = { ...form }
}
const fetchConfig = async () => {
loading.value = true
try {
const res = await getPay007Config()
if (res.data.code === 200) {
assignForm(res.data.data || {})
} else {
ElMessage.error(res.data.message || '获取支付配置失败')
}
} catch (error) {
console.error('获取 007pay 支付配置失败:', error)
ElMessage.error(error.response?.data?.message || '获取支付配置失败')
} finally {
loading.value = false
}
}
const submitForm = async () => {
const formEl = formRef.value
if (formEl) {
const valid = await formEl.validate().catch(() => false)
if (!valid) return
}
saving.value = true
try {
const res = await updatePay007Config({ ...form })
if (res.data.code === 200) {
assignForm(res.data.data || form)
ElMessage.success('支付配置已保存')
} else {
ElMessage.error(res.data.message || '保存支付配置失败')
}
} catch (error) {
console.error('保存 007pay 支付配置失败:', error)
ElMessage.error(error.response?.data?.message || '保存支付配置失败')
} finally {
saving.value = false
}
}
const resetForm = () => {
Object.assign(form, originalForm.value)
formRef.value?.clearValidate()
}
onMounted(fetchConfig)
</script>
<style scoped>
.payment-config-page {
display: flex;
flex-direction: column;
gap: 16px;
}
.page-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
padding: 18px 20px;
background: #fff;
border: 1px solid #e4e7ed;
border-radius: 8px;
}
.title-block {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
}
.title-icon {
width: 42px;
height: 42px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
background: #f0f9eb;
color: #67c23a;
font-size: 22px;
flex-shrink: 0;
}
.title-block h2 {
margin: 0;
color: #1f2d3d;
font-size: 18px;
font-weight: 600;
}
.title-block p {
margin: 4px 0 0;
color: #909399;
font-size: 13px;
}
.toolbar-actions {
display: flex;
gap: 10px;
flex-shrink: 0;
}
.summary-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
}
.summary-item {
padding: 14px 16px;
background: #fff;
border: 1px solid #ebeef5;
border-radius: 8px;
}
.summary-label {
color: #909399;
font-size: 12px;
margin-bottom: 8px;
}
.summary-value {
min-height: 24px;
color: #303133;
font-size: 15px;
font-weight: 600;
word-break: break-all;
}
.summary-value.mono {
font-family: Consolas, Monaco, monospace;
}
.config-panel {
padding: 24px 22px 18px;
background: #fff;
border: 1px solid #e4e7ed;
border-radius: 8px;
}
.config-form {
max-width: 880px;
}
.panel-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding-top: 18px;
border-top: 1px solid #f0f2f5;
}
@media (max-width: 900px) {
.page-toolbar {
align-items: flex-start;
flex-direction: column;
}
.toolbar-actions {
width: 100%;
justify-content: flex-end;
}
.summary-grid {
grid-template-columns: 1fr;
}
}
</style>
+37 -4
View File
@@ -213,6 +213,17 @@
<el-tag :type="getOrderStatusType(row.state)" size="small">{{ getOrderStatusText(row.state) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="支付方式" width="100">
<template #default="{row}">{{ getOrderPayTypeText(row.payType) }}</template>
</el-table-column>
<el-table-column label="退款" width="95">
<template #default="{row}">
<el-tag v-if="row.refundStatus" :type="getOrderRefundStatusType(row.refundStatus)" size="small">
{{ getOrderRefundStatusText(row.refundStatus) }}
</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="到期时间" width="160">
<template #default="{row}">{{ row.expireTime ? formatDate(row.expireTime) : '-' }}</template>
</el-table-column>
@@ -1463,26 +1474,48 @@ const fetchUserBalance = async () => {
//
const getOrderStatusText = (state) => {
const map = { 0: '待支付', 1: '已支付', 2: '已取消', 3: '已退款', 4: '已完成' }
const map = { 0: '待支付', 1: '已支付', 2: '已失效' }
return map[state] || '未知'
}
const getOrderStatusType = (state) => {
const map = { 0: 'warning', 1: 'success', 2: 'info', 3: 'danger', 4: 'success' }
const map = { 0: 'warning', 1: 'success', 2: 'info' }
return map[state] || 'info'
}
//
const getOrderTypeText = (type) => {
const map = { create: '新购', renew: '续费', upgrade: '升级' }
const map = { create: '新购', renew: '续费', update: '升级', snapshot: '快照', backup: '备份', data_volume: '数据盘', ipv4: 'IPv4', ipv6: 'IPv6', traffic: '流量', rebuild_image_diff: '重装差价' }
return map[type] || type || '未知'
}
const getOrderTypeTag = (type) => {
const map = { create: 'primary', renew: 'success', upgrade: 'warning' }
const map = { create: 'primary', renew: 'success', update: 'warning' }
return map[type] || 'info'
}
const getOrderPayTypeText = (payType) => {
const map = {
default: '默认/余额',
balance: '余额',
'007pay': '007pay',
admin: '管理员',
ali: '支付宝',
wx: '微信'
}
return map[payType] || payType || '-'
}
const getOrderRefundStatusText = (status) => {
const map = { pending: '退款中', success: '已退款', failed: '退款失败' }
return map[status] || status || '-'
}
const getOrderRefundStatusType = (status) => {
const map = { pending: 'warning', success: 'success', failed: 'danger' }
return map[status] || 'info'
}
//
const getTicketStatusText = (status) => {
const map = { 0: '待处理', 1: '处理中', 2: '已回复', 3: '已关闭' }