增加每日推送的导出和排序

This commit is contained in:
2026-07-21 15:46:01 +08:00
parent a0056ff15b
commit 5aad851108
4 changed files with 119 additions and 6 deletions

View File

@@ -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());
}
}
/**
* 导出 ExcelCSV 流式写入,兼容 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 记录回补用户信息
*/

View File

@@ -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',
}

View File

@@ -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: '导出失败,请稍后重试',
}

View File

@@ -6,20 +6,31 @@
<TableHeader
:buttons="['refresh', 'comSearch', 'quickSearch', 'columnDisplay']"
:quick-search-placeholder="t('Quick search placeholder', { fields: t('mall.dailyPush.quick Search Fields') })"
></TableHeader>
>
<template #refreshAppend>
<el-tooltip v-if="baTable.auth('export')" :content="t('mall.dailyPush.export_excel')" placement="top">
<el-button v-blur class="table-header-operate btns-ml-12" type="success" @click="exportVisible = true">
<Icon name="fa fa-file-excel-o" />
<span class="table-header-operate-text">{{ t('mall.dailyPush.export_excel') }}</span>
</el-button>
</el-tooltip>
</template>
</TableHeader>
<Table ref="tableRef"></Table>
<ExportDialog v-model="exportVisible" />
</div>
</template>
<script setup lang="ts">
import { onMounted, provide, useTemplateRef } from 'vue'
import { onMounted, provide, ref, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { baTableApi } from '/@/api/common'
import MallPageIntro from '/@/components/mall/MallPageIntro.vue'
import TableHeader from '/@/components/table/header/index.vue'
import Table from '/@/components/table/index.vue'
import baTableClass from '/@/utils/baTable'
import ExportDialog from './exportDialog.vue'
defineOptions({
name: 'mall/dailyPush',
@@ -27,6 +38,7 @@ defineOptions({
const { t } = useI18n()
const tableRef = useTemplateRef('tableRef')
const exportVisible = ref(false)
const baTable = new baTableClass(
new baTableApi('/admin/mall.DailyPush/'),
@@ -67,21 +79,21 @@ const baTable = new baTableClass(
prop: 'yesterday_win_loss_net',
align: 'center',
operator: 'RANGE',
sortable: false,
sortable: 'custom',
},
{
label: t('mall.dailyPush.yesterday_total_deposit'),
prop: 'yesterday_total_deposit',
align: 'center',
operator: 'RANGE',
sortable: false,
sortable: 'custom',
},
{
label: t('mall.dailyPush.lifetime_total_deposit'),
prop: 'lifetime_total_deposit',
align: 'center',
operator: 'RANGE',
sortable: false,
sortable: 'custom',
},
{
label: t('mall.dailyPush.lifetime_total_withdraw'),
@@ -89,7 +101,7 @@ const baTable = new baTableClass(
align: 'center',
minWidth: 95,
operator: 'RANGE',
sortable: false,
sortable: 'custom',
},
{
label: t('mall.dailyPush.create_time'),