This commit is contained in:
邓皓元 2019-01-09 10:42:33 +08:00
parent d56d4e4047
commit 767f575333
15 changed files with 206 additions and 87 deletions

View File

@ -26,6 +26,7 @@ abstract class AbstractExport implements WithEvents, WithTitle, ShouldAutoSize
\App\Domains\Virtual\Exports\CardExport::class => '客户列表',
\App\Domains\Stats\Exports\CompanyCountExport::class => '企业统计',
\App\Domains\Stats\Exports\OrderExport::class => '订单统计',
\App\Domains\Stats\Exports\OrderDetailExport::class => '订单明细',
];
public $sn;
@ -39,6 +40,8 @@ abstract class AbstractExport implements WithEvents, WithTitle, ShouldAutoSize
$this->sn = $this->sn();
$this->tag = $this->tag();
$this->filename = $this->filename();
set_time_limit(-1);
ini_set('memory_limit', '4096m');
}
/**
@ -157,7 +160,7 @@ abstract class AbstractExport implements WithEvents, WithTitle, ShouldAutoSize
*
* @return string
*/
private function sn(): string
protected function sn(): string
{
return date('YmdHis') .sprintf('%04d', explode('.', microtime(true))[1]) . sprintf('%02d', rand(0, 99));
}
@ -167,7 +170,7 @@ abstract class AbstractExport implements WithEvents, WithTitle, ShouldAutoSize
*
* @return string
*/
private function filename(): string
protected function filename(): string
{
$title = $this->tag();
@ -181,7 +184,7 @@ abstract class AbstractExport implements WithEvents, WithTitle, ShouldAutoSize
*
* @return void
*/
private function tag()
protected function tag()
{
if (!$tag = self::$classes[get_class($this)]) {
throw new NotAllowedException('类型不允许');

View File

@ -15,8 +15,6 @@ class ExportService extends Service
protected static $status = ['数据准备中', '开始写入', '写入结束', '保存成功', '任务失败'];
protected static $maxRow = 30000;
/**
* 构造函数
*
@ -52,11 +50,7 @@ class ExportService extends Service
$url = $item->status === 3 ? Storage::disk($item->disk)->url($item->filename) : '';
$conditions = '';
foreach (array_except($item->conditions, ['page', 'limit', 'orderBy', 'sortedBy']) as $key => $value) {
$conditions .= "$key: $value\n";
}
$conditions = json_encode(array_except($item->conditions, ['page', 'limit', 'orderBy', 'sortedBy']), 256);
return [
'id' => $item->id,
@ -92,9 +86,9 @@ class ExportService extends Service
/**
* 导出
*/
public static function store($export, $disk, $total = 0)
public static function store($export, $disk, $queue = false)
{
if ($total < self::$maxRow) {
if (!$queue) {
Excel::store($export, $export->filename, $disk);
$url = Storage::disk($disk)->url($export->filename);
return $url;

View File

@ -6,10 +6,9 @@ use App\Core\AbstractExport;
use Dipper\Excel\Concerns\Exportable;
use Dipper\Excel\Concerns\WithHeadings;
use Dipper\Excel\Concerns\FromCollection;
use Dipper\Excel\Concerns\WithHeadingRow;
use App\Domains\Stats\Services\CompanyCountService;
class CompanyCountExport extends AbstractExport implements FromCollection, WithHeadings, WithHeadingRow
class CompanyCountExport extends AbstractExport implements FromCollection, WithHeadings
{
public $conditions;
@ -21,8 +20,6 @@ class CompanyCountExport extends AbstractExport implements FromCollection, WithH
public function collection()
{
set_time_limit(-1);
$companies = app(CompanyCountService::class)->index($this->conditions)->toArray();
$companies = collect($companies);

View File

@ -0,0 +1,109 @@
<?php
namespace App\Domains\Stats\Exports;
use App\Core\AbstractExport;
use Illuminate\Support\Collection;
use Dipper\Excel\Concerns\WithRows;
use Dipper\Excel\Concerns\FromQuery;
use Dipper\Excel\Concerns\Exportable;
use App\Exceptions\NotAllowedException;
use Dipper\Excel\Concerns\WithHeadings;
use Illuminate\Database\Eloquent\Builder;
use App\Domains\Stats\Services\OrderService;
use Dipper\Excel\Concerns\WithColumnFormatting;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
class OrderDetailExport extends AbstractExport implements FromQuery, WithHeadings, WithRows, WithColumnFormatting
{
public $conditions;
public static $types = ['销售', '续费', '续费包', '加油包'];
public function __construct(array $conditions = [])
{
$this->conditions = $conditions;
parent::__construct();
}
/**
* @return Builder
*/
public function query()
{
if (!$class = OrderService::$classes[$this->conditions['type']]) {
throw new NotAllowedException('统计类型不存在');
}
$repository = app($class);
$builder = $repository->withConditions($this->conditions)->applyConditions()->getModel();
return $builder;
}
public function headings(): array
{
return [
'SIM',
'企业名称',
'套餐名称',
'套餐周期',
'支付方式',
'价格',
'订单时间',
];
}
/**
* @param mixed $row
*
* @return mixed
*/
public function rows($rows)
{
$rows = OrderService::detailTransformer($rows);
$rows->transform(function ($item) {
return [
$item['sim'],
$item['company_name'],
$item['package_name'],
$item['service_months'],
$item['pay_channel_name'],
$item['unit_price'],
$item['order_at'],
];
});
return $rows;
}
/**
* @return array
*/
public function columnFormats(): array
{
return [
'A' => NumberFormat::FORMAT_NUMBER,
'F' => NumberFormat::FORMAT_NUMBER_00,
];
}
/**
* 类型
*
* @return void
*/
protected function tag()
{
if ((!$tag = self::$classes[get_class($this)]) || !self::$types[$this->conditions['type']]) {
throw new NotAllowedException('类型不允许');
}
$tag = self::$types[$this->conditions['type']] . $tag;
return $tag;
}
}

View File

@ -4,12 +4,12 @@ namespace App\Domains\Stats\Exports;
use App\Core\AbstractExport;
use Dipper\Excel\Concerns\Exportable;
use App\Exceptions\NotAllowedException;
use Dipper\Excel\Concerns\WithHeadings;
use Dipper\Excel\Concerns\FromCollection;
use Dipper\Excel\Concerns\WithHeadingRow;
use App\Domains\Stats\Services\OrderService;
class OrderExport extends AbstractExport implements FromCollection, WithHeadings, WithHeadingRow
class OrderExport extends AbstractExport implements FromCollection, WithHeadings
{
public $conditions;
@ -23,9 +23,6 @@ class OrderExport extends AbstractExport implements FromCollection, WithHeadings
public function collection()
{
set_time_limit(-1);
$orders = app(OrderService::class)->index($this->conditions)->map(function ($item) {
return collect([
'company_name' => $item->company_name,
@ -62,32 +59,18 @@ class OrderExport extends AbstractExport implements FromCollection, WithHeadings
}
/**
* 表格标题
* 类型
*
* @return string
* @return void
*/
public function title(): string
protected function tag()
{
$title = parent::title();
$title = self::$types[$this->conditions['type']] . $title;
return $title;
if ((!$tag = self::$classes[get_class($this)]) || !self::$types[$this->conditions['type']]) {
throw new NotAllowedException('类型不允许');
}
/**
* 文件名称
*
* @return string
*/
private function filename(): string
{
$title = self::$classes[get_class($this)];
$tag = self::$types[$this->conditions['type']] . $tag;
$filename = $title . date('YmdHis');
$filename = self::$types[$this->conditions['type']] . $filename;
return "export/{$filename}.xlsx";
return $tag;
}
}

View File

@ -44,7 +44,7 @@ class CompanyCountController extends Controller
*/
public function export()
{
$conditions = $this->request->all();
$conditions = $this->request->except(['page', 'limit']);
$conditions['limit'] = 0;
try {

View File

@ -2,9 +2,11 @@
namespace App\Domains\Stats\Http\Controllers;
use Illuminate\Http\Request;
use App\Exceptions\NotAllowedException;
use App\Domains\Stats\Exports\OrderExport;
use App\Domains\Stats\Services\OrderService;
use App\Domains\Export\Services\ExportService;
use App\Domains\Stats\Exports\OrderDetailExport;
class OrderController extends Controller
{
@ -41,7 +43,7 @@ class OrderController extends Controller
*/
public function export()
{
$conditions = $this->request->all();
$conditions = $this->request->except(['page', 'limit']);
$conditions['limit'] = 0;
try {
@ -76,12 +78,23 @@ class OrderController extends Controller
*/
public function detailExport()
{
$conditions = $this->request->all();
$conditions['limit'] = 0;
$conditions = $this->request->except(['page', 'limit']);
$conditions['order_id'] = $this->request->ids('order_id');
if (!$class = OrderService::$classes[$conditions['type']]) {
throw new NotAllowedException('统计类型不存在');
}
$repository = app($class);
$total = $repository->withConditions($conditions)->applyConditions()->getCountForPagination();
try {
$export = new OrderExport($conditions);
$url = ExportService::store($export, $this->disk);
$export = new OrderDetailExport($conditions);
$queue = $total > 6000;
$url = ExportService::store($export, $this->disk, $queue);
} catch (\Exception $e) {
throw $e;
}

View File

@ -16,7 +16,7 @@ class OrderService extends Service
protected $packageRepository;
protected $orderRepository;
protected static $classes = [
public static $classes = [
\App\Domains\Virtual\Repositories\OrderCardRepository::class,
\App\Domains\Virtual\Repositories\OrderRenewalCardRepository::class,
\App\Domains\Virtual\Repositories\OrderRenewalPackageCardRepository::class,
@ -89,23 +89,36 @@ class OrderService extends Service
$repository = app($class);
$companies = $this->companyRepository->withTrashed()->get()->pluck('name', 'id')->toArray();
$packages = $this->packageRepository->withTrashed()->get()->keyBy('id')->toArray();
$cards = $repository->withConditions($conditions)->applyConditions()->paginate($conditions['limit']);
$carrierOperators = app(Dicts::class)->get('carrier_operator');
return self::detailTransformer($cards);
}
$cards = $repository->with('order:id,unit_price,pay_channel,order_at')->withConditions($conditions)->applyConditions()->paginate($conditions['limit']);
/**
* 格式转化
*
* @param mixed $cards
* @return mixed
*/
public static function detailTransformer($cards)
{
$companies = app(CompanyRepository::class)->withTrashed()->get()->pluck('name', 'id')->toArray();
$packages = app(PackageRepository::class)->withTrashed()->get()->keyBy('id')->toArray();
$orders = app(OrderRepository::class)->withTrashed()
->select(['id', 'unit_price', 'pay_channel', 'order_at'])
->withConditions(['id' => array_unique($cards->pluck('order_id')->toArray())])->get()->keyBy('id')->toArray();
$cards->map(function ($item) use ($companies, $packages, $carrierOperators) {
$cards->map(function ($item) use ($companies, $packages, $carrierOperators, $orders) {
$package = $packages[$item->package_id];
$order = $orders[$item->order_id];
$item->company_name = $companies[$item->company_id];
$item->package_name = $package['name'];
$item->carrier_operator_name = $carrierOperators[$package['carrier_operator']];
$item->service_months = $package['service_months'];
$item->unit_price = $item->order['unit_price'];
$item->pay_channel_name = CommonService::namePayChannel($item->order['pay_channel']);
$item->order_at = $item->order['order_at'];
$item->unit_price = sprintf('%.02f', $order['unit_price']/100);
$item->pay_channel_name = CommonService::namePayChannel($order['pay_channel']);
$item->order_at = $order['order_at'];
});
return $cards;

View File

@ -24,8 +24,6 @@ class CardExport extends AbstractExport implements FromQuery, WithHeadings, With
public function query()
{
set_time_limit(-1);
return app(OrderCardRepository::class)->withConditions($this->conditions)->applyConditions();
}

View File

@ -48,8 +48,7 @@ class CardController extends Controller
*/
public function export()
{
$conditions = $this->request->all();
$conditions['limit'] = 0;
$conditions = $this->request->except(['page', 'limit']);
if ($conditions['id']) {
$conditions['id'] = intval(str_replace('No', '', $conditions['id']));
@ -59,7 +58,8 @@ class CardController extends Controller
try {
$export = new CardExport($conditions);
$url = ExportService::store($export, $disk = 'public', $total);
$queue = $total > 30000;
$url = ExportService::store($export, $disk = 'public', $queue);
} catch (\Exception $e) {
throw $e;
}

View File

@ -6,7 +6,7 @@ let domain = window.CONFIG.url;
// 创建axios实例
export const service = axios.create({
timeout: 10000,
timeout: 1800000,
headers: {
post: {
'Content-Type': 'application/x-www-form-urlencoded'
@ -16,7 +16,7 @@ export const service = axios.create({
});
export const serviceForm = axios.create({
timeout: 10000,
timeout: 1800000,
headers: {
post: {
'Content-Type': 'multipart/form-data'

View File

@ -36,7 +36,7 @@ export default {
{
title: '查询条件',
key: '',
width: 300,
width: 500,
render: (h, { row, column, index }) => {
return h('pre', row.conditions);
}

View File

@ -95,11 +95,17 @@ export default {
exportExcel() {
this.isShowLoading(true);
let params = this.options;
params.page = page;
service.get('api/stats/order/detail/export', { params }).then((res) => {
if (res.code === 0) {
if (res.data) {
this.downloadFile(res.data);
} else {
this.$Modal.success({
title: '提示',
content: '当前导出数据量大,已进入后台队列导出模式,请稍后至导出列表查看下载。'
});
}
}
this.isShowLoading(false);

View File

@ -93,7 +93,9 @@ export default {
sortedBy: 'asc'
};
service.get('api/stats/order/detail', { params }).then(res => {
service.get('api/stats/order/detail', {
params
}).then(res => {
this.isShowLoading(false);
if (res.code == 0) {
this.detailObj = {
@ -132,6 +134,7 @@ export default {
* @return {[type]} [description]
*/
index() {
this.isShowLoading(true);
this.type = Number(this.$route.params.type);
this.data = [];
@ -146,8 +149,6 @@ export default {
limit: 0
}, options);
this.isShowLoading(true);
service.get('api/stats/order', {
params
}).then(res => {
@ -223,16 +224,18 @@ export default {
exportExcel() {
this.isShowLoading(true);
this.type = Number(this.$route.params.type);
let options = Object.assign({
orderBy: 'company_id',
sortedBy: 'asc'
sortedBy: 'asc',
type: this.type
},
this.options);
let params = this.searchDataHandle({}, {}, options);
this.isShowLoading(true);
let params = this.searchDataHandle({}, {
limit: 0
}, options);
service.get('api/stats/order/export', {
params

View File

@ -91,7 +91,7 @@ abstract class Repository implements RepositoryInterface, CacheableInterface, Cr
*/
public function getModel()
{
return $this->makeModel();
return $this->model;
}
/**
@ -279,9 +279,9 @@ abstract class Repository implements RepositoryInterface, CacheableInterface, Cr
}
if ($this->model instanceof EloquentBuilder) {
$field = $this->getModel()->getQualifiedKeyName();
$field = $this->makeModel()->getQualifiedKeyName();
} elseif ($this->model instanceof Model) {
$field = $this->getModel()->getQualifiedKeyName();
$field = $this->makeModel()->getQualifiedKeyName();
} else {
$field = 'id';
}
@ -511,7 +511,7 @@ abstract class Repository implements RepositoryInterface, CacheableInterface, Cr
}
$this->resetModel();
event(new RepositoryModelUpdated($this, $this->getModel()));
event(new RepositoryModelUpdated($this, $this->makeModel()));
return $model;
}
@ -527,7 +527,7 @@ abstract class Repository implements RepositoryInterface, CacheableInterface, Cr
$this->resetModel();
event(new RepositoryModelUpdated($this, $this->getModel()));
event(new RepositoryModelUpdated($this, $this->makeModel()));
return $this->model;
}
@ -545,7 +545,7 @@ abstract class Repository implements RepositoryInterface, CacheableInterface, Cr
$deleted = $this->model->delete();
event(new RepositoryModelDeleted($this, $this->getModel()));
event(new RepositoryModelDeleted($this, $this->makeModel()));
$this->resetModel();
@ -565,11 +565,11 @@ abstract class Repository implements RepositoryInterface, CacheableInterface, Cr
if ($this->model instanceof Model) {
$deleted = $this->model->destroy($ids);
} else {
$this->model->whereIn($this->getModel()->getKeyName(), $ids)->delete();
$this->model->whereIn($this->makeModel()->getKeyName(), $ids)->delete();
}
event(new RepositoryModelDeleted($this, $this->getModel()));
event(new RepositoryModelDeleted($this, $this->makeModel()));
$this->resetModel();
@ -585,7 +585,7 @@ abstract class Repository implements RepositoryInterface, CacheableInterface, Cr
{
$deleted = $this->model->restore();
event(new RepositoryModelRestore($this, $this->getModel()));
event(new RepositoryModelRestore($this, $this->makeModel()));
$this->resetModel();
@ -628,7 +628,7 @@ abstract class Repository implements RepositoryInterface, CacheableInterface, Cr
{
if ($this->model instanceof EloquentBuilder) {
if (empty($this->model->getQuery()->orders) && empty($this->model->getQuery()->unionOrders)) {
$this->orderBy($this->getModel()->getQualifiedKeyName(), 'asc');
$this->orderBy($this->makeModel()->getQualifiedKeyName(), 'asc');
}
}
}
@ -643,7 +643,7 @@ abstract class Repository implements RepositoryInterface, CacheableInterface, Cr
if ($this->model instanceof Model) {
$results = $this->model->newCollection();
} elseif ($this->model instanceof EloquentBuilder) {
$results = $this->getModel()->newCollection();
$results = $this->makeModel()->newCollection();
} else {
$results = collect();
}