客户管理等
This commit is contained in:
parent
006c8e8966
commit
b859a811cd
@ -1,12 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Stats\Exports;
|
||||
namespace App\Core;
|
||||
|
||||
use App\Models\Stats\Export;
|
||||
use App\Models\Export\Export;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Dipper\Excel\Events\AfterStore;
|
||||
use Dipper\Excel\Concerns\WithTitle;
|
||||
use Dipper\Excel\Events\AfterExport;
|
||||
use Dipper\Excel\Concerns\Exportable;
|
||||
use Dipper\Excel\Concerns\WithEvents;
|
||||
use Dipper\Excel\Events\BeforeExport;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
@ -14,10 +15,12 @@ use Dipper\Excel\Events\BeforeWriting;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Dipper\Excel\Concerns\ShouldAutoSize;
|
||||
use App\Domains\Stats\Repositories\ExportRepository;
|
||||
use App\Domains\Export\Repositories\ExportRepository;
|
||||
|
||||
abstract class AbstractExport implements WithEvents, WithTitle, ShouldAutoSize
|
||||
{
|
||||
use Exportable;
|
||||
|
||||
public static $classes = [
|
||||
\App\Domains\Stats\Exports\CompanyCountExport::class => '企业统计',
|
||||
];
|
0
app/Domains/Export/.gitkeep
Normal file
0
app/Domains/Export/.gitkeep
Normal file
@ -1,10 +1,11 @@
|
||||
<?php
|
||||
namespace App\Domains\Stats\Http\Controllers;
|
||||
namespace App\Domains\Export\Http\Controllers;
|
||||
|
||||
use App\Core\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Domains\Stats\Services\ExportService;
|
||||
use App\Domains\Export\Services\ExportService;
|
||||
|
||||
class ExportController extends Controller
|
||||
{
|
33
app/Domains/Export/Providers/ExportServiceProvider.php
Normal file
33
app/Domains/Export/Providers/ExportServiceProvider.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace App\Domains\Export\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use App\Domains\Export\Providers\RouteServiceProvider;
|
||||
use Illuminate\Database\Eloquent\Factory as EloquentFactory;
|
||||
|
||||
class ExportServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* 引导启动任何应用程序服务
|
||||
*
|
||||
* php artisan make:migration --path=app/Domains/Export/Database/migrations
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
// $this->loadMigrationsFrom([realpath(__DIR__ . '/../Database/migrations')]);
|
||||
// $this->app->make(EloquentFactory::class)->load(realpath(__DIR__ . '/../Database/factories'));
|
||||
// $this->mergeConfigFrom(realpath(__DIR__ . '/../config.php'), 'domain.export');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个服务提供者
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
}
|
||||
}
|
20
app/Domains/Export/Providers/RouteServiceProvider.php
Normal file
20
app/Domains/Export/Providers/RouteServiceProvider.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace App\Domains\Export\Providers;
|
||||
|
||||
use Dipper\Foundation\Core\RouteServiceProvider as ServiceProvider;
|
||||
|
||||
class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Read the routes from the "api.php" and "web.php" files of this Domain
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$app = $this->app;
|
||||
$namespace = 'App\Domains\Export\Http\Controllers';
|
||||
$pathApi = __DIR__.'/../Routes/api.php';
|
||||
$pathWeb = __DIR__.'/../Routes/web.php';
|
||||
|
||||
$this->loadRoutesFiles($app->router, $namespace, $pathApi, $pathWeb);
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Stats\Repositories;
|
||||
namespace App\Domains\Export\Repositories;
|
||||
|
||||
use App\Core\Repository;
|
||||
use App\Models\Stats\Export as Model;
|
||||
use App\Models\Export\Export as Model;
|
||||
|
||||
class ExportRepository extends Repository
|
||||
{
|
||||
@ -57,6 +57,10 @@ class ExportRepository extends Repository
|
||||
$this->model = $this->model->whereIn('id', $conditions['id']);
|
||||
}
|
||||
|
||||
if (isset($conditions['tag'])) {
|
||||
$this->model = $this->model->where('tag', $conditions['tag']);
|
||||
}
|
||||
|
||||
if (isset($conditions['starttime'])) {
|
||||
$this->model = $this->model->where('created_at', '>=', $conditions['starttime']);
|
||||
}
|
8
app/Domains/Export/Routes/api.php
Normal file
8
app/Domains/Export/Routes/api.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
// Prefix: /api/exports
|
||||
$router->group(['prefix' => 'exports', 'as' => 'exports', 'middleware' => ['adminAuth']], function ($router) {
|
||||
// 导出记录
|
||||
$router->get('/', ['as' => 'index', 'uses' => 'ExportController@index']);
|
||||
$router->post('/destroy', ['as' => 'destroy', 'uses' => 'ExportController@destroy']);
|
||||
});
|
14
app/Domains/Export/Routes/web.php
Normal file
14
app/Domains/Export/Routes/web.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
$router->group(['prefix' => 'exports', 'as' => 'exports'], function($router) {
|
||||
|
||||
// The controllers live in Domains/Export/Http/Controllers
|
||||
// $router->get('/', ['as' => 'index', 'uses' => 'ExportController@index']);
|
||||
|
||||
/**
|
||||
* 需要认证的接口
|
||||
*/
|
||||
// $router->group(['middleware' => ['userAuth']], function($router) {
|
||||
// // $router->post('delete', ['as' => 'delete', 'uses' => 'ExportController@delete']);
|
||||
// });
|
||||
});
|
@ -1,12 +1,12 @@
|
||||
<?php
|
||||
namespace App\Domains\Stats\Services;
|
||||
namespace App\Domains\Export\Services;
|
||||
|
||||
use App\Dicts;
|
||||
use App\Core\Service;
|
||||
use App\Core\AbstractExport;
|
||||
use Dipper\Excel\Facades\Excel;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Domains\Stats\Exports\AbstractExport;
|
||||
use App\Domains\Stats\Repositories\ExportRepository;
|
||||
use App\Domains\Export\Repositories\ExportRepository;
|
||||
|
||||
class ExportService extends Service
|
||||
{
|
||||
@ -57,14 +57,23 @@ class ExportService extends Service
|
||||
}
|
||||
}
|
||||
|
||||
$url = $item->status === 3 ? Storage::disk($item->disk)->url($item->filename) : '';
|
||||
|
||||
$conditions = '';
|
||||
|
||||
foreach (array_except($item->conditions, ['page', 'limit', 'orderBy', 'sortedBy']) as $key => $value) {
|
||||
$conditions .= "$key: $value\n";
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $item->id,
|
||||
'tag_name' => $classes[$item['tag']] ?? '未知',
|
||||
'filesize' => human_filesize($item->filesize),
|
||||
'dateline' => !$item->conditions['starttime'] ? '所有' : $item->conditions['starttime'] . ' 至 ' . $item->conditions['endtime'],
|
||||
'conditions' => $conditions,
|
||||
'status' => $item->status,
|
||||
'status_name' => $status[$item->status],
|
||||
'url' => $status[$item->status] === 3 ? Storage::disk($item->disk)->url($item->filename) : '',
|
||||
'url' => $url,
|
||||
'created_at' => (string)$item->created_at,
|
||||
'updated_at' => (string)$item->updated_at,
|
||||
];
|
13
app/Domains/Export/Tests/Services/ExportServiceTest.php
Normal file
13
app/Domains/Export/Tests/Services/ExportServiceTest.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace App\Domains\Export\Tests\Services;
|
||||
|
||||
use App\Core\TestCase;
|
||||
use App\Domains\Export\Services\ExportService;
|
||||
|
||||
class ExportServiceTest extends TestCase
|
||||
{
|
||||
public function testExportServiceTest()
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
11
app/Domains/Export/composer.json
Normal file
11
app/Domains/Export/composer.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "app/export",
|
||||
"description": "",
|
||||
"type": "app-domain",
|
||||
"require": {
|
||||
|
||||
},
|
||||
"autoload": {
|
||||
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Domains\Stats\Exports;
|
||||
|
||||
use App\Core\AbstractExport;
|
||||
use Dipper\Excel\Concerns\Exportable;
|
||||
use Dipper\Excel\Concerns\WithHeadings;
|
||||
use Dipper\Excel\Concerns\FromCollection;
|
||||
@ -10,8 +11,6 @@ use App\Domains\Stats\Services\CompanyCountService;
|
||||
|
||||
class CompanyCountExport extends AbstractExport implements FromCollection, WithHeadings, WithHeadingRow
|
||||
{
|
||||
use Exportable;
|
||||
|
||||
public $conditions;
|
||||
|
||||
public function __construct(array $conditions = [])
|
||||
|
@ -5,7 +5,7 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Dipper\Excel\Facades\Excel;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Domains\Stats\Services\ExportService;
|
||||
use App\Domains\Export\Services\ExportService;
|
||||
use App\Domains\Stats\Exports\CompanyCountExport;
|
||||
use App\Domains\Stats\Services\CompanyCountService;
|
||||
|
||||
|
@ -2,11 +2,6 @@
|
||||
|
||||
// Prefix: /api/stats
|
||||
$router->group(['prefix' => 'stats', 'as' => 'stats', 'middleware' => ['adminAuth']], function ($router) {
|
||||
|
||||
// 导出记录
|
||||
$router->get('/exports', ['as' => 'exports', 'uses' => 'ExportController@index']);
|
||||
$router->post('/exports/destroy', ['as' => 'exports.destroy', 'uses' => 'ExportController@destroy']);
|
||||
|
||||
// 企业统计
|
||||
$router->get('/company-count', ['as' => 'company-count.index', 'uses' => 'CompanyCountController@index']);
|
||||
$router->get('/company-count/export', ['as' => 'company-count.export', 'uses' => 'CompanyCountController@export']);
|
||||
|
63
app/Domains/Virtual/Exports/CardExport.php
Normal file
63
app/Domains/Virtual/Exports/CardExport.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Virtual\Exports;
|
||||
|
||||
use App\Core\AbstractExport;
|
||||
use Dipper\Excel\Concerns\Exportable;
|
||||
use Dipper\Excel\Concerns\WithHeadings;
|
||||
use Dipper\Excel\Concerns\FromCollection;
|
||||
use Dipper\Excel\Concerns\WithHeadingRow;
|
||||
use App\Domains\Virtual\Services\CardService;
|
||||
|
||||
class CardExport extends AbstractExport implements FromCollection, WithHeadings, WithHeadingRow
|
||||
{
|
||||
public $conditions;
|
||||
|
||||
public function __construct(array $conditions = [])
|
||||
{
|
||||
$this->conditions = $conditions;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function collection()
|
||||
{
|
||||
set_time_limit(-1);
|
||||
|
||||
$collection = app(CardService::class)->index($this->conditions);
|
||||
|
||||
$collection = $collection->only([
|
||||
'id',
|
||||
'sim',
|
||||
'imsi',
|
||||
'iccid',
|
||||
'carrier_operator',
|
||||
'company_name',
|
||||
'package_name',
|
||||
'virtual_activated_at',
|
||||
'status_name',
|
||||
'created_at',
|
||||
'service_start_at',
|
||||
'service_end_at',
|
||||
]);
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'客户编号',
|
||||
'SIM',
|
||||
'IMSI',
|
||||
'ICCID',
|
||||
'运营商',
|
||||
'企业名称',
|
||||
'套餐名称',
|
||||
'激活时间',
|
||||
'状态',
|
||||
'创建时间',
|
||||
'服务开始时间',
|
||||
'服务结束时间',
|
||||
];
|
||||
}
|
||||
}
|
68
app/Domains/Virtual/Http/Controllers/CardController.php
Normal file
68
app/Domains/Virtual/Http/Controllers/CardController.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
namespace App\Domains\Virtual\Http\Controllers;
|
||||
|
||||
use App\Core\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Domains\Virtual\Exports\CardExport;
|
||||
use App\Domains\Virtual\Services\CardService;
|
||||
use App\Domains\Export\Services\ExportService;
|
||||
|
||||
class CardController extends Controller
|
||||
{
|
||||
protected $request;
|
||||
protected $cardService;
|
||||
|
||||
/**
|
||||
* 构造函数,自动注入.
|
||||
*/
|
||||
public function __construct(Request $request, CardService $cardService)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->cardService = $cardService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$conditions = $this->request->all();
|
||||
$conditions['limit'] = $this->request->get('limit', 20);
|
||||
|
||||
if ($conditions['id']) {
|
||||
$conditions['id'] = intval(str_replace('No', '', $conditions['id']));
|
||||
}
|
||||
|
||||
$cards = $this->cardService->index($conditions);
|
||||
|
||||
return res($cards, '卡列表', 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function export()
|
||||
{
|
||||
$conditions = $this->request->all();
|
||||
$conditions['limit'] = 0;
|
||||
|
||||
if ($conditions['id']) {
|
||||
$conditions['id'] = intval(str_replace('No', '', $conditions['id']));
|
||||
}
|
||||
|
||||
$total = $this->orderCardRepository->withConditions($conditions)->applyConditions()->count();
|
||||
|
||||
try {
|
||||
$export = new CardExport($conditions);
|
||||
$url = ExportService::store($export, $this->disk);
|
||||
} catch (\Exception $e) {
|
||||
return err('导出失败,请稍后重试');
|
||||
}
|
||||
|
||||
return res($url, '导出成功', 201);
|
||||
}
|
||||
}
|
@ -4,41 +4,6 @@ namespace App\Domains\Virtual\Repositories\Concerns;
|
||||
|
||||
trait OrderCardConcern
|
||||
{
|
||||
|
||||
/**
|
||||
* 是否关闭缓存
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cacheSkip = false;
|
||||
|
||||
/**
|
||||
* 是否开启数据转化
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $needTransform = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldSearchable = [
|
||||
'id' => '=',
|
||||
'created_at' => 'like',
|
||||
];
|
||||
|
||||
/**
|
||||
* 数据格式化
|
||||
*
|
||||
* @param mixed $result
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform($model)
|
||||
{
|
||||
return $model->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询条件
|
||||
*
|
||||
@ -51,6 +16,11 @@ trait OrderCardConcern
|
||||
$this->model = $this->model->whereIn('id', $conditions['id']);
|
||||
}
|
||||
|
||||
if (isset($conditions['sim'])) {
|
||||
$conditions['sim'] = array_wrap($conditions['sim']);
|
||||
$this->model = $this->model->whereIn('sim', $conditions['sim']);
|
||||
}
|
||||
|
||||
if (isset($conditions['company_id'])) {
|
||||
$this->model = $this->model->where('company_id', $conditions['company_id']);
|
||||
}
|
||||
@ -82,11 +52,11 @@ trait OrderCardConcern
|
||||
}
|
||||
|
||||
if (isset($conditions['starttime'])) {
|
||||
$this->model = $this->model->where('order_at', '>=', $conditions['starttime']);
|
||||
$this->model = $this->model->where('created_at', '>=', $conditions['starttime']);
|
||||
}
|
||||
|
||||
if (isset($conditions['endtime'])) {
|
||||
$this->model = $this->model->where('order_at', '<=', $conditions['endtime']);
|
||||
$this->model = $this->model->where('created_at', '<=', $conditions['endtime']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -10,6 +10,40 @@ class OrderCardRepository extends Repository
|
||||
{
|
||||
use OrderCardConcern;
|
||||
|
||||
/**
|
||||
* 是否关闭缓存
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cacheSkip = false;
|
||||
|
||||
/**
|
||||
* 是否开启数据转化
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $needTransform = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldSearchable = [
|
||||
'id' => '=',
|
||||
'created_at' => 'like',
|
||||
];
|
||||
|
||||
/**
|
||||
* 数据格式化
|
||||
*
|
||||
* @param mixed $result
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform($model)
|
||||
{
|
||||
return $model->toArray();
|
||||
}
|
||||
|
||||
public function model()
|
||||
{
|
||||
return Model::class;
|
||||
|
@ -10,6 +10,40 @@ class OrderFlowPackageCardsRepository extends Repository
|
||||
{
|
||||
use OrderCardConcern;
|
||||
|
||||
/**
|
||||
* 是否关闭缓存
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cacheSkip = false;
|
||||
|
||||
/**
|
||||
* 是否开启数据转化
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $needTransform = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldSearchable = [
|
||||
'id' => '=',
|
||||
'created_at' => 'like',
|
||||
];
|
||||
|
||||
/**
|
||||
* 数据格式化
|
||||
*
|
||||
* @param mixed $result
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform($model)
|
||||
{
|
||||
return $model->toArray();
|
||||
}
|
||||
|
||||
public function model()
|
||||
{
|
||||
return Model::class;
|
||||
|
@ -10,6 +10,40 @@ class OrderRenewalCardRepository extends Repository
|
||||
{
|
||||
use OrderCardConcern;
|
||||
|
||||
/**
|
||||
* 是否关闭缓存
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cacheSkip = false;
|
||||
|
||||
/**
|
||||
* 是否开启数据转化
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $needTransform = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldSearchable = [
|
||||
'id' => '=',
|
||||
'created_at' => 'like',
|
||||
];
|
||||
|
||||
/**
|
||||
* 数据格式化
|
||||
*
|
||||
* @param mixed $result
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform($model)
|
||||
{
|
||||
return $model->toArray();
|
||||
}
|
||||
|
||||
public function model()
|
||||
{
|
||||
return Model::class;
|
||||
|
@ -10,6 +10,40 @@ class OrderRenewalPackageCardRepository extends Repository
|
||||
{
|
||||
use OrderCardConcern;
|
||||
|
||||
/**
|
||||
* 是否关闭缓存
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cacheSkip = false;
|
||||
|
||||
/**
|
||||
* 是否开启数据转化
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $needTransform = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldSearchable = [
|
||||
'id' => '=',
|
||||
'created_at' => 'like',
|
||||
];
|
||||
|
||||
/**
|
||||
* 数据格式化
|
||||
*
|
||||
* @param mixed $result
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform($model)
|
||||
{
|
||||
return $model->toArray();
|
||||
}
|
||||
|
||||
public function model()
|
||||
{
|
||||
return Model::class;
|
||||
|
@ -49,13 +49,7 @@ $router->group(['prefix' => 'virtual', 'as' => 'virtual', 'middleware' => ['admi
|
||||
$router->post('/orders/update/{id}', ['as' => 'orders.update', 'uses' => 'OrderController@update']);
|
||||
$router->post('/orders/destroy', ['as' => 'orders.destroy', 'uses' => 'OrderController@destroy']);
|
||||
|
||||
// 数据统计
|
||||
$router->get('/stat/company-index', ['as' => 'stat.company-index', 'uses' => 'StatController@companyIndex']);
|
||||
|
||||
/**
|
||||
* 需要认证的接口
|
||||
*/
|
||||
// $router->group(['middleware' => ['adminAuth']], function($router) {
|
||||
// // $router->post('delete', ['as' => 'delete', 'uses' => 'VirtualController@delete']);
|
||||
// });
|
||||
// 客户管理
|
||||
$router->get('/cards/index', ['as' => 'cards.index', 'uses' => 'CardController@index']);
|
||||
$router->get('/cards/export', ['as' => 'cards.export', 'uses' => 'CardController@export']);
|
||||
});
|
||||
|
136
app/Domains/Virtual/Services/CardService.php
Normal file
136
app/Domains/Virtual/Services/CardService.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
namespace App\Domains\Virtual\Services;
|
||||
|
||||
use App\Dicts;
|
||||
use App\Core\Service;
|
||||
use App\Models\Card\Card;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Models\Virtual\OrderCard;
|
||||
use App\Domains\Card\Repositories\CardRepository;
|
||||
use App\Domains\Virtual\Repositories\OrderCardRepository;
|
||||
|
||||
class CardService extends Service
|
||||
{
|
||||
protected $orderCardRepository;
|
||||
protected $cardRepository;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(OrderCardRepository $orderCardRepository, CardRepository $cardRepository)
|
||||
{
|
||||
$this->orderCardRepository = $orderCardRepository;
|
||||
$this->cardRepository = $cardRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡列表
|
||||
*
|
||||
* @param array $conditions
|
||||
* @return mixed
|
||||
*/
|
||||
public function index(array $conditions = [])
|
||||
{
|
||||
$limit = $conditions['limit'] ?? 20;
|
||||
|
||||
$cards = $this->orderCardRepository->with(['card', 'company:id,name', 'package:id,name,carrier_operator,service_months', 'renewals', 'renewalPackages'])
|
||||
->withConditions($conditions)->applyConditions()->paginate($limit);
|
||||
|
||||
$carrierOperators = app(Dicts::class)->get('carrier_operator');
|
||||
$cardStatus = app(Dicts::class)->get('card_status');
|
||||
|
||||
$cards->transform(function ($item) use ($carrierOperators, $cardStatus) {
|
||||
$status = $this->getStatus($item->card);
|
||||
$timelines = $this->timelines($item);
|
||||
|
||||
$service_start_at = min(array_pluck($timelines, 'starttime'));
|
||||
$service_end_at = max(array_pluck($timelines, 'endtime'));
|
||||
|
||||
return [
|
||||
'id' => sprintf('No%011d', $item->id),
|
||||
'sim' => $item->sim,
|
||||
'imsi' => $item->card['imsi'],
|
||||
'iccid' => $item->card['iccid'],
|
||||
'carrier_operator' => $carrierOperators[$item->card['carrier_operator']],
|
||||
'company_name' => $item->company['name'],
|
||||
'package_name' => $item->package['name'],
|
||||
'virtual_activated_at' => (string)$item->card['virtual_activated_at'],
|
||||
'status' => $status,
|
||||
'status_name' => $cardStatus[$status],
|
||||
'created_at' => (string)$item->created_at,
|
||||
'updated_at' => (string)$item->updated_at,
|
||||
'service_start_at' => $service_start_at,
|
||||
'service_end_at' => $service_end_at,
|
||||
'timelines' => $timelines,
|
||||
];
|
||||
});
|
||||
|
||||
return $cards;
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡状态
|
||||
*
|
||||
* @param Card $card
|
||||
* @return void
|
||||
*/
|
||||
public static function getStatus($card)
|
||||
{
|
||||
return $card['virtual_activated_at'] ? ($card['cancelled_at'] ? 3 : 2) : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生命周期
|
||||
* @param OrderCard $item
|
||||
*/
|
||||
public static function timelines($item)
|
||||
{
|
||||
$array = [];
|
||||
|
||||
$virtual_activated_at = $item->card['virtual_activated_at'] ? Carbon::parse($item->card['virtual_activated_at'])->format('Y-m') : '';
|
||||
|
||||
// 基础套餐
|
||||
$array[] = [
|
||||
'type' => 0,
|
||||
'name' => $item->package['name'],
|
||||
'starttime' => $item->card['virtual_activated_at'] ? Carbon::parse($item->card['virtual_activated_at'])->format('Y-m') : '',
|
||||
'endtime' => $virtual_activated_at ? Carbon::parse($virtual_activated_at)->addMonths($item->package['service_months'])->format('Y-m') : '',
|
||||
];
|
||||
|
||||
// 续费套餐
|
||||
$packages = $item->renewals->merge($item->renewalPackages);
|
||||
|
||||
$packages = $packages->sortBy(function ($value) {
|
||||
return $value->pivot->created_at;
|
||||
});
|
||||
|
||||
$packages->map(function ($package) use ($next, $virtual_activated_at, &$array) {
|
||||
if (!$virtual_activated_at) {
|
||||
$starttime = $endtime = '';
|
||||
} else {
|
||||
$starttime = (Carbon::parse($package->pivot->created_at) < Carbon::parse($next)) ? Carbon::parse($next) : Carbon::parse($package->pivot->created_at);
|
||||
$endtime = $starttime->copy()->addMonths($package['service_months'] * $package->pivot->counts);
|
||||
$next = $endtime;
|
||||
$starttime = $starttime->format('Y-m');
|
||||
$endtime = $endtime->format('Y-m');
|
||||
}
|
||||
|
||||
$array[] = [
|
||||
'type' => $package->type + 1,
|
||||
'name' => $package->name,
|
||||
'starttime' => $starttime,
|
||||
'endtime' => $endtime,
|
||||
];
|
||||
});
|
||||
|
||||
$typeNames = ['基础套餐', '基础续费', '续费包'];
|
||||
|
||||
foreach ($array as $key => &$value) {
|
||||
$value['type_name'] = $typeNames[$value['type']];
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
13
app/Domains/Virtual/Tests/Services/CardServiceTest.php
Normal file
13
app/Domains/Virtual/Tests/Services/CardServiceTest.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace App\Domains\Virtual\Tests\Services;
|
||||
|
||||
use App\Core\TestCase;
|
||||
use App\Domains\Virtual\Services\CardService;
|
||||
|
||||
class CardServiceTest extends TestCase
|
||||
{
|
||||
public function testCardServiceTest()
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Stats;
|
||||
namespace App\Models\Export;
|
||||
|
||||
use App\Core\Model;
|
||||
|
||||
class Export extends Model
|
||||
{
|
||||
protected $table = 'stats_exports';
|
||||
protected $table = 'exports';
|
||||
|
||||
protected $fillable = ['id', 'sn', 'tag', 'filename' , 'filesize', 'conditions', 'status', 'progress'];
|
||||
|
@ -15,16 +15,16 @@ class OrderCard extends Model
|
||||
|
||||
public function renewals()
|
||||
{
|
||||
return $this->belongsToMany(Package::class, 'virtual_order_renewal_cards', 'sim', 'package_id', 'sim', 'id');
|
||||
return $this->belongsToMany(Package::class, 'virtual_order_renewal_cards', 'sim', 'package_id', 'sim', 'id')->withPivot('created_at', 'counts');
|
||||
}
|
||||
|
||||
public function renewalPackages()
|
||||
{
|
||||
return $this->belongsToMany(Package::class, 'virtual_order_renewal_package_cards', 'sim', 'package_id', 'sim', 'id');
|
||||
return $this->belongsToMany(Package::class, 'virtual_order_renewal_package_cards', 'sim', 'package_id', 'sim', 'id')->withPivot('created_at', 'counts');
|
||||
}
|
||||
|
||||
public function flowPackages()
|
||||
{
|
||||
return $this->belongsToMany(Package::class, 'virtual_order_flows_package_cards', 'sim', 'package_id', 'sim', 'id');
|
||||
return $this->belongsToMany(Package::class, 'virtual_order_flows_package_cards', 'sim', 'package_id', 'sim', 'id')->withPivot('created_at', 'counts');
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class CreateStatsExportsTable extends Migration
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('stats_exports', function (Blueprint $table) {
|
||||
Schema::create('exports', function (Blueprint $table) {
|
||||
$table->increments('id')->comment('自增ID');
|
||||
$table->string('sn', 32)->default('')->comment('命令编号');
|
||||
$table->string('tag', 20)->default('')->comment('标记');
|
||||
@ -37,6 +37,6 @@ class CreateStatsExportsTable extends Migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('stats_exports');
|
||||
Schema::dropIfExists('exports');
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,22 @@ class PermissionSeeder extends Seeder
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'virtual_card_ctrl',
|
||||
'title' => '客户管理',
|
||||
'path' => '#',
|
||||
'icon' => 'ios-settings',
|
||||
'type' => 0,
|
||||
'open' => 3,
|
||||
'children' => [
|
||||
[
|
||||
'name' => 'virtual.cards.index', 'title' => '客户列表', 'path' => '/cards', 'icon' => 'ios-cube', 'type' => 0, 'open' => 3,
|
||||
'children' => [
|
||||
['name' => 'virtual.cards.show', 'title' => '查看', 'description' => 'show', 'type' => 1],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'virtual_order_ctrl',
|
||||
'title' => '订单管理',
|
||||
@ -137,17 +153,22 @@ class PermissionSeeder extends Seeder
|
||||
'type' => 0,
|
||||
'open' => 3,
|
||||
'children' => [
|
||||
[
|
||||
'name' => 'stat.exports.index', 'title' => '导出记录', 'path' => '/stats/exports', 'icon' => 'ios-download', 'type' => 0, 'open' => 3,
|
||||
'children' => [
|
||||
['name' => 'stat.exports.destroy', 'title' => '删除', 'description' => 'destroy', 'type' => 1],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'stats.company-index', 'title' => '企业统计', 'path' => '/stats/company-count', 'icon' => 'md-pulse', 'type' => 0, 'open' => 3
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'export.index',
|
||||
'title' => '导出记录',
|
||||
'path' => '/exports',
|
||||
'icon' => 'ios-download',
|
||||
'type' => 0,
|
||||
'open' => 3,
|
||||
'children' => [
|
||||
['name' => 'exports.destroy', 'title' => '删除', 'description' => 'destroy', 'type' => 1],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
|
25
frontend/src/api/virtual/cards.js
Normal file
25
frontend/src/api/virtual/cards.js
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 客户管理
|
||||
*/
|
||||
|
||||
/**
|
||||
* [index 客户列表]
|
||||
* @param {[type]} data [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
export function index(data) {
|
||||
return service.get('api/virtual/cards/index', {
|
||||
params: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* [show 客户详情]
|
||||
* @param {[type]} data [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
export function exportExcel(data) {
|
||||
return service.get('api/virtual/cards/export', {
|
||||
params: data
|
||||
});
|
||||
}
|
@ -124,7 +124,7 @@ export default {
|
||||
parseTime(time) {
|
||||
return {
|
||||
starttime: this.moment(time[0]).format('YYYY-MM-DD') + ' 00:00:00',
|
||||
endtime: this.moment(time[1]).format('YYYY-MM-DD') + ' 00:00:00'
|
||||
endtime: this.moment(time[1]).format('YYYY-MM-DD') + ' 23:59:59'
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -22,7 +22,8 @@ const routes = [
|
||||
{ path: '/products', name: 'Products', component: load('virtual/products/index'), meta: { title: '定价管理' } },
|
||||
{ path: '/orders', name: 'Orders', component: load('virtual/orders/index'), meta: { title: '订单列表' } },
|
||||
{ path: '/packages', name: 'Packages', component: load('virtual/packages/index'), meta: { title: '套餐管理' } },
|
||||
{ path: '/stats/exports', name: 'StatsExports', component: load('stats/exports/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: '企业统计' } }
|
||||
]
|
||||
},
|
||||
|
70
frontend/src/views/exports/index.vue
Normal file
70
frontend/src/views/exports/index.vue
Normal file
@ -0,0 +1,70 @@
|
||||
<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="destroyBatch" icon="md-trash" type="primary" v-has="'destroy'">删除</Button>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="search-wrap" v-show="search.show">
|
||||
<ul class="handle-wraper">
|
||||
<li class="handle-item w-250">
|
||||
<Select clearable placeholder="类型" v-model="other.tag">
|
||||
<Option value="Card">客户列表</Option>
|
||||
<Option value="CompanyCount">企业统计</Option>
|
||||
</Select>
|
||||
</li>
|
||||
|
||||
<li class="handle-item w-350">
|
||||
<DatePicker :editable="false" placeholder="请选择时间" placement="bottom-start" type="daterange" v-model.trim="other.time"></DatePicker>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="handle-wraper">
|
||||
<li class="f-r">
|
||||
<div class="handle-item">
|
||||
<Button @click="index(1)" ghost type="primary">立即搜索</Button>
|
||||
</div>
|
||||
<div class="handle-item">
|
||||
<Button @click="resetSearch" ghost type="warning">重置搜索</Button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-list-wrap">
|
||||
<Alert class="page-tips" show-icon>
|
||||
已选
|
||||
<span class="num">{{selection.length}}</span>项
|
||||
<span @click="handleSelectAll(false)" class="clear">清空</span>
|
||||
</Alert>
|
||||
|
||||
<Table :columns="table_titles" :data="list_data?list_data.data:[]" @on-selection-change="selectionChange" ref="table"></Table>
|
||||
</div>
|
||||
|
||||
<div class="page-turn-wrap" v-if="list_data && list_data.data.length">
|
||||
<Page :current="Number(list_data.current_page)" :page-size="Number(list_data.per_page)" :total="Number(list_data.total)" @on-change="index" show-elevator show-total></Page>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./js/index.js"></script>
|
@ -6,7 +6,8 @@ export default {
|
||||
request_param: ''
|
||||
},
|
||||
other: {
|
||||
time: []
|
||||
time: [],
|
||||
tag: null
|
||||
},
|
||||
list_data: null,
|
||||
search: {
|
||||
@ -33,9 +34,12 @@ export default {
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '查询范围',
|
||||
key: 'dateline',
|
||||
width: 300
|
||||
title: '查询条件',
|
||||
key: '',
|
||||
width: 300,
|
||||
render: (h, { row, column, index }) => {
|
||||
return h('pre', row.conditions);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '文件大小',
|
||||
@ -111,7 +115,7 @@ export default {
|
||||
let data = this.searchDataHandle(this.params, { page }, this.other);
|
||||
this.isShowLoading(true);
|
||||
console.log(data);
|
||||
service.get('api/stats/exports', { params: data }).then(res => {
|
||||
service.get('api/exports', { params: data }).then(res => {
|
||||
this.isShowLoading(false);
|
||||
if (res.code == 0) {
|
||||
let result = res.data;
|
||||
@ -156,7 +160,7 @@ export default {
|
||||
title: '提示',
|
||||
content: '确认执行删除操作?',
|
||||
onOk: () => {
|
||||
service.post('api/stats/exports/destroy', data).then(res => {
|
||||
service.post('api/exports/destroy', data).then(res => {
|
||||
if (res.code == 0) {
|
||||
// 当有勾选项,删除操作的地方为每行的按钮,将复选框勾选项去除此id
|
||||
const ids = data.ids.toString().split(',');
|
||||
@ -195,6 +199,7 @@ export default {
|
||||
for (let k in this.params) {
|
||||
this.params[k] = '';
|
||||
}
|
||||
this.other.tag = null;
|
||||
this.other.time = [];
|
||||
this.index(1);
|
||||
},
|
@ -1,41 +1,41 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="header-bar">
|
||||
<div class="collapsed-wrap">
|
||||
<a @click="collapsedChange" type="text">
|
||||
<Icon class="shrink" type="md-menu" size="26" :class="{'collapsed':collapsed}" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="head-other">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
<div class="user-wrap">
|
||||
<Dropdown trigger="click" :transfer="true" @on-click="dropChange">
|
||||
<a href="javascript:void(0)" class="user-name" v-if="account">
|
||||
<template>
|
||||
<span>
|
||||
{{account.username}}
|
||||
<Icon type="md-arrow-dropdown" size="17" />
|
||||
</span>
|
||||
</template>
|
||||
<img class="head-img" :src="account.avatar" @error="imgError($event,default_head)">
|
||||
</a>
|
||||
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem :name="1">修改密码</DropdownItem>
|
||||
<DropdownItem :name="2">个人信息</DropdownItem>
|
||||
<DropdownItem :name="3" divided>安全退出</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
<div>
|
||||
<div class="header-bar">
|
||||
<div class="collapsed-wrap">
|
||||
<a @click="collapsedChange" type="text">
|
||||
<Icon :class="{'collapsed':collapsed}" class="shrink" size="26" type="md-menu"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ui-psw :show.sync="password.show"></ui-psw>
|
||||
<div class="head-other">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
<ui-detail :show.sync="detail.show"></ui-detail>
|
||||
</div>
|
||||
<div class="user-wrap">
|
||||
<Dropdown :transfer="true" @on-click="dropChange" trigger="click">
|
||||
<a class="user-name" href="javascript:void(0)" v-if="account">
|
||||
<template>
|
||||
<span>
|
||||
{{account.username}}
|
||||
<Icon size="17" type="md-arrow-dropdown"/>
|
||||
</span>
|
||||
</template>
|
||||
<img :src="account.avatar" @error="imgError($event,default_head)" class="head-img">
|
||||
</a>
|
||||
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem :name="1">修改密码</DropdownItem>
|
||||
<DropdownItem :name="2">个人信息</DropdownItem>
|
||||
<DropdownItem :name="3" divided>安全退出</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ui-psw :show.sync="password.show"></ui-psw>
|
||||
|
||||
<ui-detail :show.sync="detail.show"></ui-detail>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./js/header_bar.js"></script>
|
||||
|
@ -1,73 +0,0 @@
|
||||
<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 v-has="'destroy'" type="primary" icon="md-trash" @click="destroyBatch">删除</Button>
|
||||
</div>
|
||||
|
||||
<div class="handle-item">
|
||||
<Button type="primary" icon="ios-search" ghost @click="search.show=!search.show">搜索</Button>
|
||||
</div>
|
||||
|
||||
<div class="handle-item">
|
||||
<Button icon="md-refresh" @click="index(1)">刷新</Button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="search-wrap" v-show="search.show">
|
||||
<ul class="handle-wraper">
|
||||
<li class="handle-item w-350">
|
||||
<DatePicker
|
||||
:editable="false"
|
||||
type="daterange"
|
||||
placement="bottom-start"
|
||||
placeholder="请选择时间"
|
||||
v-model.trim="other.time">
|
||||
</DatePicker>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="handle-wraper">
|
||||
<li class="f-r">
|
||||
<div class="handle-item">
|
||||
<Button type="primary" ghost @click="index(1)">立即搜索</Button>
|
||||
</div>
|
||||
<div class="handle-item">
|
||||
<Button type="warning" ghost @click="resetSearch">重置搜索</Button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-list-wrap">
|
||||
<Alert show-icon class="page-tips">
|
||||
已选<span class="num">{{selection.length}}</span>项
|
||||
<span class="clear" @click="handleSelectAll(false)">清空</span>
|
||||
</Alert>
|
||||
|
||||
<Table ref="table" :columns="table_titles" :data="list_data?list_data.data:[]" @on-selection-change="selectionChange"></Table>
|
||||
</div>
|
||||
|
||||
<div class="page-turn-wrap" v-if="list_data && list_data.data.length">
|
||||
<Page
|
||||
show-total
|
||||
show-elevator
|
||||
:current="Number(list_data.current_page)"
|
||||
:total="Number(list_data.total)"
|
||||
:page-size="Number(list_data.per_page)"
|
||||
@on-change="index">
|
||||
</Page>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./js/index.js"></script>
|
67
frontend/src/views/virtual/cards/detail.vue
Normal file
67
frontend/src/views/virtual/cards/detail.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<Drawer :mask-closable="true" @on-visible-change="visibleChange" title="客户详情" v-model="my_show" width="500">
|
||||
<div class="page-detail-wrap" v-if="data">
|
||||
<Divider>基础资料</Divider>
|
||||
<ul>
|
||||
<li class="ui-list">
|
||||
<div class="ui-list-title">客户编号:</div>
|
||||
<div class="ui-list-content">{{data.id}}</div>
|
||||
</li>
|
||||
|
||||
<li class="ui-list">
|
||||
<div class="ui-list-title">SIM:</div>
|
||||
<div class="ui-list-content">{{data.sim}}</div>
|
||||
</li>
|
||||
|
||||
<li class="ui-list">
|
||||
<div class="ui-list-title">IMSI:</div>
|
||||
<div class="ui-list-content">{{data.imsi}}</div>
|
||||
</li>
|
||||
|
||||
<li class="ui-list">
|
||||
<div class="ui-list-title">ICCID:</div>
|
||||
<div class="ui-list-content">{{data.iccid}}</div>
|
||||
</li>
|
||||
|
||||
<li class="ui-list">
|
||||
<div class="ui-list-title">运营商:</div>
|
||||
<div class="ui-list-content">{{data.carrier_operator}}</div>
|
||||
</li>
|
||||
|
||||
<li class="ui-list">
|
||||
<div class="ui-list-title">所属企业:</div>
|
||||
<div class="ui-list-content">{{data.company_name}}</div>
|
||||
</li>
|
||||
|
||||
<li class="ui-list">
|
||||
<div class="ui-list-title">卡状态:</div>
|
||||
<div class="ui-list-content">{{data.status_name}}</div>
|
||||
</li>
|
||||
|
||||
<li class="ui-list">
|
||||
<div class="ui-list-title">创建时间:</div>
|
||||
<div class="ui-list-content">{{data.created_at}}</div>
|
||||
</li>
|
||||
|
||||
<li class="ui-list">
|
||||
<div class="ui-list-title">更新时间:</div>
|
||||
<div class="ui-list-content">{{data.updated_at}}</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<Divider>服务时间段</Divider>
|
||||
<ul v-for="item in data.timelines">
|
||||
<li class="ui-list">
|
||||
<Row>
|
||||
<Col span="8">{{item.name}}</Col>
|
||||
<Col span="8">{{item.type_name}}</Col>
|
||||
<Col span="8">{{item.starttime}} 至 {{item.endtime}}</Col>
|
||||
</Row>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Drawer>
|
||||
</template>
|
||||
|
||||
<script src="./js/detail.js"></script>
|
||||
|
90
frontend/src/views/virtual/cards/index.vue
Normal file
90
frontend/src/views/virtual/cards/index.vue
Normal file
@ -0,0 +1,90 @@
|
||||
<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="openEdit(true, null)" icon="md-add" type="primary" v-has="'create'">添加企业</Button>
|
||||
</div>-->
|
||||
<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="params.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">
|
||||
<DatePicker :editable="false" placeholder="创建时间" placement="bottom-start" type="daterange" v-model.trim="params.time"></DatePicker>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="handle-wraper">
|
||||
<li class="handle-item w-250">
|
||||
<Select clearable placeholder="运营商" v-model="params.carrier_operator">
|
||||
<Option :value="0">联通</Option>
|
||||
<Option :value="1">移动</Option>
|
||||
<Option :value="2">电信</Option>
|
||||
</Select>
|
||||
</li>
|
||||
|
||||
<li class="handle-item w-250">
|
||||
<Input clearable placeholder="客户编号" v-model.trim="params.id"></Input>
|
||||
</li>
|
||||
|
||||
<li class="handle-item w-250">
|
||||
<Input placeholder="SIM" type="textarea" v-model="params.sim"/>
|
||||
</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="table_titles" :data="list_data ? list_data.data : []"></Table>
|
||||
</div>
|
||||
|
||||
<div class="page-turn-wrap" v-if="list_data">
|
||||
<Page :current="Number(list_data.current_page)" :page-size="Number(list_data.per_page)" :total="Number(list_data.total)" @on-change="index" show-elevator show-total></Page>
|
||||
</div>
|
||||
|
||||
<ui-detail :data="detailObj.data" :show.sync="detailObj.show"></ui-detail>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./js/index.js"></script>
|
29
frontend/src/views/virtual/cards/js/detail.js
Normal file
29
frontend/src/views/virtual/cards/js/detail.js
Normal file
@ -0,0 +1,29 @@
|
||||
export default{
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(bool) {
|
||||
this.my_show = bool;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
my_show: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
visibleChange(bool) {
|
||||
this.$emit('update:show', bool);
|
||||
}
|
||||
}
|
||||
};
|
193
frontend/src/views/virtual/cards/js/index.js
Normal file
193
frontend/src/views/virtual/cards/js/index.js
Normal file
@ -0,0 +1,193 @@
|
||||
import * as API from 'api/virtual/cards';
|
||||
|
||||
export default {
|
||||
name: 'Cards',
|
||||
components: {
|
||||
UiDetail: resolve => require(['views/virtual/cards/detail'], resolve)
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
params: {
|
||||
'id': null,
|
||||
'sim': null,
|
||||
'company_name': null,
|
||||
'package_name': null,
|
||||
'carrier_operator': null,
|
||||
'time': []
|
||||
},
|
||||
list_data: null,
|
||||
detailObj: {
|
||||
show: false,
|
||||
data: null
|
||||
},
|
||||
search: {
|
||||
show: false
|
||||
},
|
||||
table_titles: [
|
||||
{
|
||||
title: '客户编号',
|
||||
key: 'id',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: 'SIM',
|
||||
key: 'sim',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '运营商',
|
||||
key: 'carrier_operator',
|
||||
width: 90
|
||||
},
|
||||
{
|
||||
title: '企业名称',
|
||||
key: 'company_name',
|
||||
width: 300
|
||||
},
|
||||
{
|
||||
title: '套餐名称',
|
||||
key: 'package_name',
|
||||
width: 110
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status_name',
|
||||
width: 110
|
||||
},
|
||||
{
|
||||
title: '服务时间',
|
||||
key: '',
|
||||
width: 170,
|
||||
render: (h, { row, column, index }) => {
|
||||
return h('span', row.service_start_at + ' - ' + row.service_end_at);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'created_at',
|
||||
width: 170
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (h, {
|
||||
row,
|
||||
column,
|
||||
index
|
||||
}) => {
|
||||
let html = [];
|
||||
|
||||
if (this.haveJurisdiction('show')) {
|
||||
html.push(h('Button', {
|
||||
props: {
|
||||
type: 'dashed',
|
||||
size: 'small',
|
||||
disabled: false,
|
||||
icon: 'md-eye'
|
||||
},
|
||||
class: ['btn'],
|
||||
on: {
|
||||
click: (event) => {
|
||||
this.detailObj = {
|
||||
show: true,
|
||||
data: row
|
||||
};
|
||||
}
|
||||
}
|
||||
}, '查看'));
|
||||
}
|
||||
|
||||
if (html.length) {
|
||||
return h('div', html);
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.index(1);
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* [index 列表]
|
||||
* @param {Number} page [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
index(page = 1) {
|
||||
let params = Object.assign({
|
||||
orderBy: 'id',
|
||||
sortedBy: 'asc'
|
||||
}, this.params);
|
||||
|
||||
if (this.params.sim) {
|
||||
params.sim = this.params.sim.split(/[\s|,|;]+/);
|
||||
}
|
||||
|
||||
let data = this.searchDataHandle({}, { page }, params);
|
||||
this.isShowLoading(true);
|
||||
API.index(data).then(res => {
|
||||
this.isShowLoading(false);
|
||||
if (res.code == 0) {
|
||||
this.list_data = res.data;
|
||||
}
|
||||
}).catch(() => {
|
||||
this.isShowLoading(false);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* [request 刷新]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
request() {
|
||||
const result = this.list_data;
|
||||
let page = result.current_page;
|
||||
|
||||
if (result && result.data.length == 1) {
|
||||
page = this.returnPage(result.total, result.current_page, result.per_page);
|
||||
}
|
||||
|
||||
this.index(page);
|
||||
},
|
||||
|
||||
resetSearch() {
|
||||
for (let k in this.params) {
|
||||
if (k === 'time') {
|
||||
this.params[k] = [];
|
||||
} else {
|
||||
this.params[k] = null;
|
||||
}
|
||||
}
|
||||
this.index(1);
|
||||
},
|
||||
|
||||
exportExcel() {
|
||||
let params = Object.assign({
|
||||
orderBy: 'id',
|
||||
sortedBy: 'asc'
|
||||
}, this.params);
|
||||
|
||||
if (this.params.sim) {
|
||||
params.sim = this.params.sim.split(/[\s|,|;]+/);
|
||||
}
|
||||
|
||||
let data = this.searchDataHandle({}, { limit: 0 }, params);
|
||||
this.isShowLoading(true);
|
||||
|
||||
API.exportExcel(data).then(res => {
|
||||
this.isShowLoading(false);
|
||||
if (res.url) {
|
||||
this.downloadFile(res.url);
|
||||
} else {
|
||||
this.$Modal.success({
|
||||
title: '提示',
|
||||
content: '当前导出数据量大,已进入后台队列导出模式,请稍后至导出列表查看下载。'
|
||||
});
|
||||
}
|
||||
}).catch(() => {
|
||||
this.isShowLoading(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
2
public/css/chunk-7b30bdf4.a0bc7fe7.css
Normal file
2
public/css/chunk-7b30bdf4.a0bc7fe7.css
Normal file
File diff suppressed because one or more lines are too long
2
public/js/app.42556444.js
Normal file
2
public/js/app.42556444.js
Normal file
File diff suppressed because one or more lines are too long
1
public/js/app.42556444.js.map
Normal file
1
public/js/app.42556444.js.map
Normal file
File diff suppressed because one or more lines are too long
2
public/js/chunk-7b30bdf4.362c903a.js
Normal file
2
public/js/chunk-7b30bdf4.362c903a.js
Normal file
File diff suppressed because one or more lines are too long
1
public/js/chunk-7b30bdf4.362c903a.js.map
Normal file
1
public/js/chunk-7b30bdf4.362c903a.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -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-a0b8384a.2b7901ac.css rel=prefetch><link href=/js/chunk-00ae0766.16700330.js rel=prefetch><link href=/js/chunk-a0b8384a.d3cdc6cf.js rel=prefetch><link href=/css/app.36043160.css rel=preload as=style><link href=/css/chunk-vendors.3c3b2e85.css rel=preload as=style><link href=/js/app.6330bcc5.js rel=preload as=script><link href=/js/chunk-vendors.02a4e5bc.js rel=preload as=script><link href=/css/chunk-vendors.3c3b2e85.css rel=stylesheet><link href=/css/app.36043160.css rel=stylesheet></head><body><noscript><strong>很抱歉,如果没有启用JavaScript,程序不能正常工作,若要继续使用请启用它。</strong></noscript><div id=app></div><script src=/js/chunk-vendors.02a4e5bc.js></script><script src=/js/app.6330bcc5.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-7b30bdf4.a0bc7fe7.css rel=prefetch><link href=/js/chunk-00ae0766.16700330.js rel=prefetch><link href=/js/chunk-7b30bdf4.362c903a.js rel=prefetch><link href=/css/app.36043160.css rel=preload as=style><link href=/css/chunk-vendors.3c3b2e85.css rel=preload as=style><link href=/js/app.42556444.js rel=preload as=script><link href=/js/chunk-vendors.02a4e5bc.js rel=preload as=script><link href=/css/chunk-vendors.3c3b2e85.css rel=stylesheet><link href=/css/app.36043160.css rel=stylesheet></head><body><noscript><strong>很抱歉,如果没有启用JavaScript,程序不能正常工作,若要继续使用请启用它。</strong></noscript><div id=app></div><script src=/js/chunk-vendors.02a4e5bc.js></script><script src=/js/app.42556444.js></script></body></html>
|
Loading…
x
Reference in New Issue
Block a user