237 lines
9.0 KiB
PHP
237 lines
9.0 KiB
PHP
@extends('admin.content')
|
||
|
||
@section('title', '交易记录')
|
||
|
||
@section('content')
|
||
@php $portal = $portal ?? 'admin'; @endphp
|
||
<style>
|
||
.tx-cell { word-break: break-all; font-family: Menlo, Monaco, Consolas, monospace; font-size: 12px; }
|
||
.tx-status-success { color: #16b777; font-weight: 600; }
|
||
.tx-status-failed { color: #ff5722; font-weight: 600; }
|
||
.tx-chain-tag {
|
||
display: inline-block;
|
||
padding: 0 8px;
|
||
line-height: 20px;
|
||
border-radius: 2px;
|
||
font-size: 12px;
|
||
color: #fff;
|
||
background: #909399;
|
||
}
|
||
.tx-chain-eth, .tx-chain-ethereum { background: #627eea; }
|
||
.tx-chain-btc, .tx-chain-bitcoin { background: #f7931a; }
|
||
.tx-chain-trx, .tx-chain-tron { background: #ff0013; }
|
||
.tx-summary {
|
||
margin: 0 0 12px;
|
||
padding: 10px 14px;
|
||
background: #f8fafc;
|
||
border: 1px solid #eef2f6;
|
||
border-radius: 2px;
|
||
font-size: 14px;
|
||
color: #334155;
|
||
}
|
||
.tx-summary b { color: #0f172a; }
|
||
.tx-summary .tx-sum-asset { margin-left: 16px; font-weight: 600; color: #0f766e; }
|
||
.tx-summary .tx-sum-asset:first-child { margin-left: 0; }
|
||
</style>
|
||
<div class="layui-card">
|
||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-tx-search">
|
||
<div class="layui-form-item">
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">时间范围</label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="date_range" id="LAY-tx-date-range" class="layui-input" placeholder="开始日期 - 结束日期" autocomplete="off" style="width: 230px;">
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">From</label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="from_address" class="layui-input" autocomplete="off">
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">To</label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="to_address" class="layui-input" autocomplete="off">
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">Tx Hash</label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="tx_hash" class="layui-input" autocomplete="off">
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">链</label>
|
||
<div class="layui-input-block">
|
||
<select name="chain">
|
||
<option value="">全部</option>
|
||
@foreach ($chains as $value => $label)
|
||
<option value="{{ $value }}">{{ $label }}</option>
|
||
@endforeach
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">资产</label>
|
||
<div class="layui-input-block">
|
||
<select name="asset">
|
||
<option value="">全部</option>
|
||
@foreach ($assets as $a)
|
||
<option value="{{ $a }}">{{ $a }}</option>
|
||
@endforeach
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">状态</label>
|
||
<div class="layui-input-block">
|
||
<select name="status">
|
||
<option value="">全部</option>
|
||
<option value="success">success</option>
|
||
<option value="failed">failed</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">操作者</label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="operator" class="layui-input" autocomplete="off">
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<button class="layui-btn" lay-submit lay-filter="LAY-tx-search">搜索</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
<div class="layui-card-body">
|
||
<div class="tx-summary" id="LAY-tx-summary">成功归集金额: —</div>
|
||
<table id="LAY-tx-list" lay-filter="LAY-tx-list"></table>
|
||
<script type="text/html" id="LAY-tx-ops">
|
||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">详情</a>
|
||
</script>
|
||
</div>
|
||
</div>
|
||
@endsection
|
||
|
||
@push('scripts')
|
||
<script>
|
||
layui.use(['table', 'form', 'laydate', 'layer'], function () {
|
||
var table = layui.table, form = layui.form, layer = layui.layer;
|
||
var laydate = layui.laydate;
|
||
var $ = layui.$;
|
||
|
||
laydate.render({
|
||
elem: '#LAY-tx-date-range',
|
||
type: 'date',
|
||
range: true
|
||
});
|
||
|
||
function parseRange(value) {
|
||
var m = String(value || '').match(/^(\d{4}-\d{2}-\d{2})\s*-\s*(\d{4}-\d{2}-\d{2})$/);
|
||
if (!m) return { date_from: '', date_to: '', date_range: '' };
|
||
return { date_from: m[1], date_to: m[2], date_range: m[1] + ' - ' + m[2] };
|
||
}
|
||
|
||
function searchWhere(field) {
|
||
var parsed = parseRange(field.date_range || $('#LAY-tx-date-range').val());
|
||
return Object.assign({}, field, parsed);
|
||
}
|
||
|
||
function amountParts(totals) {
|
||
var parts = (totals || []).filter(function (row) { return parseFloat(row.amount) > 0; });
|
||
if (!parts.length) return '<span class="tx-sum-asset">0 USDT</span>';
|
||
return parts.map(function (row) {
|
||
return '<span class="tx-sum-asset">' + row.amount + ' ' + row.asset + '</span>';
|
||
}).join('');
|
||
}
|
||
|
||
function renderSummary(summary) {
|
||
summary = summary || {};
|
||
$('#LAY-tx-summary').html(
|
||
'<div><b>成功归集金额:</b> ' + amountParts(summary.totals) + '</div>' +
|
||
'<div style="margin-top:6px;"><b>手续费补足金额:</b> ' + amountParts(summary.fee_totals) + '</div>'
|
||
);
|
||
}
|
||
|
||
function chainTag(chain) {
|
||
var raw = String(chain || '—');
|
||
var key = raw.toLowerCase().replace(/[^a-z0-9]+/g, '');
|
||
return '<span class="tx-chain-tag tx-chain-' + (key || 'unknown') + '">' + raw + '</span>';
|
||
}
|
||
|
||
function statusHtml(status) {
|
||
var s = String(status || '');
|
||
if (s === 'success') return '<span class="tx-status-success">success</span>';
|
||
if (s === 'failed') return '<span class="tx-status-failed">failed</span>';
|
||
return s || '—';
|
||
}
|
||
|
||
table.render({
|
||
elem: '#LAY-tx-list',
|
||
id: 'LAY-tx-list',
|
||
url: @json(route($portal.'.transfers.data')),
|
||
cols: [[
|
||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||
{ field: 'chain', title: '链', width: 90, templet: function (d) { return chainTag(d.chain); } },
|
||
{ field: 'asset', title: '资产', width: 80, sort: true },
|
||
{ field: 'amount', title: '金额', width: 120, sort: true },
|
||
{ field: 'from_address', title: 'From', minWidth: 220, templet: function (d) {
|
||
return '<span class="tx-cell">' + (d.from_address || '') + '</span>';
|
||
}},
|
||
{ field: 'to_address', title: 'To', minWidth: 220, templet: function (d) {
|
||
return '<span class="tx-cell">' + (d.to_address || '') + '</span>';
|
||
}},
|
||
{ field: 'tx_hash', title: 'Tx Hash', minWidth: 220, templet: function (d) {
|
||
return '<span class="tx-cell">' + (d.tx_hash || '—') + '</span>';
|
||
}},
|
||
{ field: 'status', title: '状态', width: 90, sort: true, templet: function (d) {
|
||
return statusHtml(d.status);
|
||
}},
|
||
{ field: 'operator', title: '操作者', width: 120 },
|
||
{ field: 'type', title: '类型', width: 70 },
|
||
{ field: 'created_at', title: '时间', width: 170, sort: true },
|
||
{ title: '操作', width: 90, align: 'center', fixed: 'right', toolbar: '#LAY-tx-ops' }
|
||
]],
|
||
page: true, limit: 20, limits: [10, 20, 30, 50],
|
||
request: { pageName: 'page', limitName: 'limit' },
|
||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' },
|
||
done: function (res) {
|
||
renderSummary(res.summary);
|
||
}
|
||
});
|
||
|
||
form.on('submit(LAY-tx-search)', function (data) {
|
||
table.reload('LAY-tx-list', { where: searchWhere(data.field), page: { curr: 1 } });
|
||
return false;
|
||
});
|
||
|
||
table.on('tool(LAY-tx-list)', function (obj) {
|
||
if (obj.event !== 'detail') return;
|
||
var d = obj.data;
|
||
var esc = function (v) {
|
||
return String(v == null || v === '' ? '—' : v)
|
||
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||
};
|
||
layer.open({
|
||
type: 1,
|
||
title: '交易详情 — #' + d.id,
|
||
area: ['640px', '480px'],
|
||
content:
|
||
'<div style="padding:16px;line-height:1.8;font-size:13px;">' +
|
||
'<div><b>状态</b>:' + statusHtml(d.status) + '</div>' +
|
||
'<div><b>链 / 资产</b>:' + esc(d.chain) + ' / ' + esc(d.asset) + '</div>' +
|
||
'<div><b>金额</b>:' + esc(d.amount) + '</div>' +
|
||
'<div><b>类型</b>:' + esc(d.type) + '</div>' +
|
||
'<div><b>From</b>:<span class="tx-cell">' + esc(d.from_address) + '</span></div>' +
|
||
'<div><b>To</b>:<span class="tx-cell">' + esc(d.to_address) + '</span></div>' +
|
||
'<div><b>Tx Hash</b>:<span class="tx-cell">' + esc(d.tx_hash) + '</span></div>' +
|
||
'<div><b>操作者</b>:' + esc(d.operator) + '</div>' +
|
||
'<div><b>时间</b>:' + esc(d.created_at) + '</div>' +
|
||
'<div style="margin-top:8px;"><b>错误</b>:<pre style="white-space:pre-wrap;word-break:break-all;margin:4px 0 0;">' + esc(d.error) + '</pre></div>' +
|
||
'</div>'
|
||
});
|
||
});
|
||
});
|
||
</script>
|
||
@endpush
|