销售激活统计

This commit is contained in:
邓皓元 2019-04-08 18:27:14 +08:00
parent 5b3d51d90d
commit 0ac9ecbe80
20 changed files with 363 additions and 1 deletions

View File

@ -0,0 +1,98 @@
<?php
namespace App\Domains\Stats\Http\Controllers;
use Carbon\Carbon;
use App\Models\Card\Card;
use Illuminate\Http\Request;
use App\Models\Virtual\OrderCard;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
/**
* 销售激活统计
*/
class SoldActivatedController extends Controller
{
protected $request;
/**
* 构造函数,自动注入.
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* 列表.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$conditions = $this->request->all();
Validator::validate($conditions, [
'starttime' => ['required', 'date'],
'endtime' => ['required', 'date', 'after_or_equal:starttime'],
], [
'starttime.required' => '开始时间不能为空',
'endtime.required' => '结束时间不能为空',
'endtime.after_or_equal' => '结束时间必须大于等于开始时间',
]);
$starttime = Carbon::parse($conditions['starttime'])->startOfMonth();
$endtime = Carbon::parse($conditions['endtime'])->endOfMonth();
$query = OrderCard::leftJoin('cards', 'cards.sim', '=', 'virtual_order_cards.sim')
->select([
'company_id',
DB::raw('count(*) as sells'),
DB::raw('count(CASE WHEN virtual_activated_at IS NOT NULL THEN 1 END) as activates'),
DB::raw("to_char(virtual_activated_at, 'YYYY-MM') as activated_month"),
DB::raw("to_char(virtual_order_cards.created_at, 'YYYY-MM') as order_month"),
])->groupBy([
'company_id',
DB::raw("to_char(virtual_activated_at, 'YYYY-MM')"),
DB::raw("to_char(virtual_order_cards.created_at, 'YYYY-MM')")
]);
$query = $query->where('virtual_order_cards.created_at', '>=', $starttime)->where('virtual_order_cards.created_at', '<=', $endtime);
if (isset($conditions['company_id'])) {
$query = $query->where('company_id', $conditions['company_id']);
}
$list = $query->get()->groupBy('company_id');
$res = [];
foreach ($list as $company_id => $companyList) {
$companyList = $companyList->groupBy('order_month');
for ($i=0; $i <= $endtime->diffInMonths($starttime); $i++) {
$month = $starttime->copy()->addMonths($i)->format('Y-m');
$monthList = $companyList[$month] ?? collect();
$monthList = $monthList->keyBy('activated_month');
$res[$company_id][$month]['order_month'] = $month;
$res[$company_id][$month]['sells'] = 0;
for ($j=0; $j <= $endtime->diffInMonths($starttime); $j++) {
$m = $starttime->copy()->addMonths($j)->format('Y-m');
$item = $monthList[$m] ?? [];
$res[$company_id][$month]['sells'] += $item['sells'] ?? 0;
$res[$company_id][$month][$m] = $item['activates'] ?? 0;
}
}
$res[$company_id] = array_values($res[$company_id]);
}
return res($res, '销售激活统计', 201);
}
}

View File

@ -17,4 +17,7 @@ $router->group(['prefix' => 'stats', 'as' => 'stats', 'middleware' => ['adminAut
$router->get('/company-report/export', ['as' => 'company-report.export', 'uses' => 'CompanyReportController@export']);
$router->get('/company-report/detail', ['as' => 'company-report.detail', 'uses' => 'CompanyReportController@detail']);
$router->get('/company-report/detail/export', ['as' => 'company-report.detail.export', 'uses' => 'CompanyReportController@detailExport']);
// 销售激活统计
$router->get('/sold-activated', ['as' => 'sold-activated.index', 'uses' => 'SoldActivatedController@index']);
});

View File

@ -265,6 +265,7 @@ class PermissionSeeder extends Seeder
['name' => 'stats.order.3', 'title' => '加油包订单统计', 'path' => '/stats/order/3', 'icon' => 'md-color-fill', 'type' => 0, 'open' => 3],
['name' => 'stats.company-report.1', 'title' => '用户月报表', 'path' => '/stats/company-report/1', 'icon' => 'ios-contacts', 'type' => 0, 'open' => 3],
['name' => 'stats.company-report.2', 'title' => '增值包月报表', 'path' => '/stats/company-report/2', 'icon' => 'md-bonfire', 'type' => 0, 'open' => 3],
['name' => 'stats.sold-activated', 'title' => '销售激活统计', 'path' => '/stats/sold-activated', 'icon' => 'md-timer', 'type' => 0, 'open' => 3],
],
],
[

View File

@ -28,6 +28,7 @@ const routes = [
{ path: '/stats/company-count', name: 'StatsCompanyCount', component: load('stats/company-count/index'), meta: { title: '企业统计' } },
{ 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: '/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,104 @@
<template>
<div class="page-wrap">
<ui-loading :show="page_loading.show"></ui-loading>
<div class="product-content">
<div class="nav">
<div class="search umar-t5">
<AutoComplete @on-search="handleSearchCompanies" placeholder="输入名称进行过滤"></AutoComplete>
</div>
<div class="box">
<CellGroup @on-click="index" v-for="item in companies" :key="item.id">
<Cell
:name="item.id"
:selected="item.id == params.company_id ? true : false"
:title="item.name"
/>
</CellGroup>
</div>
</div>
<div class="info-wrap">
<div class="page-handle-wrap">
<ul class="handle-wraper bd-b">
<li class="f-l">
<div class="text-exp">
<b>{{company.name}}</b>
</div>
</li>
</ul>
<div class="search-wrap">
<ul class="handle-wraper">
<li class="handle-item lh-32">查询时间</li>
<li class="handle-item">
<DatePicker
:editable="false"
placeholder="开始时间"
placement="bottom-start"
type="month"
v-model.trim="params.starttime"
></DatePicker>
</li>
<li class="handle-item lh-32">-</li>
<li class="handle-item">
<DatePicker
:editable="false"
placeholder="结束时间"
placement="bottom-start"
type="month"
v-model.trim="params.endtime"
></DatePicker>
</li>
<li class="f-r">
<div class="handle-item">
<Button @click="index()" 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 ? data : []"></Table>
</div>
</div>
</div>
</div>
</template>
<script src="./js/index.js"></script>
<style lang="less" scoped>
.page-wrap {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
padding: 0;
.product-content {
display: flex;
height: 100%;
.nav {
width: 20%;
background: #fff;
padding: 10px;
.box {
margin-top: 10px;
overflow-x: hidden;
overflow-y: auto;
height: calc(100% - 5px);
}
}
.info-wrap {
width: 80%;
}
}
}
</style>

View File

@ -0,0 +1,109 @@
export default {
name: 'SoldActivated',
data() {
return {
params: {
company_id: '',
starttime: this.moment().startOf('year').format('YYYY-MM'),
endtime: this.moment().subtract('1', 'months').format('YYYY-MM')
},
search: {
show: false
},
companies: [],
company: { id: 0, name: '请选择企业' },
data: [],
columns: []
};
},
created() {
this.initCompleteCompanies().then(res => {
this.companies = res.filter(function(item) {
return item.status === 0;
});
});
},
methods: {
setColumns() {
let columns = [
{
title: '销售时间',
key: 'order_month',
minWidth: 110
},
{
title: '销售数',
key: 'sells',
minWidth: 110
}
];
for (let i = 0; i <= this.moment(this.params.endtime).diff(this.moment(this.params.starttime), 'months'); i++) {
columns.push({
title: this.moment(this.params.starttime).add(i, 'months').format('YYYY-MM'),
key: this.moment(this.params.starttime).add(i, 'months').format('YYYY-MM'),
minWidth: 110
});
}
this.columns = columns;
},
/**
* [index 列表]
* @param {Number} company_id [description]
* @return {[type]} [description]
*/
index(company_id = null) {
if (company_id) {
this.params.company_id = company_id;
this.company = this.companies.find(item => {
return item.id === company_id;
});
}
if (this.params.company_id === '') {
return this.$Message.error('请先选择企业');
}
this.setColumns();
this.isShowLoading(true);
let params = JSON.parse(JSON.stringify(this.params));
params.starttime = this.moment(params.starttime).format('YYYY-MM');
params.endtime = this.moment(params.endtime).format('YYYY-MM');
service.get('api/stats/sold-activated', {
params
}).then(res => {
this.isShowLoading(false);
if (res.code == 0) {
this.data = res.data[this.params.company_id];
}
}).catch(() => {
this.isShowLoading(false);
});
},
/**
* [request 刷新]
* @return {[type]} [description]
*/
request() {
this.index();
},
resetSearch() {
this.params.starttime = this.moment().startOf('year').format('YYYY-MM');
this.params.endtime = this.moment().subtract('1', 'months').format('YYYY-MM');
this.index();
},
handleSearchCompanies(value) {
this.handleCompleteCompanies(value).then(res => {
this.companies = res.filter(item => {
return item.status === 0;
});
});
}
}
};

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

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

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

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-01a502ce.e5be0e8f.css rel=prefetch><link href=/css/chunk-996b1e80.5cadf3d0.css rel=prefetch><link href=/js/chunk-00ae0766.3874cd10.js rel=prefetch><link href=/js/chunk-01a502ce.b2793a6c.js rel=prefetch><link href=/js/chunk-07a274ec.c3ad5dec.js rel=prefetch><link href=/js/chunk-996b1e80.d3b45e46.js rel=prefetch><link href=/css/app.d71a8195.css rel=preload as=style><link href=/css/chunk-vendors.3c3b2e85.css rel=preload as=style><link href=/js/app.6a9ce39d.js rel=preload as=script><link href=/js/chunk-vendors.ed6443e8.js rel=preload as=script><link href=/css/chunk-vendors.3c3b2e85.css rel=stylesheet><link href=/css/app.d71a8195.css rel=stylesheet></head><body><noscript><strong>很抱歉如果没有启用JavaScript程序不能正常工作若要继续使用请启用它。</strong></noscript><div id=app></div><script src=/js/chunk-vendors.ed6443e8.js></script><script src=/js/app.6a9ce39d.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-64227684.c6156de6.css rel=prefetch><link href=/css/chunk-996b1e80.5cadf3d0.css rel=prefetch><link href=/js/chunk-00ae0766.3874cd10.js rel=prefetch><link href=/js/chunk-07a274ec.20f6d59e.js rel=prefetch><link href=/js/chunk-64227684.f1668692.js rel=prefetch><link href=/js/chunk-996b1e80.1e853bf4.js rel=prefetch><link href=/css/app.d71a8195.css rel=preload as=style><link href=/css/chunk-vendors.3c3b2e85.css rel=preload as=style><link href=/js/app.7c6af744.js rel=preload as=script><link href=/js/chunk-vendors.ed6443e8.js rel=preload as=script><link href=/css/chunk-vendors.3c3b2e85.css rel=stylesheet><link href=/css/app.d71a8195.css rel=stylesheet></head><body><noscript><strong>很抱歉如果没有启用JavaScript程序不能正常工作若要继续使用请启用它。</strong></noscript><div id=app></div><script src=/js/chunk-vendors.ed6443e8.js></script><script src=/js/app.7c6af744.js></script></body></html>