From 5aad85110814cb1fdb746ee1e73c65e6647eacda Mon Sep 17 00:00:00 2001 From: zhenhui <1276357500@qq.com> Date: Tue, 21 Jul 2026 15:46:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=AF=8F=E6=97=A5=E6=8E=A8?= =?UTF-8?q?=E9=80=81=E7=9A=84=E5=AF=BC=E5=87=BA=E5=92=8C=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/controller/mall/DailyPush.php | 73 +++++++++++++++++++ web/src/lang/backend/en/mall/dailyPush.ts | 14 ++++ web/src/lang/backend/zh-cn/mall/dailyPush.ts | 14 ++++ .../views/backend/mall/dailyPush/index.vue | 24 ++++-- 4 files changed, 119 insertions(+), 6 deletions(-) diff --git a/app/admin/controller/mall/DailyPush.php b/app/admin/controller/mall/DailyPush.php index 68dd280..01cf9bf 100644 --- a/app/admin/controller/mall/DailyPush.php +++ b/app/admin/controller/mall/DailyPush.php @@ -4,6 +4,7 @@ namespace app\admin\controller\mall; use Throwable; use app\common\library\MallDailyPushBackfill; +use app\common\library\MallDailyPushExport; use app\common\controller\Backend; use support\Response; use Webman\Http\Request; @@ -35,6 +36,11 @@ class DailyPush extends Backend 'create_time', ]; + /** + * exportCount 与 export 共用导出权限 + */ + protected array $noNeedPermission = ['exportCount']; + public function initialize(): void { parent::initialize(); @@ -59,6 +65,73 @@ class DailyPush extends Backend return $this->_index(); } + /** + * 导出筛选结果条数预览 + */ + public function exportCount(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) { + return $response; + } + + if (!$this->auth->check('mall/dailyPush/export')) { + return $this->error(__('You have no permission'), [], 401); + } + + try { + [$where, $alias] = $this->buildExportQueryParts(); + $count = $this->model->alias($alias)->where($where)->count(); + $exporter = new MallDailyPushExport(); + return $this->success('', [ + 'count' => $count, + 'max_limit' => $exporter->getMaxExportLimit(), + ]); + } catch (Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * 导出 Excel(CSV 流式写入,兼容 Excel 打开) + */ + public function export(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) { + return $response; + } + + $fieldsRaw = $request->post('fields', $request->get('fields', [])); + $fields = is_array($fieldsRaw) ? $fieldsRaw : explode(',', strval($fieldsRaw)); + $limitRaw = strval($request->post('export_limit', $request->get('export_limit', '1000'))); + if (!is_numeric($limitRaw)) { + return $this->error(__('Parameter error')); + } + $limit = intval($limitRaw); + if ($limit < 1) { + return $this->error(__('Parameter error')); + } + + try { + [$where, $alias, $order] = $this->buildExportQueryParts(); + $lang = strval($request->header('think-lang', 'zh-cn')); + $exporter = new MallDailyPushExport(); + return $exporter->export($this->model, $where, $alias, $order, $fields, $limit, $lang); + } catch (Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * @return array{0: array, 1: array, 2: array} + */ + private function buildExportQueryParts(): array + { + [$where, $alias, , $order] = $this->queryBuilder(); + return [$where, $alias, $order]; + } + /** * 按历史 mall_daily_push 记录回补用户信息 */ diff --git a/web/src/lang/backend/en/mall/dailyPush.ts b/web/src/lang/backend/en/mall/dailyPush.ts index 297b4c5..c74ec2d 100644 --- a/web/src/lang/backend/en/mall/dailyPush.ts +++ b/web/src/lang/backend/en/mall/dailyPush.ts @@ -9,4 +9,18 @@ export default { lifetime_total_withdraw: 'Lifetime total withdraw', create_time: 'Created at', 'quick Search Fields': 'ID', + export_excel: 'Export Excel', + export_title: 'Export daily push data', + export_tip: 'Exports data using the current filters and sort order. The server writes in batches to avoid freezing on large datasets.', + export_fields: 'Export fields', + export_select_all: 'Select all', + export_clear_all: 'Clear all', + export_limit: 'Export limit', + export_all_matched: 'All matched', + export_matched_count: '{count} record(s) match the current filters', + export_actual_count: 'will export {count} record(s)', + export_large_warning: 'Large export may take a while. Maximum {max} records per export.', + export_confirm: 'Start export', + export_success: 'Successfully exported {count} record(s)', + export_failed: 'Export failed, please try again later', } diff --git a/web/src/lang/backend/zh-cn/mall/dailyPush.ts b/web/src/lang/backend/zh-cn/mall/dailyPush.ts index f5c6cfb..dd72ec0 100644 --- a/web/src/lang/backend/zh-cn/mall/dailyPush.ts +++ b/web/src/lang/backend/zh-cn/mall/dailyPush.ts @@ -9,5 +9,19 @@ export default { lifetime_total_withdraw: '历史总提现', create_time: '创建时间', 'quick Search Fields': 'ID', + export_excel: 'Excel导出', + export_title: '导出每日推送数据', + export_tip: '将按当前列表筛选条件与排序导出数据;采用服务端分批写入,避免一次性加载导致卡顿。', + export_fields: '导出字段', + export_select_all: '全选', + export_clear_all: '清空', + export_limit: '导出条数', + export_all_matched: '全部匹配', + export_matched_count: '当前筛选条件下共 {count} 条', + export_actual_count: '实际将导出 {count} 条', + export_large_warning: '导出条数较多,可能需要等待较长时间;单次最多导出 {max} 条。', + export_confirm: '开始导出', + export_success: '已成功导出 {count} 条数据', + export_failed: '导出失败,请稍后重试', } diff --git a/web/src/views/backend/mall/dailyPush/index.vue b/web/src/views/backend/mall/dailyPush/index.vue index 1522b98..382ff6f 100644 --- a/web/src/views/backend/mall/dailyPush/index.vue +++ b/web/src/views/backend/mall/dailyPush/index.vue @@ -6,20 +6,31 @@ + > + +
+