流量池

This commit is contained in:
邓皓元 2019-02-26 16:31:09 +08:00
parent 3c362d54ed
commit 0ea764aeaf
15 changed files with 269 additions and 95 deletions

View File

@ -25,6 +25,7 @@ abstract class AbstractExport implements WithEvents, WithTitle, ShouldAutoSize
public static $classes = [
\App\Domains\Virtual\Exports\CardExport::class => '客户列表',
\App\Domains\Virtual\Exports\FlowPoolExport::class => '流量池列表',
\App\Domains\Virtual\Exports\FlowPoolExportDetailExport::class => '流量池明细',
\App\Domains\Stats\Exports\CompanyCountExport::class => '企业统计',
\App\Domains\Stats\Exports\OrderExport::class => '订单统计',
\App\Domains\Stats\Exports\OrderDetailExport::class => '订单明细',

View File

@ -0,0 +1,97 @@
<?php
namespace App\Domains\Virtual\Exports;
use Carbon\Carbon;
use App\Core\AbstractExport;
use Dipper\Excel\Concerns\WithRows;
use Dipper\Excel\Concerns\FromQuery;
use App\Exceptions\NotExistException;
use App\Models\Virtual\FlowPoolMonth;
use Illuminate\Support\Facades\Schema;
use Dipper\Excel\Concerns\WithHeadings;
use Dipper\Excel\Concerns\WithColumnFormatting;
use App\Domains\Virtual\Services\PackageService;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use App\Domains\Virtual\Services\FlowPoolService;
use App\Domains\Virtual\Repositories\FlowPoolRepository;
class FlowPoolExportDetailExport extends AbstractExport implements FromQuery, WithHeadings, WithRows, WithColumnFormatting
{
public $conditions;
public function __construct(array $conditions = [])
{
$this->conditions = $conditions;
parent::__construct();
}
/**
* @return Builder
*/
public function query()
{
$pool_id = $this->conditions['pool_id'];
$month = Carbon::parse($this->conditions['month']);
$table = app(FlowPoolMonth::class)->getTable() . '_' . $month->format('Ym');
return app(FlowPoolMonth::class)->setTable($table)->where('pool_id', $pool_id)->select(['product_id', 'sim', 'kilobyte']);
}
public function headings(): array
{
$headings = [
'SIM',
'套餐名称',
'保底流量',
'已用流量',
];
return $headings;
}
/**
* @param mixed $row
*
* @return mixed
*/
public function rows($rows)
{
$pool_id = $this->conditions['pool_id'];
$month = Carbon::parse($this->conditions['month']);
if (!$flowPool = app(FlowPoolRepository::class)->find($pool_id)) {
throw new NotExistException('流量池不存在或已删除');
}
$flowPool = FlowPoolService::transformer(collect([$flowPool]), $month)->first();
$minimum_settings = $flowPool['settings'][0]['minimum_settings'] ?? [];
$minimum_flows = array_pluck($minimum_settings, 'flows', 'product_id');
$array = [];
foreach ($rows as $item) {
$array[] = [
$item['sim'],
PackageService::load($item['product_id'])['name'],
FlowPoolService::humanFlows($minimum_flows[$item['product_id']] ?? 0),
FlowPoolService::humanFlows($item['kilobyte']),
];
}
return $array;
}
/**
* @return array
*/
public function columnFormats(): array
{
return [
'A' => NumberFormat::FORMAT_NUMBER,
];
}
}

View File

@ -1,12 +1,16 @@
<?php
namespace App\Domains\Virtual\Http\Controllers;
use Carbon\Carbon;
use App\Core\Controller;
use Illuminate\Http\Request;
use Dipper\Excel\Facades\Excel;
use Illuminate\Support\Facades\DB;
use App\Models\Virtual\FlowPoolData;
use App\Exceptions\NotExistException;
use App\Models\Virtual\FlowPoolMonth;
use Illuminate\Support\Facades\Schema;
use App\Exceptions\NotAllowedException;
use Illuminate\Support\Facades\Validator;
use App\Models\Virtual\OrderCardPartition;
use App\Exceptions\InvalidArgumentException;
@ -16,6 +20,8 @@ use App\Domains\Virtual\Imports\FlowCardImport;
use App\Domains\Virtual\Services\ProductService;
use App\Domains\Virtual\Services\FlowPoolService;
use App\Domains\Virtual\Repositories\FlowPoolRepository;
use App\Domains\Virtual\Exports\FlowPoolExportDetailExport;
use App\Domains\Virtual\Repositories\OrderCardPartitionRepository;
class FlowPoolController extends Controller
@ -75,11 +81,43 @@ class FlowPoolController extends Controller
*/
public function show()
{
$page = $this->request->get('page');
$conditions = $this->request->all();
$res = $this->flowPoolService->show($conditions);
return res($res, '流量池详情', 201);
}
/**
* 明细导出.
*
* @return \Illuminate\Http\Response
*/
public function detailExport()
{
$conditions = $this->request->only(['pool_id', 'month']);
$pool_id = $conditions['pool_id'];
$month = Carbon::parse($conditions['month']);
$table = app(FlowPoolMonth::class)->getTable() . '_' . $month->format('Ym');
if (!Schema::hasTable($table)) {
throw new NotAllowedException('无该月数据');
}
$total = app(FlowPoolMonth::class)->setTable($table)->where('pool_id', $pool_id)->count();
try {
$export = new FlowPoolExportDetailExport($conditions);
$queue = $total > 30000;
$url = ExportService::store($export, $disk = 'public', $queue);
} catch (\Exception $e) {
throw $e;
}
return res($url, '导出成功', 201);
}
/**
* 创建.
@ -240,7 +278,7 @@ class FlowPoolController extends Controller
try {
$export = new FlowPoolExport($conditions);
$url = ExportService::store($export, $disk = 'public');
$url = ExportService::store($export, $disk = 'public');
} catch (\Exception $e) {
throw $e;
}

View File

@ -59,6 +59,7 @@ $router->group(['prefix' => 'virtual', 'as' => 'virtual', 'middleware' => ['admi
$router->get('/flow-pools/index', ['as' => 'flow-pools.index', 'uses' => 'FlowPoolController@index']);
$router->get('/flow-pools/export', ['as' => 'flow-pools.export', 'uses' => 'FlowPoolController@export']);
$router->get('/flow-pools/show', ['as' => 'flow-pools.show', 'uses' => 'FlowPoolController@show']);
$router->get('/flow-pools/detail/export', ['as' => 'flow-pools.detailExport', 'uses' => 'FlowPoolController@detailExport']);
$router->post('/flow-pools/create', ['as' => 'flow-pools.create', 'uses' => 'FlowPoolController@create']);
$router->post('/flow-pools/update/{id}', ['as' => 'flow-pools.update', 'uses' => 'FlowPoolController@update']);
$router->post('/flow-pools/destroy', ['as' => 'flow-pools.destroy', 'uses' => 'FlowPoolController@destroy']);

View File

@ -575,6 +575,7 @@ class FlowPoolService extends Service
public function show(array $conditions = [])
{
$limit = $conditions['limit'] ?? 20;
$page = $conditions['page'] ?? 1;
$pool_id = $conditions['pool_id'];
$month = Carbon::parse($conditions['month']);
@ -593,14 +594,15 @@ class FlowPoolService extends Service
$query = app(FlowPoolMonth::class)->setTable($table)->where('pool_id', $pool_id);
if (Schema::hasTable($table) && $total = $query->count()) {
$cards = $query->forPage($page, $limit)->get();
$cards = $query->select(['product_id', 'sim', 'kilobyte'])->forPage($page, $limit)->get();
} else {
$cards = collect();
}
$cards->map(function ($item) use ($minimum_flows) {
$item->package_name = PackageService::load($item->product_id)['name'];
$item->minimum_flows = $minimum_flows[$item->product_id] ?? 0;
$item->product_name = PackageService::load($item->product_id)['name'];
$item->kilobyte = $this->humanFlows($item->kilobyte);
$item->minimum_flows = $this->humanFlows($minimum_flows[$item->product_id] ?? 0);
});
$cards = new LengthAwarePaginator($cards, $total, $limit);
@ -639,8 +641,9 @@ class FlowPoolService extends Service
foreach ($item->product_ids as $value) {
$products[] = [
'product_id' => $value,
'product_name' => ProductService::load($value)['name'],
'product_id' => $value,
'type' => ProductService::load($value)['type'],
'product_name' => ProductService::load($value)['name'],
];
}
@ -727,6 +730,4 @@ class FlowPoolService extends Service
{
return human_filesize($int, 2, ['unit' => 'KB', 'min' => 'MB', 'max' => 'PB']);
}
}

View File

@ -140,7 +140,7 @@ class ProductService extends Service
public static function load($id)
{
if (!self::$products) {
self::$products = app(ProductRepository::class)->select(['id', 'name', 'company_id', 'package_id', 'price', 'status'])
self::$products = app(ProductRepository::class)->select(['id', 'type', 'name', 'company_id', 'package_id', 'price', 'status'])
->withTrashed()->get()->keyBy('id');
}

View File

@ -1,6 +0,0 @@
<?php
$a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var_dump(array_slice($a, 0, 2));
var_dump(array_slice($a, 2, 3));

View File

@ -51,6 +51,17 @@ export function show(params) {
return service.get('api/virtual/flow-pools/show', params);
}
/**
* [exportDetail 流量池详情导出]
* @param {[type]} data [description]
* @return {[type]} [description]
*/
export function exportDetail(data) {
return service.get('api/virtual/flow-pools/detail/export', {
params: data
});
}
/**
* [create 创建流量池]
* @param {[type]} data [description]

View File

@ -8,10 +8,10 @@
>
<ui-loading :show="page_loading.show"></ui-loading>
<Card class="page-detail-wrap" v-if="flowPool">
<div class="page-edit-wrap" v-if="flowPool">
<Row>
<Col span="8">
<Divider>基础信息</Divider>
<Divider>基础信息</Divider>
<Col span="12">
<ul>
<li class="ui-list">
<div class="ui-list-title">统计年月:</div>
@ -32,13 +32,27 @@
<div class="ui-list-title">共享类型:</div>
<div class="ui-list-content">{{flowPool.shared_name}}</div>
</li>
</ul>
</Col>
<Col span="12">
<ul>
<li class="ui-list">
<div class="ui-list-title">套餐包含:</div>
<div class="ui-list-content">
<Tag
color="blue"
v-for="(item,index) in flowPool.products"
v-for="(item,index) in products"
:key="index"
>{{item.product_name}}</Tag>
</div>
</li>
<li class="ui-list">
<div class="ui-list-title">续费包包含:</div>
<div class="ui-list-content">
<Tag
color="blue"
v-for="(item,index) in renewPackageProducts"
:key="index"
>{{item.product_name}}</Tag>
</div>
@ -59,35 +73,36 @@
</li>
</ul>
</Col>
<Col offset="1" span="15">
<Divider>计费规则</Divider>
<div v-if="flowPool.settings[0]">
<li class="ui-list">
<div class="ui-list-title">超出流量:</div>
<div class="ui-list-content">
<Table size='small' :columns="settingsColumns" :data="flowPool.settings"></Table>
</div>
</li>
<li class="ui-list">
<div class="ui-list-title">保底流量:</div>
<div class="ui-list-content">
<Table size='small'
:columns="minimumSettingsColumns"
:data="flowPool.settings[0].minimum_settings"
></Table>
</div>
</li>
</div>
<div v-if="!flowPool.settings[0]">
<Alert type="error">计费规则未配置</Alert>
</div>
</Col>
</Row>
<Row></Row>
</Card>
</div>
<Row>
<ul>
<li class="f-r">
<div class="handle-item">
<Button @click="exportExcel" icon="md-download">导出</Button>
</div>
</li>
</ul>
</Row>
<div class="page-list-wrap">
<Table :columns="cardsColumns" :data="cards ? cards.data : []"></Table>
</div>
<div class="page-turn-wrap" v-if="cards">
<Page
:current="Number(cards.current_page)"
:page-size="Number(cards.per_page)"
:total="Number(cards.total)"
@on-change="index"
:page-size-opts="[5, 10, 50, 100]"
@on-page-size-change="changeLimit"
show-elevator
show-total
show-sizer
></Page>
</div>
</Drawer>
</template>

View File

@ -12,7 +12,7 @@ export default {
},
data: {
type: Object,
default () {
default() {
return null;
}
}
@ -28,53 +28,28 @@ export default {
},
data() {
return {
limit: 5,
my_show: false,
flowPool: null,
cards: null,
settingsColumns: [{
title: '首月单价',
key: 'first_month_price'
},
{
title: '次月单价',
key: 'other_month_price'
},
{
title: '梯度',
key: 'gradient'
},
{
title: '梯度单位',
key: '',
render: (h, {
row
}) => {
return h('span', {}, row.gradient_unit ? 'M' : 'G');
}
}
],
minimumSettingsColumns: [{
title: '套餐名称',
key: 'product_name'
},
{
title: '月保底流量',
key: '',
render: (h, {
row
}) => {
return h('span', {}, row.flows + ' M/月');
}
},
{
title: '月保底价格',
key: '',
render: (h, {
row
}) => {
return h('span', {}, row.price + ' 元');
}
}
products: [],
renewPackageProducts: [],
cardsColumns: [{
title: 'SIM',
key: 'sim'
},
{
title: '套餐名称',
key: 'product_name'
},
{
title: '保底流量',
key: 'minimum_flows'
},
{
title: '已用流量',
key: 'kilobyte'
}
]
};
},
@ -89,7 +64,8 @@ export default {
let params = {
'pool_id': this.data.id,
'month': this.month,
'page': page
'page': page,
'limit': this.limit
};
API.show({
@ -99,6 +75,12 @@ export default {
if (res.code == 0) {
this.flowPool = res.data.flowPool;
this.cards = res.data.cards;
this.products = this.flowPool.products.filter(item => {
return item.type === 0;
});
this.renewPackageProducts = this.flowPool.products.filter(item => {
return item.type === 2;
});
this.flowPool.settings.map(setting => {
setting.first_month_price = Number(setting.first_month_price);
@ -116,6 +98,34 @@ export default {
},
visibleChange(bool) {
this.$emit('update:show', bool);
},
changeLimit(limit) {
this.limit = limit;
this.index(1);
},
exportExcel() {
let params = {
'pool_id': this.data.id,
'month': this.month
};
this.isShowLoading(true);
API.exportDetail(params).then(res => {
if (res.code === 0) {
if (res.data) {
this.downloadFile(res.data);
} else {
this.$Modal.success({
title: '提示',
content: '当前导出数据量大,已进入后台队列导出模式,请稍后至导出列表查看下载。'
});
}
}
this.isShowLoading(false);
}).catch(() => {
this.isShowLoading(false);
});
}
}
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=\favicon.ico><script src=\config.js></script><title></title><link href=/css/chunk-caf89654.f97d0276.css rel=prefetch><link href=/js/chunk-00ae0766.9e6b7bf3.js rel=prefetch><link href=/js/chunk-caf89654.eb5414d4.js rel=prefetch><link href=/css/app.8e0e058f.css rel=preload as=style><link href=/css/chunk-vendors.3c3b2e85.css rel=preload as=style><link href=/js/app.fa7f1e81.js rel=preload as=script><link href=/js/chunk-vendors.02a4e5bc.js rel=preload as=script><link href=/css/chunk-vendors.3c3b2e85.css rel=stylesheet><link href=/css/app.8e0e058f.css rel=stylesheet></head><body><noscript><strong>很抱歉如果没有启用JavaScript程序不能正常工作若要继续使用请启用它。</strong></noscript><div id=app></div><script src=/js/chunk-vendors.02a4e5bc.js></script><script src=/js/app.fa7f1e81.js></script></body></html>
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=\favicon.ico><script src=\config.js></script><title></title><link href=/css/chunk-caf89654.f97d0276.css rel=prefetch><link href=/js/chunk-00ae0766.9e6b7bf3.js rel=prefetch><link href=/js/chunk-caf89654.a53630b1.js rel=prefetch><link href=/css/app.8e0e058f.css rel=preload as=style><link href=/css/chunk-vendors.3c3b2e85.css rel=preload as=style><link href=/js/app.2a86d87f.js rel=preload as=script><link href=/js/chunk-vendors.02a4e5bc.js rel=preload as=script><link href=/css/chunk-vendors.3c3b2e85.css rel=stylesheet><link href=/css/app.8e0e058f.css rel=stylesheet></head><body><noscript><strong>很抱歉如果没有启用JavaScript程序不能正常工作若要继续使用请启用它。</strong></noscript><div id=app></div><script src=/js/chunk-vendors.02a4e5bc.js></script><script src=/js/app.2a86d87f.js></script></body></html>