续费率统计

This commit is contained in:
邓皓元 2020-03-06 16:00:28 +08:00
parent 068bbac28e
commit 86c6765edc
9 changed files with 372 additions and 1 deletions

View File

@ -0,0 +1,38 @@
<?php
namespace App\Domains\Stats\Http\Controllers;
use Illuminate\Http\Request;
use App\Domains\Stats\Services\RenewalService;
/**
* 续费率统计
*/
class RenewalController extends Controller
{
protected $request;
protected $renewalService;
/**
* 构造函数,自动注入.
*/
public function __construct(Request $request, RenewalService $renewalService)
{
$this->request = $request;
$this->renewalService = $renewalService;
}
/**
* 列表.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$conditions = $this->request->all();
$res = $this->renewalService->index($conditions);
return res($res, '续费率统计', 201);
}
}

View File

@ -20,4 +20,7 @@ $router->group(['prefix' => 'stats', 'as' => 'stats', 'middleware' => ['adminAut
// 销售激活统计
$router->get('/sold-activated', ['as' => 'sold-activated.index', 'uses' => 'SoldActivatedController@index']);
// 续费率统计
$router->get('/renewal', ['as' => 'renewal.index', 'uses' => 'RenewalController@index']);
});

View File

@ -0,0 +1,68 @@
<?php
namespace App\Domains\Stats\Services;
use App\Core\Service;
use Illuminate\Support\Facades\DB;
use App\Domains\Virtual\Services\CompanyService;
class RenewalService extends Service
{
/**
* 构造函数
*
* @return void
*/
public function __construct() { }
/**
* 统计
*
* @return void
*/
public function index(array $conditions = [])
{
$sql = 'SELECT c.company_id, count(*) AS activates, SUM(CASE WHEN p.id IS NOT NULL THEN 1 ELSE 0 END) AS renewals ' .
'FROM virtual_order_cards AS c ' .
'LEFT JOIN virtual_order_cards_partition AS p ON p.type IN (1, 2) AND p.sim = c.sim ';
$where = 'WHERE c.service_start_at IS NOT NULL ';
$group = 'GROUP BY c.company_id ';
if($conditions['company_id']){
$where .= 'AND c.company_id = ' . $conditions['company_id'] . ' ';
}
if($conditions['activate_start_time']){
$where .= 'AND c.service_start_at >= ' . $conditions['activate_start_time'] . ' ';
}
if($conditions['activate_end_time']){
$where .= 'AND c.service_end_at <= ' . $conditions['activate_end_time'] . ' ';
}
if($conditions['renewal_start_time']){
$where .= 'AND p.service_start_at >= ' . $conditions['renewal_start_time'] . ' ';
}
if($conditions['renewal_start_time']){
$where .= 'AND p.service_start_at >= ' . $conditions['renewal_start_time'] . ' ';
}
$sql = $sql . $where . $group;
$data = DB::select($sql);
if(!$data){
return [];
}
foreach ($data as $item) {
$item = (array)$item;
$item['company_name'] = CompanyService::load($item['company_id'])['name'];
$item['ratio'] = $item['activates'] == 0 ? 0 : $item['renewals']/$item['activates'];
$item['ratio'] = sprintf('%.02f', $item['ratio']);
}
return $data;
}
}

View File

@ -336,6 +336,12 @@ class PermissionSeeder extends Seeder
['name' => 'stats.sold-activated.show', 'title' => '明细', 'description' => 'show', 'type' => 1],
]
],
[
'name' => 'stats.renewal', 'title' => '续费率统计', 'path' => '/stats/renewal', 'icon' => 'md-bowtie', 'type' => 0, 'open' => 3,
'children' => [
['name' => 'stats.renewal.export', 'title' => '导出', 'description' => 'output', 'type' => 1],
]
],
[
'name' => 'stats.flow-pools', 'title' => '流量池统计', 'path' => '/flow-pools', 'icon' => 'md-swap', 'type' => 0, 'open' => 3,
'children' => [

View File

@ -3,7 +3,7 @@ var CONFIG = {
login_background: '/assets/login_background.jpg',
logo_big: '/assets/logo_big.png',
logo_small: '/assets/logo_small.png',
url: (window.location.hostname === 'localhost') ? 'http://vd.dipp.ink/' : '/'
url: (window.location.hostname === 'localhost') ? 'http://127.0.0.1:8000/' : '/'
};
window.CONFIG = CONFIG;

View File

@ -31,6 +31,7 @@ const routes = [
{ path: '/stats/order/:type', name: 'StatsOrder', component: load('stats/order/index'), meta: { title: '订单统计' } },
{ path: '/stats/company-report/:type', name: 'StatsCompanyReport', component: load('stats/company-report/index'), meta: { title: '月报表' } },
{ path: '/stats/sold-activated', name: 'SoldActivated', component: load('stats/sold-activated/index'), meta: { title: '销售激活统计' } },
{ path: '/stats/renewal', name: 'Renewal', component: load('stats/renewal/index'), meta: { title: '续费率统计' } },
{ path: '/artisan/real-sync', name: 'RealSync', component: load('artisan/real-sync/index'), meta: { title: 'RD数据同步' } },
{ path: '/flow-pools', name: 'FlowPools', component: load('virtual/flow_pools/index'), meta: { title: '流量池管理' } }
]

View File

@ -0,0 +1,105 @@
<template>
<div class="page-wrap">
<ui-loading :show="page_loading.show"></ui-loading>
<div class="page-handle-wrap">
<ul class="handle-wraper bd-b">
<li class="f-l">
<div class="text-exp">
<b>全部信息</b>
</div>
</li>
<li class="f-r">
<div class="handle-item">
<Button @click="search.show=!search.show" ghost icon="ios-search" type="primary">搜索</Button>
</div>
<div class="handle-item">
<Button @click="index(1)" icon="md-refresh">刷新</Button>
</div>
<div class="handle-item" v-if="hasPermission('output')">
<Button @click="exportExcel" icon="md-download">导出</Button>
</div>
</li>
</ul>
<div class="search-wrap" v-show="search.show">
<ul class="handle-wraper">
<li class="handle-item w-250">
<AutoComplete
@on-search="handleCompleteCompanies"
icon="ios-search"
placeholder="企业名称"
v-model.trim="options.name"
>
<Option
:key="item.id"
:value="item.name"
v-for="item in completeHandledCompanies"
>{{ item.name }}</Option>
</AutoComplete>
</li>
<li class="handle-item w-250">
<DatePicker
placeholder="激活时间"
placement="bottom-start"
type="daterange"
v-model.trim="options.activate_time"
:options="datePickerOptionsMonth"
></DatePicker>
</li>
<li class="handle-item w-250">
<DatePicker
placeholder="续费时间"
placement="bottom-start"
type="daterange"
v-model.trim="options.renewal_time"
:options="datePickerOptionsMonth"
></DatePicker>
</li>
</ul>
<ul class="handle-wraper">
<li class="f-r">
<div class="handle-item">
<Button @click="index(1)" ghost type="primary">立即搜索</Button>
</div>
<div class="handle-item">
<Button @click="resetSearch" ghost type="warning">重置搜索</Button>
</div>
</li>
</ul>
</div>
</div>
<div class="page-list-wrap">
<Table
:columns="columns"
:data="data"
:height="page.limit > 12 ? 610 : ''"
ref="table"
stripe
></Table>
</div>
<div class="page-turn-wrap">
<Page
:current="Number(page.page)"
:page-size="Number(page.limit)"
:page-size-opts="[10, 20, 100, Infinity]"
:total="Number(page.total)"
@on-change="changePage"
@on-page-size-change="changeLimit"
show-elevator
show-sizer
show-total
></Page>
</div>
</div>
</template>
<script src="./js/index.js"></script>

View File

@ -0,0 +1,149 @@
export default {
name: 'StatsRenewal',
data() {
return {
search: {
show: true
},
options: {
name: '',
time: [
this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM-DD'),
this.moment().subtract('1', 'months').endOf('month').format('YYYY-MM-DD')
]
},
data: [],
list: [],
stats: {},
page: {
total: 0,
limit: 10,
page: 1
},
columns: [
{
title: '企业ID',
key: 'company_id',
width: 80
},
{
title: '企业名称',
key: 'company_name'
},
{
title: '激活数',
key: 'activates',
width: 120
},
{
title: '续费数',
key: 'renewals',
width: 120
},
{
title: '续费率',
key: 'ratio',
width: 120
}
]
};
},
created() {
this.index();
},
methods: {
/**
* [index 列表]
* @param {Number} page [description]
* @return {[type]} [description]
*/
index() {
let options = Object.assign({
orderBy: 'id',
sortedBy: 'asc'
},
this.options);
let params = this.searchDataHandle({}, {
limit: 0
}, options);
this.isShowLoading(true);
service.get('api/stats/renewal', {
params
}).then(res => {
this.isShowLoading(false);
if (res.code == 0) {
this.list = res.data;
this.page.total = this.list.length;
this.changePage(1);
}
}).catch(() => {
this.isShowLoading(false);
});
},
/**
* [request 刷新]
* @return {[type]} [description]
*/
request() {
let page = this.page.page;
if (this.data.length == 1) {
page = this.returnPage(this.page.total, this.page.page, this.page.limit);
}
this.index();
this.changePage(page);
},
resetSearch() {
for (let k in this.options) {
if (k === 'month') {
this.options[k] = this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM');
} else {
this.options[k] = '';
}
}
this.index();
},
changeLimit(limit) {
this.page.limit = limit;
this.changePage(1);
},
changePage(page) {
this.page.page = page;
this.data = this.list.slice((page - 1) * this.page.limit, page * this.page.limit);
},
exportExcel() {
this.isShowLoading(true);
let options = Object.assign({
orderBy: 'id',
sortedBy: 'asc'
},
this.options);
let params = this.searchDataHandle({}, {}, options);
this.isShowLoading(true);
service.get('api/stats/company-count/export', {
params
}).then((res) => {
if (res.code === 0) {
this.downloadFile(res.data);
}
this.isShowLoading(false);
}).catch(() => {
this.isShowLoading(false);
});
}
}
};

View File

@ -2,6 +2,7 @@
use App\Domains\Stats\Services\OrderService;
use App\Domains\Export\Services\ExportService;
use App\Domains\Stats\Services\RenewalService;
use App\Domains\Virtual\Services\PropertyService;
use App\Domains\Stats\Exports\CompanyReportDetailExport;