流量池配置

This commit is contained in:
邓皓元 2019-02-20 15:49:15 +08:00
parent a3a3856fbb
commit f703863e4e
46 changed files with 1880 additions and 951 deletions

View File

@ -0,0 +1,16 @@
<?php
namespace App\Core;
use Dipper\Excel\Concerns\Importable;
abstract class AbstractImport
{
use Importable;
public function __construct()
{
set_time_limit(-1);
ini_set('memory_limit', '4096m');
}
}

View File

@ -5,6 +5,7 @@ namespace App\Domains\Account\Repositories;
use App\Core\Repository;
use App\Models\Account\Account as Model;
use App\Domains\Account\Services\AccountService;
use function App\account_avatar;
class AccountRepository extends Repository
{

View File

@ -28,7 +28,7 @@ class ConfigController extends Controller
{
$key = $this->request->get('key');
$config = $this->configService->get($key);
return res($config, '获取配置', 201);
}

View File

@ -93,7 +93,7 @@ class ExportService extends Service
$url = Storage::disk($disk)->url($export->filename);
return $url;
}
Excel::queue($export, $export->filename, $disk);
}
}

View File

@ -22,7 +22,7 @@ class FileService extends Service
protected $user;
protected $fileRepository;
protected $fileWithRepository;
public static $types = ['account/avatar'];
@ -132,7 +132,7 @@ class FileService extends Service
}
}
return $fileModel;
}
@ -188,7 +188,7 @@ class FileService extends Service
if (empty($news)) {
return false;
}
if ($cover) {
$this->detach($type, $typeid);
}
@ -264,7 +264,7 @@ class FileService extends Service
}
list($width, $height) = ($imageInfo = @getimagesize($file->getRealPath())) === false ? [null, null] : $imageInfo;
if (($filename = $file->storeAs($path, '', $disk)) === false) {
throw new UploadFailedException('上传失败');
}

View File

@ -23,7 +23,7 @@ class FlowPoolSync extends Command
$companies = app(CompanyRepository::class)->withTrashed()->get()->keyBy('sn');
$packages = app(PackageRepository::class)->withTrashed()->get()->keyBy('sn');
$select = ['id', 'shared_type as shared', "level_type as level", 'custom_no', 'cell_number as sn', 'name', 'flows', 'status', 'del', 'create_time'];
$select = ['id', 'type_id', 'shared_type as shared', "level_type as level", 'custom_no', 'cell_number as sn', 'name', 'flows', 'status', 'del', 'create_time'];
$types = DB::connection('real')->table('jxc_flow_cell_type')->select(['id', 'carrieroperator'])->get()->pluck('carrieroperator', 'id')->toArray();
@ -59,7 +59,7 @@ class FlowPoolSync extends Command
$data = [];
foreach ($flowPools as $value) {
$carrier_operator = $types[$value['typeid']] ?? 3;
$carrier_operator = $types[$value['type_id']] ?? 3;
$package_ids = $flowPackages[$value['id']] ?? [];
$data[] = [

View File

@ -3,8 +3,11 @@ namespace App\Domains\Virtual\Http\Controllers;
use App\Core\Controller;
use Illuminate\Http\Request;
use Dipper\Excel\Facades\Excel;
use Illuminate\Support\Facades\Validator;
use App\Exceptions\InvalidArgumentException;
use App\Domains\Virtual\Imports\FlowCardImport;
use App\Domains\Virtual\Services\FlowPoolService;
use App\Domains\Real\Repositories\FlowPoolRepository as RealFlowPoolRepository;
class FlowPoolController extends Controller
{
@ -27,7 +30,7 @@ class FlowPoolController extends Controller
*/
public function real()
{
$list = app(RealFlowPoolRepository::class)->get();
$list = $this->flowPoolService->real();
return res($list, 'RD流量池列表', 201);
}
@ -88,4 +91,59 @@ class FlowPoolController extends Controller
return res(true, '删除成功');
}
/**
* 添加卡.
*
* @return \Illuminate\Http\Response
*/
public function addCards()
{
if (!$this->request->file('file')) {
throw new InvalidArgumentException('上传的文件错误');
}
$cards = (new FlowCardImport)->toArray($this->request->file('file'));
if (empty($cards)) {
throw new InvalidArgumentException('上传的文件错误');
}
$sheet = $cards[0];
$simArray = [];
foreach ($sheet as $row) {
if (is_numeric($row[0])) {
$simArray[] = $row[0];
}
}
$simArray = array_unique($simArray);
if (empty($simArray)) {
throw new InvalidArgumentException('流量卡张数为空');
}
$pool_id = $this->request->get('pool_id', 0);
$this->flowPoolService->addCards($pool_id, $simArray);
return res(true, '添加成功');
}
/**
* 编辑.
*
* @return \Illuminate\Http\Response
*/
public function setting()
{
$attributes = $this->request->all();
$setting = $this->flowPoolService->setting($attributes);
return res($setting, $attributes['id'] ? '修改成功' : '添加成功');
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\Domains\Virtual\Imports;
use App\Core\AbstractImport;
class FlowCardImport extends AbstractImport
{
}

View File

@ -16,7 +16,7 @@ class FlowPoolCardRepository extends Repository
/**
* 是否开启数据转化
*
*
* @var bool
*/
protected $needTransform = false;
@ -24,12 +24,10 @@ class FlowPoolCardRepository extends Repository
/**
* @var array
*/
protected $fieldSearchable = [
'id' => '=',
'created_at' => 'like',
];
protected $fieldSearchable = [];
public function model() {
public function model()
{
return Model::class;
}
@ -52,11 +50,21 @@ class FlowPoolCardRepository extends Repository
*/
public function withConditions(array $conditions = [])
{
if (isset($conditions['id'])) {
$conditions['id'] = array_wrap($conditions['id']);
$this->model = $this->model->whereIn('id', $conditions['id']);
if (isset($conditions['pool_id'])) {
$conditions['pool_id'] = array_wrap($conditions['pool_id']);
$this->model = $this->model->whereIn('pool_id', $conditions['pool_id']);
}
if (isset($conditions['sim'])) {
$conditions['sim'] = array_wrap($conditions['sim']);
$this->model = $this->model->whereIn('sim', $conditions['sim']);
}
if (isset($conditions['package_id'])) {
$conditions['package_id'] = array_wrap($conditions['package_id']);
$this->model = $this->model->whereIn('package_id', $conditions['package_id']);
}
return $this;
}
}
}

View File

@ -1,72 +0,0 @@
<?php
namespace App\Domains\Virtual\Repositories;
use App\Core\Repository;
use App\Models\Virtual\FlowPoolPackage as Model;
class FlowPoolPackageRepository extends Repository
{
/**
* 是否关闭缓存
*
* @var boolean
*/
protected $cacheSkip = false;
/**
* 是否开启数据转化
*
* @var bool
*/
protected $needTransform = false;
/**
* @var array
*/
protected $fieldSearchable = [
'id' => '=',
'created_at' => 'like',
];
public function model() {
return Model::class;
}
/**
* 数据格式化
*
* @param mixed $result
*
* @return mixed
*/
public function transform($model)
{
return $model->toArray();
}
/**
* 查询条件
*
* @return void
*/
public function withConditions(array $conditions = [])
{
if (isset($conditions['id'])) {
$conditions['id'] = array_wrap($conditions['id']);
$this->model = $this->model->whereIn('id', $conditions['id']);
}
if (isset($conditions['pool_id'])) {
$conditions['pool_id'] = array_wrap($conditions['pool_id']);
$this->model = $this->model->whereIn('pool_id', $conditions['pool_id']);
}
if (isset($conditions['package_id'])) {
$conditions['package_id'] = array_wrap($conditions['package_id']);
$this->model = $this->model->whereIn('package_id', $conditions['package_id']);
}
return $this;
}
}

View File

@ -59,4 +59,6 @@ $router->group(['prefix' => 'virtual', 'as' => 'virtual', 'middleware' => ['admi
$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']);
$router->post('/flow-pools/add-cards', ['as' => 'flow-pools.add-cards', 'uses' => 'FlowPoolController@addCards']);
$router->post('/flow-pools/setting', ['as' => 'flow-pools.setting', 'uses' => 'FlowPoolController@setting']);
});

View File

@ -2,23 +2,30 @@
namespace App\Domains\Virtual\Services;
use App\Dicts;
use Carbon\Carbon;
use App\Core\Service;
use Illuminate\Validation\Rule;
use App\Models\Virtual\FlowPool;
use App\Models\Virtual\OrderCard;
use Illuminate\Support\Facades\DB;
use App\Exceptions\NotExistException;
use App\Exceptions\NotAllowedException;
use App\Models\Virtual\FlowPoolSetting;
use Illuminate\Support\Facades\Validator;
use App\Domains\Virtual\Services\CompanyService;
use App\Domains\Virtual\Services\PackageService;
use App\Domains\Virtual\Repositories\FlowPoolRepository;
use App\Domains\Virtual\Repositories\OrderCardRepository;
use App\Domains\Virtual\Repositories\FlowPoolCardRepository;
use App\Domains\Virtual\Repositories\FlowPoolMonthRepository;
use App\Domains\Virtual\Repositories\FlowPoolPackageRepository;
use App\Domains\Virtual\Repositories\FlowPoolSettingRepository;
use App\Domains\Real\Repositories\FlowPoolRepository as RealFlowPoolRepository;
use App\Exceptions\InvalidArgumentException;
use function App\range_compare;
class FlowPoolService extends Service
{
protected $realFlowPoolRepository;
protected $flowPoolRepository;
protected $flowPoolPackageRepository;
protected $flowPoolSettingRepository;
@ -33,19 +40,47 @@ class FlowPoolService extends Service
* @return void
*/
public function __construct(
RealFlowPoolRepository $realFlowPoolRepository,
FlowPoolRepository $flowPoolRepository,
FlowPoolPackageRepository $flowPoolPackageRepository,
FlowPoolSettingRepository $flowPoolSettingRepository,
FlowPoolCardRepository $flowPoolCardRepository,
FlowPoolMonthRepository $flowPoolMonthRepository
) {
$this->realFlowPoolRepository = $realFlowPoolRepository;
$this->flowPoolRepository = $flowPoolRepository;
$this->flowPoolPackageRepository = $flowPoolPackageRepository;
$this->flowPoolSettingRepository = $flowPoolSettingRepository;
$this->flowPoolCardRepository = $flowPoolCardRepository;
$this->flowPoolMonthRepository = $flowPoolMonthRepository;
}
/**
* RD流量池列表
*
* @return void
*/
public function real()
{
$used = $this->flowPoolRepository->select(['id', 'real_pool_ids'])->get();
$array = [];
foreach ($used as $item) {
$item['real_pool_ids'] = $item['real_pool_ids'] ?? [];
foreach ($item['real_pool_ids'] as $key => $value) {
$array[$value] = $item['id'];
}
}
$list = $this->realFlowPoolRepository->get();
$list->map(function ($item) use ($array) {
$item->virtual_pool_id = $array[$item['id']] ?? 0;
});
return $list;
}
/**
* 流量池列表
*
@ -59,19 +94,51 @@ class FlowPoolService extends Service
$flowPools = $this->flowPoolRepository->withConditions($conditions)
->applyConditions()->paginate($limit);
$packages = $this->flowPoolPackageRepository->withConditions([
'pool_id' => $flowPools->pluck('id')->toArray(),
])->get()->groupBy('pool_id');
$packages = $this->flowPoolCardRepository->select([
'pool_id',
'package_id',
])->withConditions(['pool_id' => $flowPools->pluck('id')->toArray()])->groupBy(['pool_id', 'package_id'])->get();
$packages->map(function ($item) {
$item->package_name = app(PackageService::class)->load($item->package_id)['name'];
});
$packages = $packages->groupBy('pool_id');
$settings = $this->flowPoolSettingRepository->withConditions(['pool_id' => $flowPools->pluck('id')->toArray()])->orderBy('start_at', 'desc')->get();
$settings->map(function ($item) use ($packages) {
$itemPackages = $packages[$item->pool_id] ?? [];
$minimum_settings = $item->minimum_settings ?? [];
foreach ($itemPackages as $package) {
if (!in_array($package['package_id'], array_pluck($minimum_settings, 'package_id'))) {
$minimum_settings[] = [
'package_id' => $package['package_id'],
'package_name' => $package['package_name'],
'flows' => 0,
'price' => 0
];
}
}
$item->minimum_settings = $minimum_settings;
});
$settings = $settings->groupBy('pool_id');
$carrierOperators = app(Dicts::class)->get('carrier_operator');
$shares = app(Dicts::class)->get('shares');
$flowPools->map(function ($item) use ($carrierOperators, $shares, $packages) {
$flowPools->map(function ($item) use ($carrierOperators, $shares, $packages, $settings) {
$item->company_name = app(CompanyService::class)->load($item['company_id'])['name'];
$item->carrier_operator_name = $carrierOperators[$item['carrier_operator']];
$item->shared_name = $shares[$item['shared']];
$item->package_ids = $packages[$item->id] ? array_pluck($packages[$item->id], 'package_id') : [];
$item->real_pool_ids = empty($item->real_pool_ids) ? [] : $item->real_pool_ids;
$item->status = $item->end_at ? 1 : 0;
$item->packages = $packages[$item->id] ?? [];
$item->settings = $settings[$item->id] ?? [];
});
return $flowPools;
@ -85,6 +152,11 @@ class FlowPoolService extends Service
*/
public function store(array $attributes = [])
{
$attributes['start_at'] = $attributes['start_at'] ? Carbon::parse($attributes['start_at'])->startOfMonth()->format('Y-m-d H:i:s') : Carbon::now()->startOfMonth()->format('Y-m-d H:i:s');
$attributes['end_at'] = $attributes['status'] ? Carbon::now()->endOfMonth()->format('Y-m-d H:i:s') : null;
$attributes = array_only($attributes, ['id', 'company_id', 'name', 'flows', 'carrier_operator', 'shared', 'real_pool_ids', 'remark', 'start_at', 'end_at']);
$rule = [
'name' => ['required', 'between:2,32', Rule::unique($this->flowPoolRepository->getTable(), 'name')->ignore($attributes['id'])->whereNUll('deleted_at')],
'carrier_operator' => ['required', 'in:0,1,2,3'],
@ -103,25 +175,12 @@ class FlowPoolService extends Service
Validator::validate($attributes, $rule, $message);
if (empty($attributes['package_ids'])) {
throw new NotAllowedException('请至少加入一个套餐');
}
if (!$attributes['id']) {
$maxId = FlowPool::withTrashed()->max('id');
$attributes['id'] = $maxId ? $maxId + 1 : 1;
$attributes['sn'] = self::sn($attributes['id']);
DB::transaction(function () use ($attributes) {
$node = $this->flowPoolRepository->create(array_except($attributes, ['package_ids']));
foreach ($attributes['package_ids'] as $package_id) {
$this->flowPoolPackageRepository->create([
'pool_id' => $node->id,
'package_id' => $package_id,
]);
}
});
$node = $this->flowPoolRepository->create($attributes);
}
if ($attributes['id']) {
@ -131,25 +190,7 @@ class FlowPoolService extends Service
throw new NotExistException('流量池不存在或已删除');
}
DB::transaction(function () use ($attributes, $node) {
$exists = $this->flowPoolPackageRepository->withConditions([
'pool_id' => $node->id,
])->get()->pluck('package_id')->toArray();
$this->flowPoolRepository->setModel($node)->update(array_except($attributes, ['package_ids']));
foreach ($exists as $package_id) {
if (!in_array($package_id, $attributes['package_ids'])) {
$this->flowPoolPackageRepository->withConditions(['package_id' => $package_id])->delete();
}
}
foreach ($attributes['package_ids'] as $package_id) {
if (!in_array($package_id, $exists)) {
$this->flowPoolPackageRepository->create(['pool_id' => $node->id, 'package_id' => $package_id]);
}
}
});
$this->flowPoolRepository->setModel($node)->update($attributes);
}
return $node;
@ -169,6 +210,168 @@ class FlowPoolService extends Service
return true;
}
/**
* 添加卡
*
* @return void
*/
public function addCards($poolId, array $simArray)
{
if (!$this->flowPoolRepository->find($poolId)) {
throw new NotExistException('流量池不存在或已删除');
}
DB::transaction(function () use ($poolId, $simArray) {
foreach (array_chunk($simArray, 20000) as $chunk) {
$array = app(OrderCardRepository::class)->select(['sim', 'package_id'])->withConditions(['sim' => $chunk])
->get()->pluck('package_id', 'sim')->toArray();
$data = [];
foreach ($chunk as $key => $value) {
if (!isset($array[$value])) {
throw new NotAllowedException("{$value} 不存在销售记录");
}
$data[] = [
'pool_id' => $poolId,
'sim' => $value,
'package_id' => $array[$value],
];
}
$this->flowPoolCardRepository->upsert($data, 'sim');
}
});
$this->flowPoolCardRepository->forgetCached();
return true;
}
/**
* 定价管理
*
* @param array $attributes
* @return FlowPool
*/
public function setting(array $attributes = [])
{
$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');
if ($attributes['start_at'] > $attributes['end_at']) {
throw new InvalidArgumentException('开始时间必须小于结束时间');
}
$rule = [
'pool_id' => ['required', Rule::exists($this->flowPoolRepository->getTable(), 'id')],
'first_month_price' => ['required', 'integer'],
'other_month_price' => ['required', 'integer'],
'gradient' => ['required', 'integer'],
'gradient_unit' => ['required', 'in:0,1'],
];
$message = [
'pool_id.required' => '请输入流量池ID',
'first_month_price.required' => '请输入首月单价',
'other_month_price.required' => '请输入次月单价',
'gradient.required' => '请输入梯度',
'gradient_unit.required' => '请选择梯度单位',
];
Validator::validate($attributes, $rule, $message);
if (!$attributes['id']) {
DB::transaction(function () use ($attributes) {
$settings = $this->flowPoolSettingRepository->withConditions(['pool_id' => $attributes['pool_id']])->get();
if (empty($settings)) {
$attributes['start_at'] = '2000-01-01 00:00:00';
$attributes['end_at'] !== '3000-01-01 23:59:59';
}
$creates = [];
if (!empty($settings)) {
foreach ($settings as $item) {
$result = range_compare([$attributes['start_at'], $attributes['end_at']], [$item['start_at'], $item['end_at']]);
switch ($result) {
case 0:
$this->flowPoolSettingRepository->where(['id' => $item['id']])->update($attributes);
$creates = [];
break 2;
case 1:
$this->flowPoolSettingRepository->destroy($item['id']);
$creates[0] = $attributes;
break;
case 2:
$this->flowPoolSettingRepository->destroy($item['id']);
$creates[0] = $attributes;
unset($item['id']);
$creates[1] = $item->toArray();
$creates[1]['end_at'] = Carbon::parse($attributes['start_at'])->subMonth()->endOfMonth()->format('Y-m-d H:i:s');
$creates[2] = $item->toArray();
$creates[2]['start_at'] = Carbon::parse($attributes['end_at'])->addMonth()->startOfMonth()->format('Y-m-d H:i:s');
break 2;
case 3:
case 4:
$creates[0] = $attributes;
break;
case 5:
$creates[0] = $attributes;
$item['start_at'] = Carbon::parse($attributes['end_at'])->addMonth()->startOfMonth()->format('Y-m-d H:i:s');
$this->flowPoolSettingRepository->where(['id' => $item['id']])->update($item);
break;
case 6:
$creates[0] = $attributes;
$item['end_at'] = Carbon::parse($attributes['start_at'])->subMonth()->startOfMonth()->format('Y-m-d H:i:s');
$this->flowPoolSettingRepository->where(['id' => $item['id']])->update($item);
break;
default:
$creates[0] = $attributes;
break;
}
}
} else {
$creates[0] = $attributes;
$creates[0]['start_at'] = '2000-01-01 00:00:00';
$creates[0]['end_at'] !== '3000-01-01 23:59:59';
}
$maxId = FlowPoolSetting::withTrashed()->max('id') ?? 0;
foreach ($creates as $key => $create) {
$create['id'] = ++$maxId;
if ($key) {
$this->flowPoolSettingRepository->create($create);
} else {
$node =$this->flowPoolSettingRepository->create($create);
}
}
});
}
if ($attributes['id']) {
$node = $this->flowPoolSettingRepository->find($attributes['id']);
if (!$node) {
throw new NotExistException('规则不存在或已删除');
}
if ($node->start_at !== $attributes['start_at'] || $node->end_at !== $attributes['end_at']) {
throw new InvalidArgumentException('起止时间不能修改');
}
$this->flowPoolSettingRepository->setModel($node)->update($attributes);
}
return $node;
}
public static function sn($id)
{
return sprintf('FP%011d', $id);

View File

@ -27,4 +27,9 @@ class FlowPool extends Model
{
return $this->belongsToMany(Package::class, 'virtual_flow_pool_packages', 'pool_id', 'package_id');
}
public function settings()
{
return $this->hasMany(FlowPoolSetting::class, 'pool_id', 'id');
}
}

View File

@ -3,8 +3,28 @@
namespace App\Models\Virtual;
use App\Core\Model;
use Illuminate\Database\Eloquent\Builder;
class FlowPoolCard extends Model
{
protected $table = 'virtual_flow_pool_cards';
protected $primaryKey = ['pool_id', 'sim'];
public $incrementing = false;
/**
* Set the keys for a save update query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function setKeysForSaveQuery(Builder $query)
{
foreach ($this->getKeyName() as $key) {
$query->where($key, '=', $this->original[$key] ?? $this->getAttribute($key));
}
return $query;
}
}

View File

@ -1,25 +0,0 @@
<?php
namespace App\Models\Virtual;
use App\Core\Model;
use App\Models\Virtual\Package;
use App\Models\Virtual\FlowPool;
use Illuminate\Database\Eloquent\SoftDeletes;
class FlowPoolPackage extends Model
{
use SoftDeletes;
protected $table = 'virtual_flow_pool_packages';
public function package()
{
return $this->belongsTo(Package::class, 'package_id');
}
public function pool()
{
return $this->belongsTo(FlowPool::class, 'pool_id');
}
}

View File

@ -3,8 +3,15 @@
namespace App\Models\Virtual;
use App\Core\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class FlowPoolSetting extends Model
{
use SoftDeletes;
protected $table = 'virtual_flow_pool_settings';
protected $casts = [
'minimum_settings' => 'array',
];
}

View File

@ -67,9 +67,7 @@ class AppServiceProvider extends ServiceProvider
});
// excel
$this->app->singleton('excel', function ($app) {
return $app->loadComponent('excel', \Dipper\Excel\ExcelServiceProvider::class);
});
$this->app->register(\Dipper\Excel\ExcelServiceProvider::class);
// 全局代理
$this->app->singleton('dipper', function ($app) {

View File

@ -1,9 +1,11 @@
<?php
namespace App;
use Carbon\Carbon;
use App\Events\FileUploadEvent;
use Dipper\Foundation\Support\Time;
use Illuminate\Support\Facades\Event;
use App\Domains\Account\Services\AccountService;
if (! function_exists('cdn')) {
/**
@ -179,3 +181,67 @@ if (! function_exists('human_filesize')) {
return sprintf("%.{$decimals}f", $int / pow(1024, $factor)) . @$size[$factor];
}
}
if (! function_exists('range_compare')) {
/**
* 区间比较
* 0:两区间完全相等
* 1:区间包含 区间1包含区间2
* 2:区间包含 区间2包含区间1
* 3:区间不相交 区间1在左区间2在右
* 4:区间不相交 区间1在右区间2在左
* 5:区间相交 区间1在左区间2在右
* 6:区间相交 区间1在右区间2在左
*
* 情况二:区间不相交 区间1在右区间2在左 2
*
* @param array $array
* @param array $array
*/
function range_compare(array $array1, array $array2)
{
$array1 = array_values($array1);
$array2 = array_values($array2);
// 数组必须是两个值
if (count($array1) !== 2 || count($array2) !== 2) {
throw new \Exception('array count error.');
}
// 数组第一个值要小于第二个值
if ($array1[1] < $array1[0] || $array2[1] < $array2[0]) {
throw new \Exception('array values error.');
}
if ($array1 === $array2) {
return 0;
}
if ($array1[0] <= $array2[0] && $array1[1] >= $array2[1]) {
return 1;
}
if ($array1[0] >= $array2[0] && $array1[1] <= $array2[1]) {
return 2;
}
if ($array1[1] < $array2[0]) {
return 3;
}
if ($array2[1] < $array1[0]) {
return 4;
}
if ($array1[0] < $array2[0]) {
return 5;
}
if ($array2[0] < $array1[0]) {
return 6;
}
return -1;
}
}

View File

@ -41,10 +41,10 @@ class CreateFlowPoolTables extends Migration
$table->integer('flows')->default(255)->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('RD套餐ID');
$table->text('real_pool_ids')->nullable()->comment('RD流量池ID');
$table->text('remark')->nullable()->comment('流量池备注');
$table->tinyInteger('status')->unsigned()->default(0)->comment('状态 0:正常 1:禁用');
$table->timestamp('start_at')->nullable()->comment('开始时间');
$table->timestamp('end_at')->nullable()->comment('结束时间');
$table->timestamps();
$table->softDeletes();
@ -54,20 +54,6 @@ class CreateFlowPoolTables extends Migration
});
}
if (!Schema::hasTable('virtual_flow_pool_packages')) {
Schema::create('virtual_flow_pools', function (Blueprint $table) {
$table->increments('id')->comment('自增ID');
$table->integer('pool_id')->comment('流量池ID');
$table->integer('package_id')->comment('套餐ID');
$table->timestamps();
$table->softDeletes();
$table->unique(['pool_id', 'package_id', 'deleted_at']);
$table->comment('VD流量池');
});
}
if (!Schema::hasTable('virtual_flow_pool_settings')) {
Schema::create('virtual_flow_pool_settings', function (Blueprint $table) {
$table->increments('id')->comment('自增ID');
@ -75,8 +61,11 @@ class CreateFlowPoolTables extends Migration
$table->text('minimum_settings')->nullable()->comment('套餐保底配置');
$table->integer('first_month_price')->unsigned()->default(0)->comment('首月单价');
$table->integer('other_month_price')->unsigned()->default(0)->comment('次月单价');
$table->timestamp('start_at');
$table->timestamp('end_at');
$table->integer('gradient')->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('结束时间');
$table->timestamps();
$table->softDeletes();
$table->index('pool_id');
@ -88,10 +77,13 @@ class CreateFlowPoolTables extends Migration
if (!Schema::hasTable('virtual_flow_pool_cards')) {
Schema::create('virtual_flow_pool_cards', function (Blueprint $table) {
$table->integer('pool_id')->unsigned()->default(0)->comment('流量池ID');
$table->integer('package_id')->unsigned()->default(0)->comment('套餐ID');
$table->bigInteger('sim')->unsigned()->default(0)->comment('SIM号');
$table->comment('VD流量池卡关联表');
$table->primary(['pool_id', 'sim']);
$table->unique('sim');
});
}

View File

@ -58,3 +58,12 @@ export function update(data, id) {
export function destroy(data) {
return service.post('api/virtual/flow-pools/destroy', data);
}
/**
* [setting 流量池计费规则]
* @param {[type]} data [description]
* @return {[type]} [description]
*/
export function setting(data) {
return service.post('api/virtual/flow-pools/setting', data);
}

View File

@ -6,7 +6,7 @@
// Color
@primary-color : #2d8cf0;
@info-color : #b3b3b3;
@info-color : #2db7f5;
@success-color : #19be6b;
@processing-color : @primary-color;
@warning-color : #ff9900;

File diff suppressed because it is too large Load Diff

View File

@ -16,9 +16,6 @@ export default {
},
methods: {
handleComplete(array, value = '', key = 'name', indexKey = 'id') {
console.log(1);
console.log(value);
if (value === '') {
return array;
}

View File

@ -3,6 +3,7 @@ import {
} from 'vuex';
import { objectDot } from 'service/util';
import default_head from 'images/head.png';
import { getToken } from 'service/auth';
export default {
data() {
@ -35,6 +36,9 @@ export default {
};
},
computed: {
token: () => {
return getToken();
},
...mapGetters(['apps_info', 'left_menu', 'top_menu', 'permissions_array', 'permissions_object', 'account', 'page_nodes', 'tagnavs', 'cache_page', 'breadcrumb'])
},
methods: {

View File

@ -49,7 +49,7 @@
type="primary"
v-if="this.status === 'wait'"
:disabled="disabled"
>下一步</Button>
>{{ current ? '下一步' : '开始同步'}}</Button>
<Button
:loading="loading"
@click="clear"

View File

@ -30,13 +30,13 @@ export default {
},
{
'title': '同步企业',
'content': '所有下级企业数据',
'content': '所有企业数据',
'command': 'real:sync-company',
'max': 10
},
{
'title': '同步套餐',
'content': '所有套餐数据',
'content': '所有套餐数据',
'command': 'real:sync-package',
'max': 25
},

View File

@ -91,7 +91,7 @@ export default {
type: 'primary',
size: 'small',
disabled: false,
icon: 'ios-create'
icon: 'md-create'
},
class: ['btn'],
on: {

View File

@ -82,7 +82,7 @@ export default {
type: 'primary',
size: 'small',
disabled: false,
icon: 'ios-create'
icon: 'md-create'
},
class: ['btn'],
on: {

View File

@ -179,7 +179,7 @@
<div class="ui-list">
<div class="ui-list-title"></div>
<div class="ui-list-content">
<Button type="primary" class="btn w-80 umar-r10" icon="ios-create" :disabled="id?false:true" :loading="loading" @click="save">修改</Button>
<Button type="primary" class="btn w-80 umar-r10" icon="md-create" :disabled="id?false:true" :loading="loading" @click="save">修改</Button>
<Button type="primary" ghost class="btn w-80" @click="clear">重置</Button>
</div>
</div>

View File

@ -92,7 +92,7 @@ export default{
type: 'primary',
size: 'small',
disabled: false,
icon: 'ios-create'
icon: 'md-create'
},
class: ['btn'],
on: {

View File

@ -60,7 +60,7 @@ export default{
type: 'primary',
size: 'small',
disabled: false,
icon: 'ios-create'
icon: 'md-create'
},
class: ['btn'],
on: {

View File

@ -104,7 +104,7 @@ export default {
type: 'primary',
size: 'small',
disabled: false,
icon: 'ios-create'
icon: 'md-create'
},
class: ['btn'],
on: {

View File

@ -101,7 +101,7 @@ export default {
type: 'primary',
size: 'small',
disabled: false,
icon: 'ios-create'
icon: 'md-create'
},
class: ['btn'],
on: {

View File

@ -11,6 +11,22 @@
<ui-loading :show="page_loading.show"></ui-loading>
<ul>
<li class="ui-list">
<div class="ui-list-title">
<span class="title-require">*</span>开始统计月份:
</div>
<div class="ui-list-content">
<p>
<DatePicker
type="month"
placeholder="请选择月份"
:style="'width:' + listStyle.width"
v-model.trim="params.start_at"
></DatePicker>
</p>
</div>
</li>
<li class="ui-list">
<div class="ui-list-title">
<span class="title-require">*</span>流量池名称:
@ -39,6 +55,7 @@
:disabled="data ? true : false"
v-model="params.carrier_operator"
:style="'width:' + listStyle.width"
@on-change="selectCo"
>
<Option :value="0">联通</Option>
<Option :value="1">移动</Option>
@ -81,31 +98,15 @@
</li>
<li class="ui-list">
<div class="ui-list-title">
<span class="title-require">*</span>套餐:
</div>
<div class="ui-list-content">
<Transfer
:titles="['备选套餐', '已选套餐']"
:list-style="listStyle"
:data="packages"
:target-keys="package_ids"
@on-change="transferPackages"
></Transfer>
</div>
</li>
<li class="ui-list">
<div class="ui-list-title">
<span class="title-require">*</span>流量池编号:
</div>
<div class="ui-list-title">流量池编号:</div>
<div class="ui-list-content">
<Transfer
:titles="['备选流量池编号', '已选流量池编号']"
:list-style="listStyle"
:data="reals"
:data="realFilters"
:target-keys="real_pool_ids"
@on-change="transferRealFlowPools"
filterable
></Transfer>
</div>
</li>

View File

@ -1,6 +1,6 @@
<template>
<div class="page-wrap">
<ui-loading :show="page_loading.show"></ui-loading>
<ui-loading :show="page_loading.show" :msg="page_loading.msg"></ui-loading>
<div class="page-handle-wrap">
<ul class="handle-wraper bd-b">
@ -103,6 +103,50 @@
></ui-edit>
<ui-detail :data="detailObj.data" :show.sync="detailObj.show"></ui-detail>
<ui-setting
:show.sync="settingObj.show"
:data="settingObj.data"
@add-success="index"
@update-success="index(list_data.current_page)"
></ui-setting>
<Modal v-model="addCardObj.show" title="添加流量卡" :mask-closable="false" :footer-hide="true">
<div class="add-card-handle-wrap">
<ul class="handle-wraper">
<li class="f-l">
<div class="text-exp">
<b>请上传xlsxlsxcsv格式的表格文件</b>
</div>
</li>
<li class="f-r">
<div class="handle-item">
<Button
type="primary"
icon="ios-download-outline"
:to="CONFIG.url + '/storage/templates/add-cards.xls'"
target="_blank"
>下载导入模板</Button>
</div>
</li>
</ul>
<Upload
type="drag"
:action="CONFIG.url + '/api/virtual/flow-pools/add-cards?pool_id=' + addCardObj.pool_id"
:format="['xls', 'xlsx', 'csv']"
:on-success="addCardSuccess"
:on-error="addCardError"
:before-upload="addCardStart"
:headers="{Authorization: 'Bearer ' + token}"
>
<div style="padding: 20px 0">
<Icon type="ios-cloud-upload" size="52" class="primary-color"></Icon>
<p>点击或拖拽文件上上传</p>
</div>
</Upload>
</div>
</Modal>
</div>
</template>

View File

@ -8,7 +8,7 @@ export default {
},
data: {
type: Object,
default() {
default () {
return null;
}
}
@ -20,9 +20,8 @@ export default {
height: '300px'
},
companies: [],
packages: [],
package_ids: [],
reals: [],
realFilters: [],
real_pool_ids: [],
my_show: false,
isUpdate: false,
@ -32,10 +31,10 @@ export default {
carrier_operator: '',
shared: '',
company_id: '',
package_ids: [],
real_pool_ids: [],
status: 0,
remark: ''
remark: '',
start_at: this.moment().format('YYYY-MM')
}
};
},
@ -50,11 +49,17 @@ export default {
return {
'key': item.id,
'label': item.sn + ' - ' + item.name,
'disabled': false
'disabled': false,
'virtual_pool_id': item.virtual_pool_id,
'carrier_operator': item.carrier_operator
};
});
this.filterReals();
}
});
} else {
this.filterReals();
}
this.initCompleteCompanies().then(companies => {
@ -63,18 +68,6 @@ export default {
});
});
this.initCompletePackages().then(packages => {
this.packages = packages.filter(item => {
return item.status === 0;
}).map(item => {
return {
'key': item.id,
'label': item.name,
'disabled': false
};
});
});
if (this.data) {
for (let k in this.data) {
if (k in this.params) {
@ -82,13 +75,32 @@ export default {
}
}
this.package_ids = this.data.package_ids;
this.real_pool_ids = this.data.real_pool_ids;
}
}
}
},
methods: {
filterReals() {
this.realFilters = this.reals.filter(item => {
if (this.params.carrier_operator !== '' && this.params.carrier_operator !== item.carrier_operator) {
return false;
}
if (item.virtual_pool_id === 0) {
return true;
}
if (this.data && item.virtual_pool_id === this.data.id) {
return true;
}
return false;
});
},
selectCo() {
this.filterReals();
},
ok() {
if (this.params.company_id === '') {
this.$Message.info('请选择企业');
@ -105,6 +117,8 @@ export default {
return;
}
this.params.start_at = this.moment(this.params.start_at).format('YYYY-MM');
if (this.data) {
// 编辑
API.update(this.params, this.data.id).then(res => {
@ -141,21 +155,18 @@ export default {
for (let k in this.params) {
if (k == 'status') {
this.params[k] = 0;
} else if (k == 'real_pool_ids' || k == 'package_ids') {
} else if (k == 'real_pool_ids') {
this.params[k] = [];
} else if (k == 'start_at') {
this.params[k] = this.moment().format('YYYY-MM');
} else {
this.params[k] = '';
}
}
this.my_show = false;
this.package_ids = [];
this.real_pool_ids = [];
},
transferPackages(ids) {
this.package_ids = ids;
this.params.package_ids = ids;
},
transferRealFlowPools(ids) {
this.real_pool_ids = ids;
this.params.real_pool_ids = ids;

View File

@ -3,7 +3,8 @@ export default {
name: 'FlowPools',
components: {
UiEdit: resolve => require(['views/virtual/flow_pools/edit'], resolve),
UiDetail: resolve => require(['views/virtual/flow_pools/detail'], resolve)
UiDetail: resolve => require(['views/virtual/flow_pools/detail'], resolve),
UiSetting: resolve => require(['views/virtual/flow_pools/setting'], resolve)
},
data() {
return {
@ -19,10 +20,18 @@ export default {
show: false,
data: null
},
settingObj: {
show: false,
data: null
},
detailObj: {
show: false,
data: null
},
addCardObj: {
show: false,
pool_id: 0
},
search: {
show: false
},
@ -30,7 +39,7 @@ export default {
{
title: 'ID',
key: 'id',
width: 80
width: 75
},
{
title: '名称',
@ -40,12 +49,12 @@ export default {
{
title: '运营商',
key: 'carrier_operator_name',
width: 110
width: 80
},
{
title: '共享类型',
key: 'shared_name',
width: 110
width: 100
},
{
title: '客户名称',
@ -86,7 +95,11 @@ export default {
title: '状态',
key: '',
width: 100,
render: (h, { row, column, index }) => {
render: (h, {
row,
column,
index
}) => {
return h('Button', {
props: {
type: row.status ? 'error' : 'primary',
@ -103,7 +116,7 @@ export default {
{
title: '操作',
key: 'action',
width: 110,
width: 400,
render: (h, {
row,
column,
@ -112,7 +125,11 @@ export default {
let html = [];
if (row.deleted_at) {
return h('Tag', { props: { color: 'default' } }, '该企业已被删除');
return h('Tag', {
props: {
color: 'default'
}
}, '该流量池已被删除');
}
if (this.haveJurisdiction('show')) {
@ -141,7 +158,7 @@ export default {
type: 'primary',
size: 'small',
disabled: false,
icon: 'ios-create'
icon: 'md-create'
},
class: ['btn'],
on: {
@ -152,6 +169,41 @@ export default {
}, '编辑'));
}
if (this.haveJurisdiction('update')) {
html.push(h('Button', {
props: {
type: 'info',
size: 'small',
disabled: false,
icon: 'md-card'
},
class: ['btn'],
on: {
click: (event) => {
this.addCardObj.show = true;
this.addCardObj.pool_id = row.id;
}
}
}, '添加卡'));
}
if (this.haveJurisdiction('update')) {
html.push(h('Button', {
props: {
type: 'warning',
size: 'small',
disabled: false,
icon: 'logo-yen'
},
class: ['btn'],
on: {
click: (event) => {
this.openSetting(true, row);
}
}
}, '计费规则'));
}
if (this.haveJurisdiction('destroy')) {
html.push(h('Button', {
props: {
@ -200,7 +252,9 @@ export default {
* @return {[type]} [description]
*/
index(page = 1) {
let data = this.searchDataHandle({}, { page }, this.params());
let data = this.searchDataHandle({}, {
page, orderBy: 'id', sortedBy: 'asc'
}, this.params());
this.isShowLoading(true);
API.index(data).then(res => {
this.isShowLoading(false);
@ -238,6 +292,17 @@ export default {
};
},
/**
* [openSetting 打开编辑弹窗]
* @return {[type]} [description]
*/
openSetting(bool, data = null) {
this.settingObj = {
show: bool,
data: data
};
},
/**
* [request 刷新]
* @return {[type]} [description]
@ -263,6 +328,22 @@ export default {
}
this.index(1);
},
addCardSuccess(res) {
this.$Message.success(res.message);
this.page_loading.show = false;
this.page_loading.msg = '加载中...';
this.index(this.list_data.current_page);
},
addCardError(error, res, files) {
this.$Message.error(res.message);
this.page_loading.show = false;
this.page_loading.msg = '加载中...';
},
addCardStart() {
this.addCardObj.show = false;
this.page_loading.show = true;
this.page_loading.msg = '数据处理中...';
}
}
};

View File

@ -0,0 +1,170 @@
import * as API from 'api/virtual/flow_pools';
export default {
props: {
show: {
type: Boolean,
default: false
},
data: {
type: Object,
default: null
}
},
data() {
return {
my_show: false,
loading: false,
settings: [],
params: {},
start_at: this.moment('2000-01-01 00:00:00').format('YYYY-MM'),
end_at: this.moment('3000-01-01 23:59:59').format('YYYY-MM'),
monthOptions: {
shortcuts: [
{
text: '最早',
value: () => {
return this.start_at;
}
},
{
text: '至今',
value: () => {
return this.end_at;
}
},
{
text: '本月',
value: () => {
return this.moment().format('YYYY-MM');
}
}
],
disabledDate(date) {
return date && (date.valueOf() < this.start_at || date.valueOf() > this.end_at);
}
}
};
},
watch: {
show(bool) {
this.my_show = bool;
if (bool) {
this.settings = this.data.settings;
if (this.data.settings.length) {
this.set(this.data.settings[0]['id']);
} else {
this.set(0);
}
}
}
},
methods: {
ok() {
if (this.params.pool_id === '') {
this.$Message.info('参数错误');
return;
}
if (this.params.start_at === '') {
this.$Message.info('请选择开始时间');
return;
}
if (this.params.end_at === '') {
this.$Message.info('请选择结束时间');
return;
}
if (this.params.gradient < 1) {
this.$Message.info('梯度必须大于等于1');
return;
}
if (this.params.gradient_unit === '') {
this.$Message.info('请选择梯度单位');
return;
}
for (const key in this.params.minimum_settings) {
let minimum_setting = this.params.minimum_settings[key];
if (minimum_setting.flows === 0 && minimum_setting.price) {
this.$Message.info('保底流量配置不正确');
return;
}
}
this.params.start_at = this.moment(this.params.start_at).format('YYYY-MM');
this.params.end_at = this.moment(this.params.end_at).format('YYYY-MM');
if (this.params.id) {
// 编辑
API.setting(this.params).then(res => {
this.loading = false;
if (res.code == 0) {
this.$emit('update-success');
this.$Message.success('更新成功');
this.clear();
}
}).catch(err => {
this.loading = false;
});
} else {
// 添加
API.setting(this.params).then(res => {
this.loading = false;
if (res.code == 0) {
this.$emit('add-success');
this.$Message.success('添加成功');
this.clear();
}
}).catch(err => {
this.loading = false;
});
}
},
visibleChange(bool) {
if (!bool) {
this.$emit('update:show', false);
}
},
clear() {
this.params = {};
this.my_show = false;
},
set(id) {
if (id) {
this.params = this.settings.filter(item => {
return item.id == id;
})[0];
this.params.id = id;
} else {
let minimum_settings = [];
this.data.packages.map(item => {
minimum_settings.push({
package_id: item.package_id,
package_name: item.package_name,
flows: 0,
price: 0
});
});
this.params = {
pool_id: this.data.id,
start_at: this.data.settings.length ? this.moment().format('YYYY-MM') : this.start_at,
end_at: this.data.settings.length ? this.moment().format('YYYY-MM') : this.end_at,
first_month_price: 0,
other_month_price: 0,
gradient: 0,
gradient_unit: 0,
minimum_settings: minimum_settings
};
}
}
}
};

View File

@ -0,0 +1,137 @@
<template>
<Drawer
:closable="false"
:mask-closable="false"
:title="'计费规则'"
@on-visible-change="visibleChange"
v-model="my_show"
width="750"
>
<div class="page-edit-wrap uinn-lr5">
<ui-loading :show="page_loading.show"></ui-loading>
<Row>
<Col span="6">
<Timeline>
<div v-for="(item, index) in settings" :key="index">
<TimelineItem>
<p class="time">{{moment(item.end_at).format('YYYY-MM')}}</p>
</TimelineItem>
<TimelineItem>
<span slot="dot"></span>
<Button type="text" shape="circle" icon="md-build" @click="set(item.id)">修改规则</Button>
</TimelineItem>
<TimelineItem>
<p class="time">{{moment(item.start_at).format('YYYY-MM')}}</p>
</TimelineItem>
</div>
<TimelineItem>
<span slot="dot"></span>
<Button type="text" shape="circle" icon="md-add" @click="set(0)">添加规则</Button>
</TimelineItem>
</Timeline>
</Col>
<Col span="18">
<Form :model="params" :label-width="100">
<FormItem label="起止时间:" required>
<Col span="11">
<FormItem prop="start_at">
<DatePicker
type="month"
placeholder="请选择月份"
v-model="params.start_at"
:options="monthOptions"
:disabled="Boolean(params.id)"
></DatePicker>
</FormItem>
</Col>
<Col span="2">
<span class="ta-c lh-32 uinn-lr10"></span>
</Col>
<Col span="11">
<FormItem prop="end_at">
<DatePicker
type="month"
placeholder="请选择月份"
v-model="params.end_at"
:options="monthOptions"
:disabled="Boolean(params.id)"
></DatePicker>
</FormItem>
</Col>
</FormItem>
<FormItem label="超出流量:" :label-width="100" required>
<Col span="12">
<FormItem prop="first_month_price" label="首月单价" :label-width="80">
<InputNumber
:max="99999"
:min="0"
v-model="params.first_month_price"
:style="'width:110px'"
></InputNumber>
</FormItem>
</Col>
<Col span="12">
<FormItem prop="other_month_price" label="次月单价" :label-width="80">
<InputNumber
:max="99999"
:min="0"
v-model="params.other_month_price"
:style="'width:110px'"
></InputNumber>
</FormItem>
</Col>
<Col span="12">
<FormItem prop="gradient" label="梯度" :label-width="80">
<InputNumber
:max="99999"
:min="1"
v-model="params.gradient"
:style="'width:110px'"
></InputNumber>
</FormItem>
</Col>
<Col span="12">
<FormItem prop="gradient_unit" label="梯度单位" :label-width="80">
<Select v-model="params.gradient_unit" :style="'width:110px'">
<Option :value="0">M</Option>
<Option :value="1">G</Option>
</Select>
</FormItem>
</Col>
</FormItem>
<FormItem label="保底流量:" :label-width="100">
<Row>
<Col span="8">套餐名称</Col>
<Col span="8">月保底流量M/</Col>
<Col span="8">月保底价格</Col>
</Row>
<Row v-for="(item, index) in params.minimum_settings" :key="index">
<Col span="8">{{item.package_name}}</Col>
<Col span="8">
<FormItem>
<InputNumber :max="99999" :min="0" v-model="params.minimum_settings[index]['flows']"></InputNumber>
</FormItem>
</Col>
<Col span="8">
<FormItem>
<InputNumber :max="99999" :min="0" v-model="params.minimum_settings[index]['price']"></InputNumber>
</FormItem>
</Col>
</Row>
</FormItem>
<FormItem>
<Button @click="clear" class="w-80 umar-r5" ghost type="primary">取消</Button>
<Button :loading="loading" @click="ok" class="w-80" type="primary">提交</Button>
</FormItem>
</Form>
</Col>
</Row>
</div>
</Drawer>
</template>
<script src="./js/setting.js"></script>

View File

@ -128,7 +128,7 @@ export default {
type: 'primary',
size: 'small',
disabled: false,
icon: 'ios-create'
icon: 'md-create'
},
class: ['btn'],
on: {

View File

@ -102,7 +102,7 @@ export default {
type: 'primary',
size: 'small',
disabled: false,
icon: 'ios-create'
icon: 'md-create'
},
class: ['btn'],
on: {

View File

@ -140,7 +140,7 @@ INSERT INTO vd.virtual_orders ("type", sn, "source", company_id, package_id, pro
logs
GROUP BY
order_type, order_sn
) ON CONFLICT (sn, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO NOTHING;
) ON CONFLICT (sn, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO UPDATE SET counts = excluded.counts, total_price = excluded.total_price, custom_price = excluded.custom_price;
-- 第五步:同步订单详情数据
INSERT INTO vd.virtual_order_cards ("type", sim, order_id, company_id, package_id, counts, unit_price, service_start_at, service_end_at, created_at, updated_at)
@ -162,7 +162,7 @@ INSERT INTO vd.virtual_order_cards ("type", sim, order_id, company_id, package_i
LEFT JOIN vd.virtual_orders ON virtual_orders.sn = logs.order_sn
WHERE
logs.order_type = 0
) ON CONFLICT (sim, order_id, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO UPDATE SET service_start_at = excluded.service_start_at, service_end_at = excluded.service_end_at;
) ON CONFLICT (sim, order_id, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO UPDATE SET counts = excluded.counts, service_start_at = excluded.service_start_at, service_end_at = excluded.service_end_at;
INSERT INTO vd.virtual_order_renewal_cards ("type", sim, order_id, company_id, package_id, counts, unit_price, service_start_at, service_end_at, created_at, updated_at)
(
@ -183,7 +183,7 @@ INSERT INTO vd.virtual_order_renewal_cards ("type", sim, order_id, company_id, p
LEFT JOIN vd.virtual_orders ON virtual_orders.sn = logs.order_sn
WHERE
logs.order_type = 1
) ON CONFLICT (sim, order_id, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO UPDATE SET service_start_at = excluded.service_start_at, service_end_at = excluded.service_end_at;
) ON CONFLICT (sim, order_id, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO UPDATE SET counts = excluded.counts, service_start_at = excluded.service_start_at, service_end_at = excluded.service_end_at;
INSERT INTO vd.virtual_order_renewal_package_cards ("type", sim, order_id, company_id, package_id, counts, unit_price, service_start_at, service_end_at, created_at, updated_at)
(
@ -204,7 +204,7 @@ INSERT INTO vd.virtual_order_renewal_package_cards ("type", sim, order_id, compa
LEFT JOIN vd.virtual_orders ON virtual_orders.sn = logs.order_sn
WHERE
logs.order_type = 2
) ON CONFLICT (sim, order_id, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO UPDATE SET service_start_at = excluded.service_start_at, service_end_at = excluded.service_end_at;
) ON CONFLICT (sim, order_id, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO UPDATE SET counts = excluded.counts, service_start_at = excluded.service_start_at, service_end_at = excluded.service_end_at;
INSERT INTO vd.virtual_order_flows_package_cards ("type", sim, order_id, company_id, package_id, counts, unit_price, service_start_at, service_end_at, created_at, updated_at)
(
@ -225,5 +225,5 @@ INSERT INTO vd.virtual_order_flows_package_cards ("type", sim, order_id, company
LEFT JOIN vd.virtual_orders ON virtual_orders.sn = logs.order_sn
WHERE
logs.order_type = 3
) ON CONFLICT (sim, order_id, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO UPDATE SET service_start_at = excluded.service_start_at, service_end_at = excluded.service_end_at;
) ON CONFLICT (sim, order_id, COALESCE(deleted_at::TIMESTAMP, '1970-01-01 08:00:00'::TIMESTAMP)) DO UPDATE SET counts = excluded.counts, service_start_at = excluded.service_start_at, service_end_at = excluded.service_end_at;

Binary file not shown.

View File

@ -24,7 +24,7 @@ function call($command)
Artisan::queue($command, [
'month' => $datetime->format('Y-m'),
]);
$datetime->addMonth();
if ($datetime > Carbon::now()) {

View File

@ -1,17 +1,6 @@
<?php
use Illuminate\Support\Facades\Schema;
use function App\account_avatar;
require_once realpath(dirname(__FILE__) . '/TestCase.php');
Schema::table('virtual_companies', function ($table) {
$table->tinyInteger('status')->unsigned()->default(0)->comment('状态 0:正常 1:禁用');
});
Schema::table('virtual_packages', function ($table) {
$table->tinyInteger('status')->unsigned()->default(0)->comment('状态 0:正常 1:禁用');
});
Schema::table('virtual_products', function ($table) {
$table->tinyInteger('status')->unsigned()->default(0)->comment('状态 0:正常 1:禁用');
});

79
tests/MysqlTest.php Normal file
View File

@ -0,0 +1,79 @@
<?php
use Illuminate\Support\Facades\DB;
require_once realpath(dirname(__FILE__) . '/TestCase.php');
$sql = "SELECT
id,
custom_no ,
company,
content ,
valid_start_time,
valid_end_time,
create_time
FROM
ckb_custom_handle_log
WHERE
type = 11
AND custom_no IN ( SELECT custom_no FROM ckb_custom_handle_log WHERE type = 11 GROUP BY custom_no, valid_start_time HAVING count( * ) > 1 )
ORDER BY
custom_no;";
$res = DB::connection('vd_old')->select($sql);
$array = [];
foreach ($res as &$item) {
$item = (array)$item;
}
$res = array_groupBy($res, 'custom_no');
foreach ($res as $custom_no => $group) {
$group = array_groupBy($group, 'valid_start_time');
foreach ($group as $arr) {
if (count($arr) < 2) {
continue;
}
$item = $arr[0];
$rows = DB::connection('vd_old')->table('ckb_custom_handle_log')
->where('company', $item['company'])
->where('content', $item['content'])
->whereNotIn('custom_no', array_pluck($array, 'custom_no'))
->groupBy('custom_no')
->havingRaw(DB::raw("MAX(valid_end_time) < {$item['valid_start_time']}"))
->orderBy('valid_end_time', 'desc')
->limit(count($arr) - 1)
->get();
foreach ($arr as $key => $item) {
if ($key === 0) {
continue;
}
if (!$rows[$key - 1]) {
throw new \Exception('未找到卡 #:'. $item['custom_no']);
}
echo $key . ',' . $item['custom_no'] . ',' . date('Y-m-d H:i:s', $item['valid_start_time']) . ',' . $rows[$key - 1]->custom_no . PHP_EOL;
$array[] = [
'id' => $item['id'],
'custom_no' => $rows[$key - 1]->custom_no,
];
}
}
}
DB::transaction(function () use ($array) {
foreach ($array as $item) {
DB::connection('vd_old')->table('ckb_custom_handle_log')->where('id', $item['id'])->update(['custom_no' => $item['custom_no']]);
}
});
dd($array);