column('id', 'ID')->sortable();
$grid->column('transfer_app.title', '应用名称')->limit(15);
$grid->column('out_order_id', '外部订单ID')->copyable();
$grid->column('user_id', '用户ID')->link(function ($value) {
return admin_url("users/{$value}");
});
$grid->column('out_user_id', '外部用户ID')->limit(15);
$grid->column('type', '类型')->display(function ($value) {
$typeMap = [
1 => '转入',
2 => '转出',
];
$labelMap = [
1 => 'success',
2 => 'warning',
];
// 处理枚举对象
$typeValue = is_object($value) ? $value->value : $value;
$text = $typeMap[$typeValue] ?? '未知';
$label = $labelMap[$typeValue] ?? 'default';
return "{$text}";
});
$grid->column('status', '状态')->display(function ($value) {
$statusMap = [
1 => '已创建',
20 => '处理中',
30 => '已回调',
100 => '已完成',
-1 => '失败',
];
$labelMap = [
1 => 'info',
20 => 'warning',
30 => 'primary',
100 => 'success',
-1 => 'danger',
];
// 处理枚举对象
$statusValue = is_object($value) ? $value->value : $value;
$text = $statusMap[$statusValue] ?? '未知';
$label = $labelMap[$statusValue] ?? 'default';
return "{$text}";
});
$grid->column('out_amount', '外部金额')->display(function ($value) {
return number_format($value, 4);
});
$grid->column('amount', '内部金额')->display(function ($value) {
return number_format($value, 4);
});
// 手续费信息
$grid->column('fee_info', '手续费信息')->display(function () {
if ($this->fee_amount > 0) {
$feeRate = number_format($this->fee_rate * 100, 2) . '%';
$feeAmount = number_format($this->fee_amount, 4);
$actualAmount = number_format($this->actual_amount, 4);
return "费率: {$feeRate}
手续费: {$feeAmount}
实际: {$actualAmount}";
}
return '无手续费';
});
$grid->column('exchange_rate', '汇率')->display(function ($value) {
return number_format($value, 4);
});
$grid->column('created_at', '创建时间')->display(function ($value) {
return $value ? $value->format('Y-m-d H:i:s') : '-';
})->sortable();
$grid->column('completed_at', '完成时间')->display(function ($value) {
return $value ? $value->format('Y-m-d H:i:s') : '-';
});
// 处理时长
$grid->column('duration', '处理时长')->display(function () {
if ($this->completed_at && $this->created_at) {
// 确保计算正确的时间差(完成时间 - 创建时间)
$seconds = $this->completed_at->getTimestamp() - $this->created_at->getTimestamp();
// 如果时间差为负数或0,显示为0秒
if ($seconds <= 0) {
return '0秒';
}
if ($seconds < 60) {
return $seconds . '秒';
} elseif ($seconds < 3600) {
return round($seconds / 60, 1) . '分钟';
} else {
return round($seconds / 3600, 1) . '小时';
}
}
return '-';
});
// 筛选器
$grid->filter(function (Grid\Filter $filter) {
$filter->equal('transfer_app_id', '应用')->select(
\App\Module\Transfer\Models\TransferApp::pluck('title', 'id')
);
$filter->equal('type', '类型')->select([
1 => '转入',
2 => '转出',
]);
$filter->equal('status', '状态')->select([
1 => '已创建',
20 => '处理中',
30 => '已回调',
100 => '已完成',
-1 => '失败',
]);
$filter->equal('user_id', '用户ID');
$filter->like('out_order_id', '外部订单ID');
$filter->like('out_user_id', '外部用户ID');
$filter->between('amount', '内部金额');
$filter->between('created_at', '创建时间')->datetime();
});
// 操作按钮
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableDelete(); // 禁用删除
$actions->disableEdit(); // 禁用编辑
// 重新处理按钮
if ($this->canRetry()) {
$actions->append('重新处理');
}
// 手动完成按钮(仅转出订单)
if ($this->isTransferOut() && !$this->isFinalStatus()) {
$actions->append('手动完成');
}
});
// 批量操作
$grid->batchActions(function (Grid\Tools\BatchActions $batch) {
$batch->add(new \App\Module\Transfer\AdminControllers\Tools\RetryOrderTool());
});
// 工具栏
$grid->tools(function (Grid\Tools $tools) {
$tools->append('统计信息');
$tools->append(new \App\Module\Transfer\AdminControllers\Tools\ExportOrderTool());
});
// 默认排序
$grid->model()->orderBy('created_at', 'desc');
}
/**
* 配置Show详情
*/
public static function show(Show $show): void
{
$show->field('id', 'ID');
$show->divider();
$show->field('transfer_app.title', '应用名称');
$show->field('out_order_id', '外部订单ID');
$show->field('out_user_id', '外部用户ID');
$show->field('user_id', '内部用户ID');
$show->field('type', '订单类型')->using([
1 => '转入',
2 => '转出',
]);
$show->field('status', '订单状态')->using([
1 => '已创建',
20 => '处理中',
30 => '已回调',
100 => '已完成',
-1 => '失败',
]);
$show->divider();
$show->field('out_amount', '外部金额')->as(function ($value) {
return number_format($value, 10);
});
$show->field('amount', '内部金额')->as(function ($value) {
return number_format($value, 10);
});
$show->field('exchange_rate', '使用汇率')->as(function ($value) {
return number_format($value, 4);
});
// 手续费信息
$show->field('fee_rate', '手续费率')->as(function ($value) {
return number_format($value * 100, 2) . '%';
});
$show->field('fee_amount', '手续费金额')->as(function ($value) {
return number_format($value, 4);
});
$show->field('actual_amount', '实际到账金额')->as(function ($value) {
return number_format($value, 4);
});
$show->field('has_fee', '是否收取手续费')->as(function () {
return $this->fee_amount > 0 ? '是' : '否';
});
$show->divider();
$show->field('currency_id', '货币类型')->using([
1 => '金币',
2 => '钻石',
3 => '人民币',
4 => '美元',
]);
$show->field('fund_id', '资金账户类型');
$show->divider();
$show->field('callback_data', '回调数据')->json();
$show->divider();
$show->field('error_message', '错误信息');
$show->field('remark', '备注信息');
$show->divider();
$show->field('created_at', '创建时间')->as(function ($value) {
if (!$value) return '-';
if (is_string($value)) {
// 如果是ISO格式字符串,转换为友好格式
try {
return \Carbon\Carbon::parse($value)->format('Y-m-d H:i:s');
} catch (\Exception $e) {
return $value; // 如果解析失败,返回原值
}
}
return $value->format('Y-m-d H:i:s');
});
$show->field('processed_at', '处理时间')->as(function ($value) {
if (!$value) return '-';
if (is_string($value)) {
try {
return \Carbon\Carbon::parse($value)->format('Y-m-d H:i:s');
} catch (\Exception $e) {
return $value;
}
}
return $value->format('Y-m-d H:i:s');
});
$show->field('callback_at', '回调时间')->as(function ($value) {
if (!$value) return '-';
if (is_string($value)) {
try {
return \Carbon\Carbon::parse($value)->format('Y-m-d H:i:s');
} catch (\Exception $e) {
return $value;
}
}
return $value->format('Y-m-d H:i:s');
});
$show->field('completed_at', '完成时间')->as(function ($value) {
if (!$value) return '-';
if (is_string($value)) {
try {
return \Carbon\Carbon::parse($value)->format('Y-m-d H:i:s');
} catch (\Exception $e) {
return $value;
}
}
return $value->format('Y-m-d H:i:s');
});
$show->field('updated_at', '更新时间')->as(function ($value) {
if (!$value) return '-';
if (is_string($value)) {
try {
return \Carbon\Carbon::parse($value)->format('Y-m-d H:i:s');
} catch (\Exception $e) {
return $value;
}
}
return $value->format('Y-m-d H:i:s');
});
// 处理时长
$show->field('processing_duration', '处理时长')->as(function () {
if ($this->completed_at && $this->created_at) {
return $this->completed_at->diffForHumans($this->created_at, true);
}
return '未完成';
});
}
/**
* 获取状态统计
*/
public static function getStatusStats(): array
{
$stats = TransferOrder::selectRaw('status, COUNT(*) as count, SUM(amount) as amount')
->groupBy('status')
->get()
->keyBy('status');
$result = [];
foreach (TransferStatus::cases() as $status) {
$stat = $stats->get($status->value);
$result[] = [
'status' => $status->getDescription(),
'count' => $stat ? number_format($stat->count) : 0,
'amount' => $stat ? number_format($stat->amount, 2) : '0.00',
'color' => $status->getColor(),
];
}
return $result;
}
/**
* 获取类型统计
*/
public static function getTypeStats(): array
{
$stats = TransferOrder::selectRaw('type, COUNT(*) as count, SUM(amount) as amount')
->groupBy('type')
->get()
->keyBy('type');
$result = [];
foreach (TransferType::cases() as $type) {
$stat = $stats->get($type->value);
$result[] = [
'type' => $type->getDescription(),
'count' => $stat ? number_format($stat->count) : 0,
'amount' => $stat ? number_format($stat->amount, 2) : '0.00',
'color' => $type->getColor(),
];
}
return $result;
}
/**
* 获取今日统计
*/
public static function getTodayStats(): array
{
$today = now()->startOfDay();
$total = TransferOrder::where('created_at', '>=', $today)->count();
$completed = TransferOrder::where('created_at', '>=', $today)
->where('status', TransferStatus::COMPLETED)->count();
$failed = TransferOrder::where('created_at', '>=', $today)
->where('status', TransferStatus::FAILED)->count();
$amount = TransferOrder::where('created_at', '>=', $today)->sum('amount');
$feeAmount = TransferOrder::where('created_at', '>=', $today)->sum('fee_amount');
return [
'total' => number_format($total),
'completed' => number_format($completed),
'failed' => number_format($failed),
'success_rate' => $total > 0 ? number_format($completed / $total * 100, 1) . '%' : '0%',
'amount' => number_format($amount, 2),
'fee_amount' => number_format($feeAmount, 2),
];
}
/**
* 获取手续费统计
*/
public static function getFeeStats(): array
{
$stats = TransferOrder::selectRaw('
COUNT(*) as total_orders,
SUM(fee_amount) as total_fee,
AVG(fee_rate) as avg_fee_rate,
SUM(CASE WHEN type = 1 THEN fee_amount ELSE 0 END) as in_fee,
SUM(CASE WHEN type = 2 THEN fee_amount ELSE 0 END) as out_fee,
COUNT(CASE WHEN type = 1 THEN 1 END) as in_orders,
COUNT(CASE WHEN type = 2 THEN 1 END) as out_orders
')
->where('status', TransferStatus::COMPLETED)
->where('fee_amount', '>', 0)
->first();
return [
'total_orders' => number_format($stats->total_orders ?? 0),
'total_fee' => number_format($stats->total_fee ?? 0, 4),
'avg_fee_rate' => number_format(($stats->avg_fee_rate ?? 0) * 100, 2) . '%',
'in_fee' => number_format($stats->in_fee ?? 0, 4),
'out_fee' => number_format($stats->out_fee ?? 0, 4),
'in_orders' => number_format($stats->in_orders ?? 0),
'out_orders' => number_format($stats->out_orders ?? 0),
];
}
}