流量管理修改

This commit is contained in:
邓皓元 2019-04-15 17:13:33 +08:00
parent ba10fb5274
commit a27acb5a18
44 changed files with 286 additions and 178 deletions

View File

@ -49,7 +49,10 @@ class CardController extends Controller
$packages = $this->orderCardPartitionRepository->selectRaw('distinct on (sim) sim, package_id')
->whereIn('type', $conditions['type'])
->whereIn('sim', $cards->pluck('sim')->toArray())
->where('service_start_at', '<=', $time)->orderBy('sim')->orderBy('service_start_at', 'desc')
->where(function($query) use ($time){
$query->where('service_start_at', '<=', $time)->orWhereNull('service_start_at');
})
->orderBy('sim')->orderBy('service_start_at', 'desc')
->get()->keyBy('sim');
$cards->map(function ($item) use ($services, $packages) {

View File

@ -44,8 +44,6 @@ class OrderService extends Service
{
$repository = $this->orderCardPartitionRepository->where('type', $conditions['type']);
$conditions['source'] = 1;
$companies = $this->companyRepository->withTrashed()->get()->pluck('name', 'id')->toArray();
$packages = $this->packageRepository->withTrashed()->get()->pluck('name', 'id')->toArray();

View File

@ -65,7 +65,7 @@ class FlowPoolMonthSync extends Command
'sim' => intval($item['sim']),
'package_id' => $packages[$item['vd_package_sn']]['id'],
'pool_id' => $pool_id,
'kilobyte' => ceil($item['flows_used'] * 1024),
'mebibyte' => floatval($item['flows_used']),
];
}, $items);
@ -74,7 +74,7 @@ class FlowPoolMonthSync extends Command
foreach ($items as $sim => $group) {
if (count($group) > 1) {
$temp = $group[0];
$temp['kilobyte'] = array_sum(array_pluck($group, 'kilobyte'));
$temp['mebibyte'] = array_sum(array_pluck($group, 'mebibyte'));
$items[$sim] = [$temp];
}
}

View File

@ -75,31 +75,33 @@ class FlowPoolSync extends Command
$dp_billing_rules = json_decode($item['dp_billing_rules'], true);
$dp_min_cost_rules = json_decode($item['dp_min_cost_rules'], true);
$month = Carbon::parse(substr_replace($item['year_month'], '-', 4, 0));
if (count($settings) === 1) {
$start_at = '2000-01-01 00:00:00';
$end_at = '3000-01-01 23:59:59';
} else {
if ($i === 0) {
$start_at = '2000-01-01 00:00:00';
$end_at = Carbon::parse($item['year_month'])->endOfMonth()->format('Y-m-d H:i:s');
$end_at = $month->copy()->endOfMonth()->format('Y-m-d H:i:s');
} elseif ($i === count($settings) - 1) {
$start_at = Carbon::parse($item['year_month'])->startOfMonth()->format('Y-m-d H:i:s');
$start_at = $month->copy()->startOfMonth()->format('Y-m-d H:i:s');
$end_at = '3000-01-01 23:59:59';
} else {
$start_at = Carbon::parse($item['year_month'])->startOfMonth()->format('Y-m-d H:i:s');
$end_at = Carbon::parse($item['year_month'])->endOfMonth()->format('Y-m-d H:i:s');
$start_at = $month->copy()->startOfMonth()->format('Y-m-d H:i:s');
$end_at = $month->copy()->endOfMonth()->format('Y-m-d H:i:s');
}
}
$settingData = [
'pool_id' => $id,
'gradient_price' => intval($dp_billing_rules['first_month_price']) * 100,
'gradient' => $dp_billing_rules['data_step_num'] * 1024,
'gradient' => floatval($dp_billing_rules['data_step_num']),
'gradient_unit' => $dp_billing_rules['data_step_num_unit'] === 'M' ? 0 : 1,
'start_at' => $start_at,
'end_at' => $end_at,
'created_at' => Carbon::parse($item['year_month'])->startOfMonth()->format('Y-m-d H:i:s'),
'updated_at' => Carbon::parse($item['year_month'])->startOfMonth()->format('Y-m-d H:i:s'),
'created_at' => $month->copy()->startOfMonth()->format('Y-m-d H:i:s'),
'updated_at' => $month->copy()->startOfMonth()->format('Y-m-d H:i:s'),
];
$minimum_settings = [];
@ -108,7 +110,7 @@ class FlowPoolSync extends Command
$sn = explode('---', $package)[0];
$minimum_settings[] = [
'package_id' => $packages[$sn]['id'],
'flows' => $rule['dp_min_cost_data'] * 1024,
'flows' => floatval($rule['dp_min_cost_data']),
'price' => $rule['dp_min_cost_money'] * 100,
];
}
@ -120,9 +122,9 @@ class FlowPoolSync extends Command
$real_pool_ids = [];
foreach ( json_decode($value['dp_td_data_pool_sn'], true) as $pool_sn) {
foreach (json_decode($value['dp_td_data_pool_sn'], true) as $pool_sn) {
$pool_sn = explode('---', $pool_sn)[0];
if(isset($realFlowPools[$pool_sn])){
if (isset($realFlowPools[$pool_sn])) {
array_push($real_pool_ids, $realFlowPools[$pool_sn]['id']);
}
}
@ -149,8 +151,10 @@ class FlowPoolSync extends Command
FlowPool::upsert($array, 'id');
$maxId = FlowPoolSetting::withoutTrashed()->max('id');
if ($maxId) {
FlowPoolSetting::whereIn('pool_id', array_pluck($array, 'id'))->forceDelete();
DB::statement("select setval('virtual_flow_pool_settings_id_seq', {$maxId})");
}
FlowPoolSetting::insert($settingArray);
app(FlowPoolRepository::class)->forgetCached();

View File

@ -35,7 +35,7 @@ class FlowPoolExportDetailExport extends AbstractExport implements FromQuery, Wi
$table = app(FlowPoolMonth::class)->getTable() . '_' . $month->format('Ym');
return app(FlowPoolMonth::class)->setTable($table)->where('pool_id', $pool_id)->select(['package_id', 'sim', 'kilobyte']);
return app(FlowPoolMonth::class)->setTable($table)->where('pool_id', $pool_id)->select(['package_id', 'sim', 'mebibyte']);
}
public function headings(): array
@ -43,8 +43,8 @@ class FlowPoolExportDetailExport extends AbstractExport implements FromQuery, Wi
$headings = [
'SIM',
'套餐名称',
'保底流量',
'已用流量',
'保底流量(M)',
'已用流量(M)',
];
return $headings;
@ -76,8 +76,8 @@ class FlowPoolExportDetailExport extends AbstractExport implements FromQuery, Wi
$array[] = [
$item['sim'],
PackageService::load($item['package_id'])['name'],
FlowPoolService::humanFlows($minimum_flows[$item['package_id']] ?? 0),
FlowPoolService::humanFlows($item['kilobyte']),
$minimum_flows[$item['package_id']] ?? 0,
$item['mebibyte'],
];
}

View File

@ -245,8 +245,8 @@ class FlowPoolController extends Controller
$chunk = $setting['cards'];
foreach ($chunk as &$value) {
$value['flow_range'][0] = sprintf('%.02f', $value['flow_range'][0]/1024);
$value['flow_range'][1] = sprintf('%.02f', $value['flow_range'][1]/1024);
$value['flow_range'][0] = sprintf('%.02f', $value['flow_range'][0]);
$value['flow_range'][1] = sprintf('%.02f', $value['flow_range'][1]);
}
$setting['cards'] = $chunk;
@ -259,7 +259,7 @@ class FlowPoolController extends Controller
}
}
$flowPoolData['total_flows'] = sprintf('%.02f', $flowPoolData['total_flows']/1024);
$flowPoolData['total_flows'] = sprintf('%.02f', $flowPoolData['total_flows']);
return res(['flowPool' => $flowPool, 'settings' => $newSettings, 'total' => $cards->values()->sum(), 'total_flows' => $flowPoolData['total_flows']], '数据设置');
}
@ -299,13 +299,13 @@ class FlowPoolController extends Controller
public function importFlows()
{
$file = $this->request->file('file');
$data = ImportService::load($file, ['month', 'pool_id', 'sim', 'kilobyte']);
$data = ImportService::load($file, ['month', 'pool_id', 'sim', 'mebibyte']);
Validator::validate($data, [
'*.month' => ['required'],
'*.pool_id' => ['required'],
'*.sim' => ['required'],
'*.kilobyte' => ['required'],
'*.mebibyte' => ['required'],
]);
$flowPools = app(FlowPoolRepository::class)->withConditions(['id' => array_unique(array_pluck($data, 'pool_id'))])->get()->keyBy('id')->toArray();
@ -349,7 +349,7 @@ class FlowPoolController extends Controller
foreach ($simGroupBy as $sim => $group) {
if (count($group) > 1) {
$temp = $group[0];
$temp['kilobyte'] = array_sum(array_pluck($group, 'kilobyte'));
$temp['mebibyte'] = array_sum(array_pluck($group, 'mebibyte'));
$simGroupBy[$sim] = [$temp];
}
}

View File

@ -126,18 +126,12 @@ class FlowPoolService extends Service
$flowPools = $this->transformer($flowPools, $month);
$table = app(FlowPoolMonth::class)->getTable() . '_' . $month->format('Ym');
$flows = DB::select('select * from get_flow_pool_month_stat(?)', [$month->format('Ym')]);
if (Schema::hasTable($table)) {
$flows = app(FlowPoolMonth::class)->setTable($table)
->select(['sim', 'package_id', 'pool_id', 'kilobyte'])
->whereIn('pool_id', $flowPools->pluck('id')->toArray())->get()->groupBy('pool_id');
} else {
$flows = [];
}
$flows = collect($flows)->collect()->keyBy('pool_id')->toArray();
// 流量统计
$flowPools->map(function ($flowPool) use ($month, $flows) {
$flowPools->map(function ($flowPool) use ($flows) {
$flowArry = $flows[$flowPool->id];
// 无使用流量
@ -151,52 +145,12 @@ class FlowPoolService extends Service
return $flowPool;
}
$setting = $flowPool->settings->where('start_at', '<=', $month)->where('end_at', '>=', $month)->first();
// 无计费规则
if (!$setting) {
$flowPool->members = $flowArry->count();
$flowPool->minimum_flows = $this->humanFlows(0);
$flowPool->excess_flows = $this->humanFlows(array_sum($flowArry->pluck('kilobyte')));
$flowPool->minimum_price = sprintf('%.02f', 0);
$flowPool->excess_price = sprintf('%.02f', 0);
$flowPool->total_price = sprintf('%.02f', 0);
return $flowPool;
}
$gradient = $setting['gradient'] * pow(1024, $setting['gradient_unit']);
$gradient_price = $setting['gradient_price'] / pow(1024, $setting['gradient_unit'] + 1);
$minimum_settings = array_keyBy($setting['minimum_settings'], 'package_id');
$flowGroup = $flowArry->groupBy('package_id');
$flowPool->members = $flowArry->count();
$minimum_flows = 0;
$excess_flows = 0;
$minimum_price = 0;
$excess_price = 0;
foreach ($flowGroup as $package_id => $flowItems) {
$minimum_setting = $minimum_settings[$package_id];
foreach ($flowItems as $item) {
$itemMinimumFlows = $minimum_setting['flows'] ?? 0;
$minimum_flows += $itemMinimumFlows;
$minimum_price += $minimum_setting['price'] ?? 0;
$excess_flow = $item->kilobyte < $itemMinimumFlows ? 0 : $item->kilobyte - $itemMinimumFlows;
$excess_flows += ceil($excess_flow / $gradient) * $gradient;
$excess_price += $excess_flow * $gradient_price;
}
}
$flowPool->minimum_flows = $this->humanFlows($minimum_flows);
$flowPool->excess_flows = $this->humanFlows($excess_flows);
$flowPool->minimum_price = sprintf('%.02f', $minimum_price / 100);
$flowPool->excess_price = sprintf('%.02f', $excess_price / 100);
$flowPool->total_price = sprintf('%.02f', ($minimum_price + $excess_price) / 100);
$flowPool->members = $flowArry['members'];
$flowPool->minimum_flows = $this->humanFlows($flowArry['minimum_flows']);
$flowPool->excess_flows = $this->humanFlows($flowArry['excess_flows']);
$flowPool->minimum_price = sprintf('%.02f', $flowArry['minimum_price'] / 100);
$flowPool->excess_price = sprintf('%.02f', $flowArry['excess_price'] / 100);
$flowPool->total_price = sprintf('%.02f', $flowPool->minimum_price + $flowPool->excess_price);
return $flowPool;
});
@ -285,7 +239,7 @@ class FlowPoolService extends Service
$attributes['start_at'] = Carbon::parse($attributes['start_at'])->startOfMonth()->format('Y-m-d H:i:s');
$attributes['end_at'] = Carbon::parse($attributes['end_at'])->endOfMonth()->format('Y-m-d H:i:s');
$attributes['gradient_price'] = intval($attributes['gradient_price'] * 100);
$attributes['gradient'] = intval($attributes['gradient'] * 1024);
$attributes['gradient'] = floatval($attributes['gradient']);
if (!is_array($attributes['minimum_settings'])) {
throw new InvalidArgumentException('保底流量设置必须为数组');
@ -296,7 +250,7 @@ class FlowPoolService extends Service
foreach ($minimum_settings as &$item) {
$item = array_only($item, ['package_id', 'price', 'flows']);
$item['price'] = intval($item['price'] * 100);
$item['flows'] = intval($item['flows'] * 1024);
$item['flows'] = floatval($item['flows']);
}
$attributes['minimum_settings'] = $minimum_settings;
@ -422,7 +376,7 @@ class FlowPoolService extends Service
public function flows(array $conditions)
{
$conditions = array_only($conditions, ['pool_id', 'month', 'total_flows', 'settings']);
$conditions['total_flows'] = intval($conditions['total_flows'] * 1024);
$conditions['total_flows'] = floatval($conditions['total_flows']);
$settings = $conditions['settings'];
@ -436,8 +390,8 @@ class FlowPoolService extends Service
foreach ($cards as &$card) {
$card = array_only($card, ['counts', 'flow_range']);
$card['flow_range'][0] = intval($card['flow_range'][0] * 1024);
$card['flow_range'][1] = intval($card['flow_range'][1] * 1024);
$card['flow_range'][0] = floatval($card['flow_range'][0]);
$card['flow_range'][1] = floatval($card['flow_range'][1]);
$min_total_flows += $card['counts'] * $card['flow_range'][0];
$max_total_flows += $card['counts'] * $card['flow_range'][1];
}
@ -466,11 +420,15 @@ class FlowPoolService extends Service
throw new NotAllowedException('当前月份计费规则未设置或套餐保底流量未设置');
}
$cards = app(OrderCardPartitionRepository::class)->selectRaw('distinct sim as sim, package_id')->withConditions([
$cardConditions = [
'type' => [0, 1, 2],
'month' => $month,
'company_id' => $flowPool->company_id,
'package_id' => array_keys($settings),
])->get();
'unit_price' => 0
];
$cards = app(OrderCardPartitionRepository::class)->selectRaw('distinct sim as sim, package_id')->withConditions($cardConditions)->get();
$allTotal = $cards->count();
@ -506,24 +464,26 @@ class FlowPoolService extends Service
$flows = $conditions['total_flows'] * $cardSetting['counts'] / $allTotal;
foreach ($simArray as $sim) {
$kilobyte = rand($range_start, $range_end);
$mebibyte = rand($range_start * 100, $range_end * 100) / 100;
$dataItems[] = [
$rowObj = [
'month' => $month->format('Ym'),
'sim' => $sim['sim'],
'package_id' => $package_id,
'pool_id' => $pool_id,
'kilobyte' => $kilobyte,
'mebibyte' => $mebibyte,
];
$dataItems[] = $rowObj;
}
$itemKilobyte = array_sum(array_pluck($dataItems, 'kilobyte'));
$itemMebibyte = array_sum(array_pluck($dataItems, 'mebibyte'));
if ($itemKilobyte) {
$k = $flows/$itemKilobyte;
if ($itemMebibyte) {
$k = $flows/$itemMebibyte;
foreach ($dataItems as &$value) {
$value['kilobyte'] = round($value['kilobyte'] * $k);
$value['mebibyte'] = round($value['mebibyte'] * $k);
}
}
@ -581,14 +541,14 @@ class FlowPoolService extends Service
$query = app(FlowPoolMonth::class)->setTable($table)->where('pool_id', $pool_id);
if (Schema::hasTable($table) && $total = $query->count()) {
$cards = $query->select(['package_id', 'sim', 'kilobyte'])->forPage($page, $limit)->get();
$cards = $query->select(['package_id', 'sim', 'mebibyte'])->forPage($page, $limit)->get();
} else {
$cards = collect();
}
$cards->map(function ($item) use ($minimum_flows) {
$item->package_name = PackageService::load($item->package_id)['name'];
$item->kilobyte = $this->humanFlows($item->kilobyte);
$item->mebibyte = $this->humanFlows($item->mebibyte);
$item->minimum_flows = $this->humanFlows($minimum_flows[$item->package_id] ?? 0);
});
@ -697,12 +657,12 @@ class FlowPoolService extends Service
foreach ($settings as &$setting) {
$setting['gradient_price'] = sprintf('%.02f', $setting['gradient_price']/100);
$setting['gradient'] = sprintf('%d', $setting['gradient']/1024);
$setting['gradient'] = sprintf('%.02f', $setting['gradient']);
$minimum_settings = $setting['minimum_settings'] ?? [];
foreach ($minimum_settings as &$minimum_setting) {
$minimum_setting['price'] = sprintf('%.02f', $minimum_setting['price']/100);
$minimum_setting['flows'] = floatval($minimum_setting['flows']/1024);
$minimum_setting['flows'] = floatval($minimum_setting['flows']);
}
$setting['minimum_settings'] = $minimum_settings;
@ -729,7 +689,7 @@ class FlowPoolService extends Service
public static function humanFlows($int)
{
return human_filesize($int, 2, ['unit' => 'KB', 'min' => 'MB', 'max' => 'PB']);
return human_filesize($int, 2, ['unit' => 'MB', 'min' => 'MB', 'max' => 'MB']);
}
/**

View File

@ -13,13 +13,13 @@ use App\Models\Card\Card;
* @property int $sim SIM号
* @property int $package_id 套餐ID
* @property int $pool_id 流量池ID
* @property int $kilobyte 使用流量 单位KB
* @property int $mebibyte 使用流量 单位MB
* @property-read \App\Models\Card\Card $card
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Virtual\FlowPoolMonth newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Virtual\FlowPoolMonth newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Virtual\FlowPoolMonth query()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Virtual\FlowPoolMonth whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Virtual\FlowPoolMonth whereKilobyte($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Virtual\FlowPoolMonth wheremebibyte($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Virtual\FlowPoolMonth whereMonth($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Virtual\FlowPoolMonth wherePoolId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Virtual\FlowPoolMonth whereProductId($value)

View File

@ -177,7 +177,9 @@ if (! function_exists('human_filesize')) {
$factor = $factor > array_search($options['max'], $size) ? array_search($options['max'], $size) : $factor;
}
return sprintf("%.{$decimals}f", $int / pow(1024, $factor)) . @$size[$factor];
$result = $int / pow(1024, $factor);
return sprintf("%.{$decimals}f", $result) . @$size[$factor];
}
}

View File

@ -38,7 +38,7 @@ class CreateFlowPoolTables extends Migration
$table->string('sn', 32)->default('')->comment('编号');
$table->integer('company_id')->unsigned()->default(0)->comment('关联企业ID');
$table->string('name', 32)->unsigned()->default(0)->comment('名称');
$table->integer('flows')->default(255)->comment('流量值 -1不限流量 单位MB');
$table->integer('flows')->default(-1)->comment('流量值 -1不限流量 单位MB');
$table->tinyInteger('carrier_operator')->unsigned()->default(255)->comment('运营商(0:联通 1:移动 2:电信)');
$table->tinyInteger('shared')->unsigned()->default(0)->comment('共享类型 0:未知 1纵向共享 2横向共享');
$table->text('package_ids')->nullable()->comment('包含套餐');
@ -61,7 +61,7 @@ class CreateFlowPoolTables extends Migration
$table->integer('pool_id')->unsigned()->default(0)->comment('流量池ID');
$table->text('minimum_settings')->nullable()->comment('套餐保底配置');
$table->integer('gradient_price')->unsigned()->default(0)->comment('梯度单价');
$table->integer('gradient')->unsigned()->default(0)->comment('梯度');
$table->decimal('gradient', 10, 2)->unsigned()->default(0)->comment('梯度');
$table->tinyInteger('gradient_unit')->unsigned()->default(0)->comment('梯度单位 0:M 1:G');
$table->timestamp('start_at')->nullable()->comment('开始时间');
$table->timestamp('end_at')->nullable()->comment('结束时间');
@ -79,7 +79,7 @@ class CreateFlowPoolTables extends Migration
$table->increments('id')->comment('自增ID');
$table->integer('pool_id')->unsigned()->default(0)->comment('流量池ID');
$table->integer('month')->unsigned()->default(0)->comment('月份');
$table->integer('total_flows')->unsigned()->default(0)->comment('总使用流量 单位KB');
$table->decimal('total_flows', 10, 2)->unsigned()->default(0)->comment('总使用流量 单位MB');
$table->text('settings')->nullable()->comment('配置');
$table->timestamps();
@ -96,12 +96,14 @@ class CreateFlowPoolTables extends Migration
$table->bigInteger('sim')->unsigned()->default(0)->comment('SIM号');
$table->integer('package_id')->unsigned()->default(0)->comment('套餐ID');
$table->integer('pool_id')->unsigned()->default(0)->comment('流量池ID');
$table->integer('kilobyte')->unsigned()->default(0)->comment('使用流量 单位KB');
$table->decimal('mebibyte', 10, 2)->unsigned()->default(0)->comment('使用流量 单位MB');
$table->comment('VD卡月流量');
$table->partition('month', 'list');
});
}
DB::unprepared(File::get(__DIR__ . '/create_flow_pool_settings_view.pgsql'));
}
/**

View File

@ -0,0 +1,64 @@
CREATE OR REPLACE VIEW virtual_flow_pool_settings_view AS
SELECT pool_id,
json_array_elements(minimum_settings::json) ->> 'package_id' AS package_id,
json_array_elements(minimum_settings::json) ->> 'flows' AS flows,
json_array_elements(minimum_settings::json) ->> 'price' AS price,
gradient * pow(1024, gradient_unit) as gradient,
gradient_price / pow(1024, gradient_unit) as gradient_price,
start_at,
end_at
FROM virtual_flow_pool_settings
CREATE OR REPLACE FUNCTION GET_FLOW_POOL_MONTH_STAT(INT)
RETURNS TABLE
(
pool_id INT,
members NUMERIC,
minimum_flows NUMERIC,
minimum_price NUMERIC,
excess_flows NUMERIC,
excess_price NUMERIC
)
AS
$$
DECLARE
query TEXT;
BEGIN
query := 'SELECT virtual_flow_pool_months.pool_id,
virtual_flow_pool_months.package_id,
COUNT(*) as members,
SUM(virtual_flow_pool_settings_view.flows::NUMERIC) AS minimum_flows,
SUM(virtual_flow_pool_settings_view.price::NUMERIC) AS minimum_price,
CASE WHEN SUM(virtual_flow_pool_months.mebibyte) - SUM(virtual_flow_pool_settings_view.flows::NUMERIC) < 0 THEN 0
ELSE SUM(virtual_flow_pool_months.mebibyte) - SUM(virtual_flow_pool_settings_view.flows::NUMERIC) END AS excess_flows,
AVG(virtual_flow_pool_settings_view.gradient::int) AS gradient,
AVG(virtual_flow_pool_settings_view.gradient_price::NUMERIC) AS gradient_price
FROM virtual_flow_pool_months
JOIN virtual_flow_pool_settings_view ON
virtual_flow_pool_settings_view.package_id::int = virtual_flow_pool_months.package_id AND
virtual_flow_pool_settings_view.pool_id::int = virtual_flow_pool_months.pool_id AND
virtual_flow_pool_settings_view.start_at <=
(overlay($1::text placing ''-'' from 5 for 0) || ''-01 00:00:00'')::TIMESTAMP AND
(virtual_flow_pool_settings_view.end_at >=
(overlay($1::text placing ''-'' from 5 for 0) || ''-01 23:59:59'')::TIMESTAMP OR
virtual_flow_pool_settings_view.end_at IS NULL)
WHERE virtual_flow_pool_months.month = $1
GROUP BY virtual_flow_pool_months.pool_id, virtual_flow_pool_months.package_id
';
query := 'SELECT pool_id,
SUM(members) as members,
SUM(minimum_flows) as minimum_flows,
SUM(minimum_price) as minimum_price,
SUM(excess_flows) as excess_flows,
CEIL(SUM(excess_flows) / AVG(gradient)) * AVG(gradient) * AVG(gradient_price) as excess_price
FROM (' || query || ') AS t GROUP BY pool_id';
RAISE NOTICE '%s', query;
RETURN QUERY EXECUTE query USING $1;
END;
$$ LANGUAGE plpgsql;

View File

@ -246,6 +246,8 @@ class PermissionSeeder extends Seeder
['name' => 'virtual.flow-pools.create', 'title' => '创建', 'description' => 'create', 'type' => 1],
['name' => 'virtual.flow-pools.update', 'title' => '编辑', 'description' => 'update', 'type' => 1],
['name' => 'virtual.flow-pools.destroy', 'title' => '删除', 'description' => 'destroy', 'type' => 1],
['name' => 'virtual.flow-pools.import', 'title' => '导入', 'description' => 'input', 'type' => 1],
['name' => 'virtual.flow-pools.export', 'title' => '导出', 'description' => 'output', 'type' => 1],
],
],
],
@ -266,6 +268,12 @@ class PermissionSeeder extends Seeder
['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],
[
'name' => 'stats.flow-pools', 'title' => '流量池统计', 'path' => '/flow-pools', 'icon' => 'md-swap', 'type' => 0, 'open' => 3,
'children' => [
['name' => 'stats.flow-pools.show', 'title' => '明细', 'description' => 'show', 'type' => 1],
]
],
],
],
[

View File

@ -25,6 +25,10 @@ class PropertySettingSeeder extends Seeder
*/
public function run()
{
if (app(PropertySettingRepository::class)->count()) {
return;
};
app(PropertySettingRepository::class)->truncate();
$data = [];

View File

@ -27,11 +27,11 @@
<Button @click="index(1)" icon="md-refresh">刷新</Button>
</div>
<div class="handle-item">
<div class="handle-item" v-has="'output'">
<Button @click="exportExcel" icon="md-download">导出</Button>
</div>
<div class="handle-item">
<div class="handle-item" v-has="'input'">
<Button @click="importModel = true" type="warning">导入月流量数据</Button>
</div>
</li>
@ -100,6 +100,9 @@
@on-change="index"
show-elevator
show-total
show-sizer
:page-size-opts="[10, 20, 50, 100]"
@on-page-size-change="changeLimit"
></Page>
</div>

View File

@ -48,7 +48,7 @@ export default {
},
{
title: '已用流量',
key: 'kilobyte'
key: 'mebibyte'
}
]
};

View File

@ -1,4 +1,6 @@
import * as API from "api/virtual/flow_pools";
import { sumBy } from "service/util";
export default {
name: "FlowPools",
components: {
@ -10,6 +12,7 @@ export default {
},
data() {
return {
limit: 10,
options: {
company_name: "",
name: "",
@ -50,8 +53,12 @@ export default {
{
title: "名称",
key: "",
width: 110,
width: 135,
render: (h, { row, column, index }) => {
if (this.list_data && index == this.list_data.data.length - 1) {
return;
}
if (row.setting_status) {
return h("span", row.name);
}
@ -97,12 +104,12 @@ export default {
{
title: "保底流量",
key: "minimum_flows",
width: 110
width: 150
},
{
title: "超出流量",
key: "excess_flows",
width: 110
width: 150
},
{
title: "保底收入(元)",
@ -129,6 +136,10 @@ export default {
key: "",
width: 100,
render: (h, { row, column, index }) => {
if (this.list_data && index == this.list_data.data.length - 1) {
return;
}
return h(
"Tag",
{
@ -150,6 +161,10 @@ export default {
key: "action",
width: 450,
render: (h, { row, column, index }) => {
if (this.list_data && index == this.list_data.data.length - 1) {
return;
}
let html = [];
if (row.deleted_at) {
@ -317,7 +332,7 @@ export default {
{},
{
page,
limit: 5
limit: this.limit
},
this.params()
);
@ -326,14 +341,29 @@ export default {
.then(res => {
this.isShowLoading(false);
if (res.code == 0) {
this.list_data = res.data;
let list_data = res.data;
let array = list_data.data;
array.push({
id: '总计',
members: sumBy(list_data.data, "members"),
total_price: sumBy(list_data.data, "total_price")
});
list_data.data = array;
this.list_data = list_data;
}
})
.catch(() => {
this.isShowLoading(false);
});
},
changeLimit(limit) {
this.limit = limit;
this.index();
},
params() {
if (!this.options.month) {
this.options.month = this.moment()
@ -348,7 +378,7 @@ export default {
carrier_operator: this.options.carrier_operator,
month: this.moment(this.options.month).format("YYYY-MM"),
orderBy: "id",
sortedBy: "asc"
sortedBy: "desc"
};
return params;

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

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-4443c580.c09b5b64.css rel=prefetch><link href=/css/chunk-996b1e80.5cadf3d0.css rel=prefetch><link href=/js/chunk-00ae0766.d130b440.js rel=prefetch><link href=/js/chunk-07a274ec.55e1b3b0.js rel=prefetch><link href=/js/chunk-4443c580.0ce681dd.js rel=prefetch><link href=/js/chunk-996b1e80.92847c4e.js rel=prefetch><link href=/css/app.8e379248.css rel=preload as=style><link href=/css/chunk-vendors.3c3b2e85.css rel=preload as=style><link href=/js/app.02a931c9.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.8e379248.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.02a931c9.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-4443c580.c09b5b64.css rel=prefetch><link href=/css/chunk-996b1e80.5cadf3d0.css rel=prefetch><link href=/js/chunk-00ae0766.d130b440.js rel=prefetch><link href=/js/chunk-07a274ec.55e1b3b0.js rel=prefetch><link href=/js/chunk-4443c580.65acf954.js rel=prefetch><link href=/js/chunk-996b1e80.92847c4e.js rel=prefetch><link href=/css/app.8e379248.css rel=preload as=style><link href=/css/chunk-vendors.3c3b2e85.css rel=preload as=style><link href=/js/app.033c4b93.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.8e379248.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.033c4b93.js></script></body></html>

View File

@ -49,12 +49,12 @@ class File extends UploadedFile
* Create a new fake file.
*
* @param string $name
* @param int $kilobytes
* @param int $mebibytes
* @return \Illuminate\Http\Testing\File
*/
public static function create($name, $kilobytes = 0)
public static function create($name, $mebibytes = 0)
{
return (new FileFactory)->create($name, $kilobytes);
return (new FileFactory)->create($name, $mebibytes);
}
/**
@ -71,14 +71,14 @@ class File extends UploadedFile
}
/**
* Set the "size" of the file in kilobytes.
* Set the "size" of the file in mebibytes.
*
* @param int $kilobytes
* @param int $mebibytes
* @return $this
*/
public function size($kilobytes)
public function size($mebibytes)
{
$this->sizeToReport = $kilobytes * 1024;
$this->sizeToReport = $mebibytes * 1024;
return $this;
}

View File

@ -8,13 +8,13 @@ class FileFactory
* Create a new fake file.
*
* @param string $name
* @param int $kilobytes
* @param int $mebibytes
* @return \Illuminate\Http\Testing\File
*/
public function create($name, $kilobytes = 0)
public function create($name, $mebibytes = 0)
{
return tap(new File($name, tmpfile()), function ($file) use ($kilobytes) {
$file->sizeToReport = $kilobytes * 1024;
return tap(new File($name, tmpfile()), function ($file) use ($mebibytes) {
$file->sizeToReport = $mebibytes * 1024;
});
}

View File

@ -1388,7 +1388,7 @@ trait ValidatesAttributes
// This method will determine if the attribute is a number, string, or file and
// return the proper size accordingly. If it is a number, then number itself
// is the size. If it is a file, we take kilobytes, and for a string the
// is the size. If it is a file, we take mebibytes, and for a string the
// entire length of the string will be considered the attribute size.
if (is_numeric($value) && $hasNumeric) {
return $value;

View File

@ -25,7 +25,7 @@ return [
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'between' => [
'numeric' => 'The :attribute must be between :min and :max.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'file' => 'The :attribute must be between :min and :max mebibytes.',
'string' => 'The :attribute must be between :min and :max characters.',
'array' => 'The :attribute must have between :min and :max items.',
],
@ -50,7 +50,7 @@ return [
'json' => 'The :attribute must be a valid JSON string.',
'max' => [
'numeric' => 'The :attribute may not be greater than :max.',
'file' => 'The :attribute may not be greater than :max kilobytes.',
'file' => 'The :attribute may not be greater than :max mebibytes.',
'string' => 'The :attribute may not be greater than :max characters.',
'array' => 'The :attribute may not have more than :max items.',
],
@ -58,7 +58,7 @@ return [
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min' => [
'numeric' => 'The :attribute must be at least :min.',
'file' => 'The :attribute must be at least :min kilobytes.',
'file' => 'The :attribute must be at least :min mebibytes.',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
],
@ -76,7 +76,7 @@ return [
'same' => 'The :attribute and :other must match.',
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'file' => 'The :attribute must be :size mebibytes.',
'string' => 'The :attribute must be :size characters.',
'array' => 'The :attribute must contain :size items.',
],

View File

@ -18,7 +18,7 @@ namespace Symfony\Component\Finder\Comparator;
* Now this would be very pointless, if NumberCompare didn't understand
* magnitudes.
*
* The target value may use magnitudes of kilobytes (k, ki),
* The target value may use magnitudes of mebibytes (k, ki),
* megabytes (m, mi), or gigabytes (g, gi). Those suffixed
* with an i use the appropriate 2**n version in accordance with the
* IEC standard: http://physics.nist.gov/cuu/Units/binary.html