同步卡基础信息数据

This commit is contained in:
邓皓元 2019-01-07 17:56:03 +08:00
parent 3cc1811c70
commit 241dcc5b6c
12 changed files with 335 additions and 87 deletions

View File

@ -4,6 +4,7 @@ namespace App\Domains\Real\Commands\Sync;
use Carbon\Carbon;
use App\Models\Card\Card;
use Illuminate\Support\Arr;
use MongoDB\BSON\UTCDateTime;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Artisan;
@ -25,7 +26,8 @@ class MongoSync extends Command
public function handle()
{
$nextMicrotime = $microtime = app(ConfigService::class)->get(self::CURSOR_KEY) ?: 946656000000;
$microtime = app(ConfigService::class)->get(self::CURSOR_KEY) ?: 946656000000;
$nextMicrotime = intval(microtime(true) * 1000);
$utcDateTime = new UTCDateTime($microtime);
@ -33,9 +35,8 @@ class MongoSync extends Command
$blocs = app(BlocRepository::class)->get()->pluck('id', 'sn')->toArray();
$query = DB::connection('mongo')->table('tblCard')
->select(['cNo', 'iccid', 'imsi', 'comId', 'oType', 'saDate', 'sDate'])
->where('isDel', '<>', 1)
->where('sDate', '>', $utcDateTime)
->select(['cNo', 'bNo', 'iccid', 'imsi', 'comId', 'oType', 'saDate', 'sDate'])
->where('oRDate', '>', $utcDateTime)
->orderBy('sDate');
$total = $query->count();
@ -66,18 +67,22 @@ class MongoSync extends Command
'carrier_operator' => self::$carrierOperators[$value['oType']] ?? 255,
'activated_at' => $activated_at,
'virtual_activated_at' => $activated_at,
'order_status' => intval(!empty($value['bNo'])),
'created_at' => $value['sDate']->toDateTime()->format('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
];
$nextMicrotime = (string) $value['sDate'];
$nextMicrotime = ($nextMicrotime > $microtime) ? $nextMicrotime : $microtime;
}
Card::upsert($values, 'sim', true);
$builder = Card::query()->toBase();
app(ConfigService::class)->set(self::CURSOR_KEY, intval($nextMicrotime));
$sql = $builder->getGrammar()->compileInsert($builder, $values);
$sql .= 'on conflict (sim) do update set
activated_at=excluded.activated_at,
virtual_activated_at=COALESCE(cards.virtual_activated_at, excluded.activated_at),
order_status=excluded.order_status';
$builder->connection->insert($sql, Arr::flatten($array, 1));
if ($page * $this->limit >= $total) {
break;
@ -86,6 +91,8 @@ class MongoSync extends Command
$page++;
}
app(ConfigService::class)->set(self::CURSOR_KEY, intval($nextMicrotime));
app(CardRepository::class)->forgetCached();
}
}

View File

@ -24,44 +24,27 @@ class OrderController extends Controller
*
* @return \Illuminate\Http\Response
*/
public function index($type)
public function index()
{
$conditions = $this->request->all();
$conditions['type'] = $type;
$res = $this->OrderService->index($conditions);
$res = $this->orderService->index($conditions);
return res($res, '订单统计', 201);
}
/**
* 创建.
* 统计明细.
*
* @return \Illuminate\Http\Response
*/
public function create()
public function detail()
{
//
}
$conditions = $this->request->all();
/**
* 编辑.
*
* @return \Illuminate\Http\Response
*/
public function update($id)
{
//
}
/**
* 删除.
*
* @return \Illuminate\Http\Response
*/
public function destroy()
{
//
$res = $this->orderService->detail($conditions);
return res($res, '统计明细', 201);
}
}

View File

@ -7,6 +7,6 @@ $router->group(['prefix' => 'stats', 'as' => 'stats', 'middleware' => ['adminAut
$router->get('/company-count/export', ['as' => 'company-count.export', 'uses' => 'CompanyCountController@export']);
// 订单统计
$router->get('/order/{type}', ['as' => 'order.index', 'uses' => 'OrderController@index']);
$router->get('/order', ['as' => 'order.index', 'uses' => 'OrderController@index']);
});

View File

@ -43,16 +43,15 @@ class OrderService extends Service
*
* @return void
*/
public function index($type, array $conditions = [])
public function index(array $conditions = [])
{
$conditions['type'] = $type;
$conditions['source'] = 1;
$companies = $this->companyRepository->withTrashed()->get()->pluck('name', 'id')->toArray();
$packages = $this->packageRepository->withTrashed()->get()->pluck('name', 'id')->toArray();
$select = [
DB::raw("string_agg(DISTINCT id, ',') as id"),
DB::raw("array_to_string(array_agg(id), ',') as order_id"),
'company_id',
'package_id',
'product_id',
@ -63,10 +62,12 @@ class OrderService extends Service
];
$orders = $this->orderRepository->select($select)->withConditions($conditions)->applyConditions()
->groupBy(['company_id', 'product_id', 'pay_channel'])->paginate($conditions['limit']);
->groupBy(['company_id', 'package_id', 'product_id', 'unit_price', 'pay_channel'])->paginate($conditions['limit']);
$orders->map(function ($item) use ($companies, $packages) {
$item->company_name = $packages[$item->company_id];
$item->unit_price = floatval(sprintf('%.02f', $item->unit_price/100));
$item->custom_price = floatval(sprintf('%.02f', $item->custom_price/100));
$item->company_name = $companies[$item->company_id];
$item->package_name = $packages[$item->package_id];
$item->pay_channel_name = CommonService::namePayChannel($item->pay_channel);
});
@ -88,29 +89,19 @@ class OrderService extends Service
$repository = app($class);
$companies = $this->companyRepository->withTrashed()->get()->pluck('name', 'id')->toArray();
$packages = $this->packageRepository->withTrashed()->get()->pluck('name', 'id')->toArray();
$packages = $this->packageRepository->withTrashed()->get()->keyBy('id')->toArray();
$repository->withConditions($conditions)->applyConditions()->paginate($conditions['limit']);
$cards = $repository->with('order:id,unit_price,pay_channel,order_at')->withConditions($conditions)->applyConditions()->paginate($conditions['limit']);
$select = [
'id',
'company_id',
'package_id',
'unit_price',
'pay_channel',
DB::raw('SUM(counts) as counts'),
DB::raw('SUM(custom_price) as custom_price'),
];
$orders = $this->orderRepository->select($select)->withConditions($conditions)->applyConditions()
->groupBy(['company_id', 'product_id', 'pay_channel'])->paginate($conditions['limit']);
$orders->map(function ($item) use ($companies, $packages) {
$cards->map(function ($item) use ($companies, $packages) {
$item->company_name = $packages[$item->company_id];
$item->package_name = $packages[$item->package_id];
$item->pay_channel_name = CommonService::namePayChannel($item->pay_channel);
$item->package_name = $packages[$item->package_id]['name'];
$item->service_months = $packages[$item->package_id]['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'];
});
return $orders;
return $cards;
}
}

View File

@ -18,6 +18,11 @@ trait OrderCardConcern
$this->model = $this->model->whereIn('id', $conditions['id']);
}
if (isset($conditions['order_id'])) {
$conditions['order_id'] = array_wrap($conditions['order_id']);
$this->model = $this->model->whereIn('order_id', $conditions['order_id']);
}
if (isset($conditions['sim'])) {
$conditions['sim'] = array_wrap($conditions['sim']);
$this->model = $this->model->whereIn('sim', $conditions['sim']);

View File

@ -26,6 +26,7 @@ class CreateCardsTable extends Migration
$table->timestamp('activated_at')->nullable()->comment('激活时间');
$table->timestamp('virtual_activated_at')->nullable()->comment('虚拟激活时间');
$table->tinyInteger('type')->unsigned()->default(0)->comment('类型(0:真实卡 1:虚拟卡 2:未知卡)');
$table->tinyInteger('order_status')->unsigned()->default(0)->comment('订单状态 0:正常 1:退货');
$table->timestamp('cancelled_at')->nullable()->comment('注销时间');
$table->timestamps();

View File

@ -153,9 +153,11 @@ class PermissionSeeder extends Seeder
'type' => 0,
'open' => 3,
'children' => [
[
'name' => 'stats.company-index', 'title' => '企业统计', 'path' => '/stats/company-count', 'icon' => 'md-pulse', 'type' => 0, 'open' => 3
],
['name' => 'stats.company-index', 'title' => '企业统计', 'path' => '/stats/company-count', 'icon' => 'md-pulse', 'type' => 0, 'open' => 3],
['name' => 'stats.order.0', 'title' => '销售订单统计', 'path' => '/stats/order/0', 'icon' => 'md-pulse', 'type' => 0, 'open' => 3],
['name' => 'stats.order.1', 'title' => '续费订单统计', 'path' => '/stats/order/1', 'icon' => 'md-pulse', 'type' => 0, 'open' => 3],
['name' => 'stats.order.2', 'title' => '续费包订单统计', 'path' => '/stats/order/2', 'icon' => 'md-pulse', 'type' => 0, 'open' => 3],
['name' => 'stats.order.3', 'title' => '加油包订单统计', 'path' => '/stats/order/3', 'icon' => 'md-pulse', 'type' => 0, 'open' => 3],
],
],
[

View File

@ -24,7 +24,8 @@ const routes = [
{ path: '/packages/:type', name: 'Packages', component: load('virtual/packages/index'), meta: { title: '套餐管理' } },
{ path: '/cards', name: 'Cards', component: load('virtual/cards/index'), meta: { title: '客户列表' } },
{ path: '/exports', name: 'StatsExports', component: load('exports/index'), meta: { title: '导出记录' } },
{ path: '/stats/company-count', name: 'StatsCompanyCount', component: load('stats/company-count/index'), meta: { title: '企业统计' } }
{ 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: '*', redirect: { path: '/home' } }

View File

@ -52,9 +52,7 @@ export default {
};
},
created() {
window.t = this;
this.index();
console.log(this.$refs.table);
},
methods: {
/**
@ -129,7 +127,6 @@ export default {
this.$nextTick(() => {
setTimeout(() => {
let html = $('.ivu-table-header colgroup').html();
console.log(html);
$('.table-footer-colgroup').html(html);
}, 10);
});

View File

@ -0,0 +1,114 @@
<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">
<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.company_name">
<Option :key="item.id" :value="item.name" v-for="item in completeHandledCompanies">{{ item.name }}</Option>
</AutoComplete>
</li>
<li class="handle-item w-250">
<AutoComplete @on-search="handleCompletePackages" icon="ios-search" placeholder="套餐名称" v-model.trim="params.package_name">
<Option :key="item.id" :value="item.name" v-for="item in completeHandledPackages">{{ item.name }}</Option>
</AutoComplete>
</li>
<li class="handle-item w-250">
<Select clearable placeholder="支付方式" v-model="params.pay_channel">
<Option :value="'bank'">银行转账</Option>
<Option :value="'wx'">微信</Option>
<Option :value="'alipay'">支付宝</Option>
</Select>
</li>
</ul>
<ul class="handle-wraper">
<li class="handle-item w-250">
<DatePicker :editable="false" placeholder="请选择时间" placement="bottom-start" type="daterange" v-model.trim="options.time"></DatePicker>
</li>
<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>
<template class="table-footer" slot="footer">
<colgroup class="table-footer-colgroup"></colgroup>
<thead class="ivu-table">
<tr>
<th>
<div class="ivu-table-cell">总计</div>
</th>
<th>
<div class="ivu-table-cell"></div>
</th>
<th>
<div class="ivu-table-cell"></div>
</th>
<th>
<div class="ivu-table-cell"></div>
</th>
<th>
<div class="ivu-table-cell">{{stats.counts}}</div>
</th>
<th>
<div class="ivu-table-cell">{{stats.custom_price}}</div>
</th>
<th rowspan="1" v-if="page.limit > 12"></th>
</tr>
</thead>
</template>
</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,162 @@
import { sumBy } from 'service/util';
export default {
name: 'StatsOrder',
data() {
return {
search: {
show: true
},
options: {
company_name: null,
package_name: null,
pay_channel: null,
time: null
},
data: [],
list: [],
stats: {},
page: {
total: 0,
limit: 10,
page: 1
},
columns: [
{
title: '企业名称',
key: 'company_name'
},
{
title: '套餐名称',
key: 'package_name',
width: 150
},
{
title: '支付方式',
key: 'pay_channel_name',
width: 120
},
{
title: '销售单价',
key: 'unit_price',
width: 120
},
{
title: '销售数量',
key: 'counts',
width: 120
},
{
title: '销售总金额',
key: 'custom_price',
width: 120
}
]
};
},
created() {
this.type = Number(this.$route.params.type);
this.index();
},
methods: {
/**
* [index 列表]
* @param {Number} page [description]
* @return {[type]} [description]
*/
index() {
let options = Object.assign({
orderBy: 'company_id',
sortedBy: 'asc',
type: this.type
},
this.options);
let params = this.searchDataHandle({}, {
limit: 0
}, options);
this.isShowLoading(true);
service.get('api/stats/order', { 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) {
this.options[k] = null;
}
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);
this.stats = {
counts: sumBy(this.list, 'counts'),
custom_price: sumBy(this.list, 'custom_price')
};
this.$nextTick(() => {
setTimeout(() => {
let html = $('.ivu-table-header colgroup').html();
$('.table-footer-colgroup').html(html);
}, 10);
});
},
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

@ -1,25 +1,10 @@
<?php
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
require_once realpath(dirname(__FILE__) . '/TestCase.php');
$date = new DateTime('2018-10-31');
$date->modify('-1 month');
echo $date->format('Y-m-d');
$res = Carbon::parse('2018-10')->endOfMonth()->subMonth();
$count = DB::connection('mongo')->table('tblCard')
->count();
dd($res);
$conditions = [
'starttime' => Carbon::parse('2018-10-01')->startOfDay(),
'endtime' => Carbon::parse('2018-10-31')->startOfDay(),
];
$res = \DB::connection('mongo')->table('tblCard')->where(function ($query) use ($conditions) {
$query->where('exPCodes.cDate', '>=', $conditions['starttime'])->where('exPCodes.cDate', '<=', $conditions['endtime'])->where('oDate', 'exists', false);
})->orWhere(function ($query) use ($conditions) {
$query->where('exPCodes.oDate', '>=', $conditions['starttime'])->where('exPCodes.oDate', '<=', $conditions['endtime'])->where('pType', 0);
})->first();
dd($res['exPCodes']);
dd($count);