From 35762c67e6ec64b7665b26dd82d5e2641b3e13d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=AF=E4=B9=90=E5=8A=A0=E5=86=B0?= <11869599+addie66@user.noreply.gitee.com> Date: Thu, 8 Oct 2026 15:44:59 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat(shopro=5Fwechat=5Ftrade):=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1=E5=8F=91=E8=B4=A7/?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E6=94=B6=E8=B4=A7=E5=90=8C=E6=AD=A5=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加统计信息显示、筛选搜索功能和详细信息弹窗,优化用户体验 - 添加buildQuery方法用于构建查询条件,支持状态、同步类型和订单号筛选 - 添加getStats方法获取各状态统计数据并在页面显示统计栏 - 在index页面增加类型筛选、订单号搜索、重置和仅看失败按钮 - 实现detail方法用于获取同步记录详情 - 增加详细的CSS样式和前端交互逻辑 - 添加防止重复重试成功记录的验证 - 格式化JSON数据显示和错误信息展示 ``` --- .../controller/shopro_wechat_trade/Sync.php | 56 +++- .../view/shopro_wechat_trade/sync/index.html | 122 ++++++++- .../js/backend/shopro_wechat_trade/sync.js | 247 ++++++++++++++++-- .../controller/shopro_wechat_trade/Sync.php | 56 +++- .../view/shopro_wechat_trade/sync/index.html | 122 ++++++++- 5 files changed, 561 insertions(+), 42 deletions(-) diff --git a/addons/shopro_wechat_trade/application/admin/controller/shopro_wechat_trade/Sync.php b/addons/shopro_wechat_trade/application/admin/controller/shopro_wechat_trade/Sync.php index 021b26e..72f713f 100644 --- a/addons/shopro_wechat_trade/application/admin/controller/shopro_wechat_trade/Sync.php +++ b/addons/shopro_wechat_trade/application/admin/controller/shopro_wechat_trade/Sync.php @@ -8,25 +8,68 @@ use think\Db; class Sync extends Backend { + protected function buildQuery($status = '', $syncType = '', $orderSn = '') + { + $query = Db::name('shopro_wechat_trade_sync'); + if ($status !== '') { + $query->where('status', $status); + } + if ($syncType !== '') { + $query->where('sync_type', $syncType); + } + if ($orderSn !== '') { + $query->where('order_sn', 'like', '%' . $orderSn . '%'); + } + return $query; + } + + protected function getStats() + { + $rows = Db::name('shopro_wechat_trade_sync') + ->field('status, COUNT(*) AS cnt') + ->group('status') + ->select(); + $stats = ['success' => 0, 'pending' => 0, 'failed' => 0, 'total' => 0]; + foreach ($rows as $row) { + $key = $row['status'] ?? ''; + if (isset($stats[$key])) { + $stats[$key] = intval($row['cnt']); + } + $stats['total'] += intval($row['cnt']); + } + return $stats; + } + public function index() { if ($this->request->isAjax()) { $page = max(1, intval($this->request->get('page', 1))); $limit = max(1, min(100, intval($this->request->get('limit', 20)))); $status = trim($this->request->get('status', '')); + $syncType = trim($this->request->get('sync_type', '')); + $orderSn = trim($this->request->get('order_sn', '')); - $query = Db::name('shopro_wechat_trade_sync')->order('id', 'desc'); - if ($status !== '') { - $query->where('status', $status); - } - $total = $query->count(); + $query = $this->buildQuery($status, $syncType, $orderSn)->order('id', 'desc'); + $total = (clone $query)->count(); $list = $query->page($page, $limit)->select(); return json(['total' => $total, 'rows' => $list]); } + + $this->view->assign('stats', $this->getStats()); return $this->view->fetch(); } + public function detail() + { + $id = intval($this->request->get('id')); + $row = Db::name('shopro_wechat_trade_sync')->where('id', $id)->find(); + if (!$row) { + $this->error('记录不存在'); + } + $this->success('', null, $row); + } + public function retry() { $id = intval($this->request->post('id')); @@ -34,6 +77,9 @@ class Sync extends Backend if (!$row) { $this->error('记录不存在'); } + if ($row['status'] === 'success') { + $this->error('该记录已同步成功,无需重试'); + } try { $service = new WxShippingService(); if ($row['sync_type'] === 'confirm') { diff --git a/addons/shopro_wechat_trade/application/admin/view/shopro_wechat_trade/sync/index.html b/addons/shopro_wechat_trade/application/admin/view/shopro_wechat_trade/sync/index.html index 25b1192..72c7f22 100644 --- a/addons/shopro_wechat_trade/application/admin/view/shopro_wechat_trade/sync/index.html +++ b/addons/shopro_wechat_trade/application/admin/view/shopro_wechat_trade/sync/index.html @@ -1,14 +1,122 @@ -
-
微信发货/确认收货同步日志
+ +
+
+ 微信发货/确认收货同步日志 + 记录向微信平台同步的操作结果,供排查与手动重试 +
-
- - - - + + + + + + + +
+ +
+
+
记录ID:
+
订单号:
+
同步类型:
+
同步状态:
+
发货模式:
+
重试次数:
+
错误信息:
+
创建时间:
+
更新时间:
+
请求内容:
+

+        
响应内容:
+

+    
+
diff --git a/addons/shopro_wechat_trade/public/assets/js/backend/shopro_wechat_trade/sync.js b/addons/shopro_wechat_trade/public/assets/js/backend/shopro_wechat_trade/sync.js index 60d37d1..b772d75 100644 --- a/addons/shopro_wechat_trade/public/assets/js/backend/shopro_wechat_trade/sync.js +++ b/addons/shopro_wechat_trade/public/assets/js/backend/shopro_wechat_trade/sync.js @@ -1,4 +1,84 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + var SYNC_TYPE_MAP = { + shipping: '发货同步', + confirm: '确认收货同步' + }; + + var DELIVERY_MODE_MAP = { + 1: '统一发货', + 2: '分拆发货' + }; + + function escapeHtml(text) { + return $('
').text(text == null ? '' : text).html(); + } + + function formatSyncType(value) { + var text = SYNC_TYPE_MAP[value] || value || '-'; + if (value === 'shipping') { + return '' + text + ''; + } + if (value === 'confirm') { + return '' + text + ''; + } + return text; + } + + function formatStatus(row) { + var status = row.status; + var retryCount = parseInt(row.retry_count, 10) || 0; + if (status === 'success') { + return '成功'; + } + if (status === 'failed') { + return '失败'; + } + if (status === 'pending') { + if (retryCount > 0) { + return '待重试'; + } + return '处理中'; + } + return status || '-'; + } + + function formatDeliveryMode(value, row) { + if (row.sync_type !== 'shipping') { + return '-'; + } + var text = DELIVERY_MODE_MAP[value] || ('模式' + value); + return text; + } + + function formatErrorInfo(value, row) { + if (row.status === 'success') { + return '-'; + } + var parts = []; + if (row.errcode !== null && row.errcode !== undefined && row.errcode !== '') { + parts.push('[' + row.errcode + ']'); + } + if (row.errmsg) { + parts.push(row.errmsg); + } + return parts.length ? escapeHtml(parts.join(' ')) : '-'; + } + + function formatJsonText(raw) { + if (!raw) { + return '(无)'; + } + try { + return JSON.stringify(JSON.parse(raw), null, 2); + } catch (e) { + return raw; + } + } + + function formatDatetime(value) { + return value ? Table.api.formatter.datetime(value) : '-'; + } + var Controller = { index: function () { Table.api.init({ @@ -9,55 +89,186 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin }); var table = $("#table"); + table.bootstrapTable({ url: $.fn.bootstrapTable.defaults.extend.index_url, pk: 'id', sortName: 'id', sortOrder: 'desc', + search: false, + commonSearch: false, + showExport: false, queryParams: function (params) { params.status = $('#status-filter').val(); + params.sync_type = $('#type-filter').val(); + params.order_sn = $.trim($('#order-sn-filter').val()); return params; }, columns: [ - { field: 'id', title: 'ID' }, - { field: 'order_sn', title: '订单号' }, - { field: 'sync_type', title: '类型' }, - { field: 'status', title: '状态' }, - { field: 'delivery_mode', title: '发货模式' }, - { field: 'errcode', title: 'errcode' }, - { field: 'errmsg', title: 'errmsg' }, - { field: 'retry_count', title: '重试次数' }, + { field: 'id', title: 'ID', width: 70 }, + { + field: 'order_sn', + title: '订单号', + formatter: function (value, row) { + if (!value) { + return '-'; + } + if (row.order_id) { + return '' + escapeHtml(value) + ''; + } + return escapeHtml(value); + } + }, + { + field: 'sync_type', + title: '同步类型', + formatter: function (value) { + return formatSyncType(value); + } + }, + { + field: 'status', + title: '同步状态', + formatter: function (value, row) { + return formatStatus(row); + } + }, + { + field: 'delivery_mode', + title: '发货模式', + formatter: function (value, row) { + return formatDeliveryMode(value, row); + } + }, + { + field: 'errmsg', + title: '错误信息', + formatter: function (value, row) { + return formatErrorInfo(value, row); + } + }, + { + field: 'retry_count', + title: '重试次数', + width: 90, + formatter: function (value, row) { + if (row.status === 'success') { + return '-'; + } + return value || 0; + } + }, { field: 'createtime', title: '创建时间', - formatter: function (value) { - return value ? Table.api.formatter.datetime(value) : ''; - } + formatter: formatDatetime }, { field: 'operate', title: '操作', + width: 140, table: table, events: Table.api.events.operate, formatter: function (value, row) { - if (row.status === 'success') { - return '-'; + var html = []; + html.push('详情'); + if (row.status !== 'success') { + html.push(' 重试'); } - return '重试'; + return html.join(''); } } ] }); - $('#status-filter').on('change', function () { + function refreshTable() { table.bootstrapTable('refresh'); + } + + $('#status-filter, #type-filter').on('change', refreshTable); + + $('.btn-search').on('click', refreshTable); + + $('#order-sn-filter').on('keypress', function (e) { + if (e.which === 13) { + refreshTable(); + } + }); + + $('.btn-reset').on('click', function () { + $('#status-filter').val(''); + $('#type-filter').val(''); + $('#order-sn-filter').val(''); + refreshTable(); + }); + + $('.btn-filter-failed').on('click', function () { + $('#status-filter').val('failed'); + $('#type-filter').val(''); + refreshTable(); + }); + + table.on('click', '.btn-order', function () { + var orderId = $(this).data('id'); + Fast.api.open('shopro/order/order/detail?id=' + orderId, '订单详情'); }); table.on('click', '.btn-retry', function () { var id = $(this).data('id'); - $.post('shopro_wechat_trade/sync/retry', { id: id }, function (ret) { - Backend.api.toastr[ret.code === 1 ? 'success' : 'error'](ret.msg); - table.bootstrapTable('refresh'); + Layer.confirm('将重新向微信发起同步请求,是否继续?', { icon: 3, title: '确认重试' }, function (index) { + Layer.close(index); + $.post('shopro_wechat_trade/sync/retry', { id: id }, function (ret) { + Backend.api.toastr[ret.code === 1 ? 'success' : 'error'](ret.msg); + refreshTable(); + }); + }); + }); + + table.on('click', '.btn-detail', function () { + var id = $(this).data('id'); + $.get('shopro_wechat_trade/sync/detail', { id: id }, function (ret) { + if (ret.code !== 1) { + Backend.api.toastr.error(ret.msg || '加载失败'); + return; + } + var row = ret.data || {}; + var $tpl = $('#sync-detail-template').clone().removeAttr('id').removeClass('hide'); + $tpl.find('.detail-id').text(row.id || '-'); + $tpl.find('.detail-order-sn').text(row.order_sn || '-'); + $tpl.find('.detail-sync-type').html(formatSyncType(row.sync_type)); + $tpl.find('.detail-status').html(formatStatus(row)); + if (row.sync_type === 'shipping') { + $tpl.find('.detail-delivery-mode').text(DELIVERY_MODE_MAP[row.delivery_mode] || ('模式' + row.delivery_mode)); + $tpl.find('.detail-delivery-mode-row').show(); + } else { + $tpl.find('.detail-delivery-mode-row').hide(); + } + $tpl.find('.detail-retry').text(row.retry_count || 0); + if (row.status === 'success') { + $tpl.find('.detail-error-row').hide(); + } else { + var errParts = []; + if (row.errcode !== null && row.errcode !== undefined && row.errcode !== '') { + errParts.push('[' + row.errcode + ']'); + } + if (row.errmsg) { + errParts.push(row.errmsg); + } + $tpl.find('.detail-error').text(errParts.join(' ') || '-'); + $tpl.find('.detail-error-row').show(); + } + $tpl.find('.detail-create').text(formatDatetime(row.createtime)); + $tpl.find('.detail-update').text(formatDatetime(row.updatetime)); + $tpl.find('.detail-request').text(formatJsonText(row.request_payload)); + $tpl.find('.detail-response').text(formatJsonText(row.response_payload)); + + Layer.open({ + type: 1, + title: '同步记录详情 #' + row.id, + area: ['720px', '80%'], + shadeClose: true, + content: $tpl.prop('outerHTML') + }); }); }); diff --git a/application/admin/controller/shopro_wechat_trade/Sync.php b/application/admin/controller/shopro_wechat_trade/Sync.php index 021b26e..72f713f 100644 --- a/application/admin/controller/shopro_wechat_trade/Sync.php +++ b/application/admin/controller/shopro_wechat_trade/Sync.php @@ -8,25 +8,68 @@ use think\Db; class Sync extends Backend { + protected function buildQuery($status = '', $syncType = '', $orderSn = '') + { + $query = Db::name('shopro_wechat_trade_sync'); + if ($status !== '') { + $query->where('status', $status); + } + if ($syncType !== '') { + $query->where('sync_type', $syncType); + } + if ($orderSn !== '') { + $query->where('order_sn', 'like', '%' . $orderSn . '%'); + } + return $query; + } + + protected function getStats() + { + $rows = Db::name('shopro_wechat_trade_sync') + ->field('status, COUNT(*) AS cnt') + ->group('status') + ->select(); + $stats = ['success' => 0, 'pending' => 0, 'failed' => 0, 'total' => 0]; + foreach ($rows as $row) { + $key = $row['status'] ?? ''; + if (isset($stats[$key])) { + $stats[$key] = intval($row['cnt']); + } + $stats['total'] += intval($row['cnt']); + } + return $stats; + } + public function index() { if ($this->request->isAjax()) { $page = max(1, intval($this->request->get('page', 1))); $limit = max(1, min(100, intval($this->request->get('limit', 20)))); $status = trim($this->request->get('status', '')); + $syncType = trim($this->request->get('sync_type', '')); + $orderSn = trim($this->request->get('order_sn', '')); - $query = Db::name('shopro_wechat_trade_sync')->order('id', 'desc'); - if ($status !== '') { - $query->where('status', $status); - } - $total = $query->count(); + $query = $this->buildQuery($status, $syncType, $orderSn)->order('id', 'desc'); + $total = (clone $query)->count(); $list = $query->page($page, $limit)->select(); return json(['total' => $total, 'rows' => $list]); } + + $this->view->assign('stats', $this->getStats()); return $this->view->fetch(); } + public function detail() + { + $id = intval($this->request->get('id')); + $row = Db::name('shopro_wechat_trade_sync')->where('id', $id)->find(); + if (!$row) { + $this->error('记录不存在'); + } + $this->success('', null, $row); + } + public function retry() { $id = intval($this->request->post('id')); @@ -34,6 +77,9 @@ class Sync extends Backend if (!$row) { $this->error('记录不存在'); } + if ($row['status'] === 'success') { + $this->error('该记录已同步成功,无需重试'); + } try { $service = new WxShippingService(); if ($row['sync_type'] === 'confirm') { diff --git a/application/admin/view/shopro_wechat_trade/sync/index.html b/application/admin/view/shopro_wechat_trade/sync/index.html index 25b1192..72c7f22 100644 --- a/application/admin/view/shopro_wechat_trade/sync/index.html +++ b/application/admin/view/shopro_wechat_trade/sync/index.html @@ -1,14 +1,122 @@ -
-
微信发货/确认收货同步日志
+ +
+
+ 微信发货/确认收货同步日志 + 记录向微信平台同步的操作结果,供排查与手动重试 +
-
- - - - + + + + + + + +
+ +
+
+
记录ID:
+
订单号:
+
同步类型:
+
同步状态:
+
发货模式:
+
重试次数:
+
错误信息:
+
创建时间:
+
更新时间:
+
请求内容:
+

+        
响应内容:
+

+    
+