一些优化和bug修改

This commit is contained in:
邓皓元 2019-03-25 16:44:41 +08:00
parent 1392e2ee52
commit 93d5a177b3
44 changed files with 427206 additions and 481 deletions

View File

@ -25,6 +25,7 @@ abstract class AbstractExport implements WithEvents, WithTitle, ShouldAutoSize
\App\Domains\Virtual\Exports\FlowPoolExport::class => '流量池列表', \App\Domains\Virtual\Exports\FlowPoolExport::class => '流量池列表',
\App\Domains\Virtual\Exports\FlowPoolExportDetailExport::class => '流量池明细', \App\Domains\Virtual\Exports\FlowPoolExportDetailExport::class => '流量池明细',
\App\Domains\Virtual\Exports\OrderCardExport::class => '订单卡清单', \App\Domains\Virtual\Exports\OrderCardExport::class => '订单卡清单',
\App\Domains\Virtual\Exports\OrderExport::class => '订单导出',
\App\Domains\Stats\Exports\CompanyCountExport::class => '企业统计', \App\Domains\Stats\Exports\CompanyCountExport::class => '企业统计',
\App\Domains\Stats\Exports\OrderExport::class => '订单统计', \App\Domains\Stats\Exports\OrderExport::class => '订单统计',
\App\Domains\Stats\Exports\OrderDetailExport::class => '订单明细', \App\Domains\Stats\Exports\OrderDetailExport::class => '订单明细',

View File

@ -215,3 +215,6 @@ class OrderBaseSync extends Command
return $orderItems; return $orderItems;
} }
} }
echo strtotime('2018-10-01 00:00:00') - strtotime('2018-08-01 00:00:00');

View File

@ -3,6 +3,8 @@
namespace App\Domains\Real\Commands\Sync; namespace App\Domains\Real\Commands\Sync;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Domains\Real\Repositories\OrderCardPartitionRepository;
use App\Domains\Virtual\Repositories\OrderCardPartitionRepository as VirtualOrderCardPartitionRepository;
class RefundSync extends Command class RefundSync extends Command
{ {
@ -26,15 +28,29 @@ class RefundSync extends Command
->where('create_time', '<=', $endtime) ->where('create_time', '<=', $endtime)
->get(); ->get();
$refunds->map(function ($item) { $simArray = [];
$refunds->map(function ($item) use (&$simArray) {
$item->sim = str_to_array($item->sim, ','); $item->sim = str_to_array($item->sim, ',');
$simArray = array_merge($simArray, $item->sim);
}); });
DB::transaction(function () use ($refunds) { DB::transaction(function () use ($refunds) {
foreach ($refunds as $item) { foreach ($refunds as $item) {
DB::table('real_order_cards')->whereIn('sim', $item['sim'])->where('created_at', '<=', $item['create_time'])->delete(); DB::table('real_order_cards')
DB::table('virtual_order_cards')->whereIn('sim', $item['sim'])->where('created_at', '<=', $item['create_time'])->delete(); ->whereIn('sim', $item->sim)
->where('created_at', '<=', $item->create_time)
->update(['refunded_at' => $item->create_time]);
DB::table('virtual_order_cards_partition')
->whereIn('sim', $item->sim)
->where('created_at', '<=', $item->create_time)
->whereNull('service_start_at')
->update(['refunded_at' => $item->create_time]);
} }
}); });
app(OrderCardPartitionRepository::class)->forgetCached();
app(VirtualOrderCardPartitionRepository::class)->forgetCached();
} }
} }

View File

@ -49,6 +49,8 @@ class OrderController extends Controller
'pay_channel_name', 'pay_channel_name',
'counts', 'counts',
'shipments', 'shipments',
'refunds',
'unit_price',
'total_price', 'total_price',
'order_at', 'order_at',
'transaction_no', 'transaction_no',

View File

@ -57,7 +57,8 @@ class OrderCardPartitionRepository extends Repository
real_order_cards_partition.virtual_order_id, real_order_cards_partition.virtual_order_id,
real_order_cards_partition.counts, real_order_cards_partition.counts,
virtual_order_cards_partition.company_id, virtual_order_cards_partition.company_id,
virtual_order_cards_partition.package_id virtual_order_cards_partition.package_id,
real_order_cards_partition.refunded_at
'; ';
$this->model = $this->model->selectRaw($select); $this->model = $this->model->selectRaw($select);

View File

@ -42,7 +42,11 @@ class OrderService extends Service
$res = $this->orderRepository->withConditions($conditions)->applyConditions()->paginate($limit); $res = $this->orderRepository->withConditions($conditions)->applyConditions()->paginate($limit);
if (!$res->isEmpty()) { if (!$res->isEmpty()) {
$cards = $this->orderCardPartitionRepository->selectRaw('order_id,SUM(counts) as counts, SUM(CASE virtual_order_id WHEN 0 THEN 0 ELSE counts END) as shipments') $cards = $this->orderCardPartitionRepository->selectRaw('
order_id,SUM(counts) as counts,
SUM(CASE virtual_order_id WHEN 0 THEN 0 ELSE counts END) as shipments,
SUM(CASE WHEN refunded_at IS NULL THEN 0 ELSE counts END) as refunds
')
->withConditions(['type' => $conditions['type'], 'order_id', $res->pluck('id')->toArray()]) ->withConditions(['type' => $conditions['type'], 'order_id', $res->pluck('id')->toArray()])
->groupBy('order_id')->get()->keyBy('order_id')->toArray(); ->groupBy('order_id')->get()->keyBy('order_id')->toArray();
} }
@ -58,6 +62,7 @@ class OrderService extends Service
$item->total_price = sprintf('%.02f', $item->total_price/100); $item->total_price = sprintf('%.02f', $item->total_price/100);
$item->shipments = $cards[$item->id]['shipments'] ?? 0; $item->shipments = $cards[$item->id]['shipments'] ?? 0;
$item->counts = $cards[$item->id]['counts'] ?? 0; $item->counts = $cards[$item->id]['counts'] ?? 0;
$item->refunds = $cards[$item->id]['refunds'] ?? 0;
}); });
return $res->sortByDesc('order_at')->values(); return $res->sortByDesc('order_at')->values();

View File

@ -57,25 +57,12 @@ class CompanyCountService extends Service
$orderRenewalCard = $this->orderCardPartitionRepository->select($select)->where('type', 1)->withConditions($conditions)->groupBy($groupBy) $orderRenewalCard = $this->orderCardPartitionRepository->select($select)->where('type', 1)->withConditions($conditions)->groupBy($groupBy)
->get()->pluck('counts', 'company_id')->toArray(); ->get()->pluck('counts', 'company_id')->toArray();
// $orderRenewalPackage = $this->orderCardPartitionRepository->select($select)->where('type', 2)->withConditions($conditions)->groupBy($groupBy)
// ->get()->pluck('counts', 'company_id')->toArray();
// $renewed_counts = array_merge_sum($orderRenewalCard, $orderRenewalPackage);
$renewed_counts = $orderRenewalCard; $renewed_counts = $orderRenewalCard;
if ($conditions['starttime'] && $conditions['endtime']) {
$valid_counts = $this->orderCardPartitionRepository->select($select)->where('service_start_at', '>=', $conditions['starttime'])->where('service_end_at', '<=', $conditions['endtime'])
->groupBy($groupBy)->get()->pluck('counts', 'company_id')->toArray();
} else {
$valid_counts = $this->orderCardPartitionRepository->select($select)->whereNotNull('service_start_at')->groupBy($groupBy)->get()->pluck('counts', 'company_id')->toArray();
}
$companies->map(function ($item) use ($total, $counts, $renewed_counts, $valid_counts) { $companies->map(function ($item) use ($total, $counts, $renewed_counts, $valid_counts) {
$item->total = $total[$item['id']] ?? 0; $item->total = $total[$item['id']] ?? 0;
$item->counts = $counts[$item['id']] ?? 0; $item->counts = $counts[$item['id']] ?? 0;
$item->renewed_counts = $renewed_counts[$item['id']] ?? 0; $item->renewed_counts = $renewed_counts[$item['id']] ?? 0;
$item->valid_counts = $valid_counts[$item['id']] ?? 0;
}); });
return $companies; return $companies;

View File

@ -3,17 +3,14 @@
namespace App\Domains\Virtual\Exports; namespace App\Domains\Virtual\Exports;
use App\Core\AbstractExport; use App\Core\AbstractExport;
use Illuminate\Support\Facades\DB;
use Dipper\Excel\Concerns\WithRows; use Dipper\Excel\Concerns\WithRows;
use Dipper\Excel\Concerns\FromQuery; use Dipper\Excel\Concerns\FromQuery;
use Dipper\Excel\Concerns\WithHeadings; use Dipper\Excel\Concerns\WithHeadings;
use Illuminate\Database\Eloquent\Collection;
use App\Domains\Virtual\Services\CardService;
use Dipper\Excel\Concerns\WithColumnFormatting; use Dipper\Excel\Concerns\WithColumnFormatting;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat; use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use App\Domains\Virtual\Repositories\OrderCardPartitionRepository; use App\Domains\Virtual\Repositories\OrderCardPartitionRepository;
class OrderCardExport extends AbstractExport implements FromQuery, WithHeadings, WithColumnFormatting class OrderCardExport extends AbstractExport implements FromQuery, WithHeadings, WithRows, WithColumnFormatting
{ {
public $conditions; public $conditions;
@ -25,7 +22,7 @@ class OrderCardExport extends AbstractExport implements FromQuery, WithHeadings,
public function query() public function query()
{ {
$builder = app(OrderCardPartitionRepository::class)->forceNoReset()->select(['sim', 'counts']) $builder = app(OrderCardPartitionRepository::class)->forceNoReset()->select(['sim', 'counts', 'refunded_at'])
->withConditions($this->conditions)->orderBy('sim'); ->withConditions($this->conditions)->orderBy('sim');
return $builder; return $builder;
@ -36,16 +33,37 @@ class OrderCardExport extends AbstractExport implements FromQuery, WithHeadings,
return [ return [
'SIM', 'SIM',
'数量', '数量',
'退货',
]; ];
} }
/**
* @param mixed $row
*
* @return mixed
*/
public function rows($rows)
{
$array = [];
foreach ($rows as $item) {
$array[] = [
$item['sim'],
$item['counts'],
$item['refunded_at'] ? '是' : '',
];
}
return $array;
}
/** /**
* @return array * @return array
*/ */
public function columnFormats(): array public function columnFormats(): array
{ {
return [ return [
'A' => NumberFormat::FORMAT_NUMBER_00, 'A' => NumberFormat::FORMAT_NUMBER,
'B' => NumberFormat::FORMAT_NUMBER, 'B' => NumberFormat::FORMAT_NUMBER,
]; ];
} }

View File

@ -0,0 +1,114 @@
<?php
namespace App\Domains\Virtual\Exports;
use Carbon\Carbon;
use App\Core\AbstractExport;
use Dipper\Excel\Concerns\WithRows;
use Dipper\Excel\Concerns\FromQuery;
use Dipper\Excel\Concerns\WithHeadings;
use App\Domains\Virtual\Services\CommonService;
use Dipper\Excel\Concerns\WithColumnFormatting;
use App\Domains\Virtual\Services\CompanyService;
use App\Domains\Virtual\Services\PackageService;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use App\Domains\Virtual\Repositories\OrderCardPartitionRepository;
use App\Dicts;
class OrderExport extends AbstractExport implements FromQuery, WithHeadings, WithRows, WithColumnFormatting
{
public $conditions;
public function __construct(array $conditions = [])
{
$this->conditions = $conditions;
parent::__construct();
}
public function query()
{
$builder = app(OrderCardPartitionRepository::class)->with('order')->forceNoReset()->select(['sim', 'order_id', 'counts', 'refunded_at'])
->withConditions($this->conditions)->orderBy('order_id');
return $builder;
}
public function headings(): array
{
$headings = [
'订单编号',
'企业名称',
'运营商',
'套餐名称',
'套餐单价',
'支付方式',
'支付流水号',
'订单时间',
'SIM',
'数量',
'退货',
];
if ($this->conditions['type'] == 0) {
array_splice($headings, 6, 0, [
'订单状态',
'收款状态',
]);
}
return $headings;
}
/**
* @param mixed $row
*
* @return mixed
*/
public function rows($rows)
{
$array = [];
$carrierOperators = app(Dicts::class)->get('carrier_operator');
$orderStatues = app(Dicts::class)->get('order_status');
$transactionStatuses = app(Dicts::class)->get('transaction_status');
foreach ($rows as $item) {
$carrier_operator = PackageService::load($item['order']['package_id'])['carrier_operator'];
$data = [
"{$item['order']['sn']}\t",
CompanyService::load($item['order']['company_id'])['name'] ?? '',
$carrierOperators[$carrier_operator],
PackageService::load($item['order']['package_id'])['name'] ?? '',
sprintf('%.02f', $item['order']['unit_price']/100),
CommonService::namePayChannel($item['order']['pay_channel']),
"{$item['order']['transaction_no']}\t",
Carbon::parse($item['order']['order_at'])->format('Y-m-d'),
"{$item['sim']}\t",
$item['counts'],
$item['refunded_at'] ? '是' : '',
];
if ($this->conditions['type'] == 0) {
array_splice($data, 6, 0, [
$orderStatues[$item['order']['order_status']],
$transactionStatuses[$item['order']['transaction_status']],
]);
}
$array[] = $data;
}
return $array;
}
/**
* @return array
*/
public function columnFormats(): array
{
return [
'E' => NumberFormat::FORMAT_NUMBER_00,
];
}
}

View File

@ -5,6 +5,8 @@ use App\Dicts;
use App\Core\Controller; use App\Core\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Exceptions\NotExistException; use App\Exceptions\NotExistException;
use App\Exceptions\NotAllowedException;
use App\Domains\Virtual\Exports\OrderExport;
use App\Domains\Config\Services\ConfigService; use App\Domains\Config\Services\ConfigService;
use App\Domains\Export\Services\ExportService; use App\Domains\Export\Services\ExportService;
use App\Domains\Virtual\Services\OrderService; use App\Domains\Virtual\Services\OrderService;
@ -13,6 +15,7 @@ use App\Domains\Virtual\Exports\OrderCardExport;
use App\Domains\Virtual\Services\CompanyService; use App\Domains\Virtual\Services\CompanyService;
use App\Domains\Virtual\Services\PackageService; use App\Domains\Virtual\Services\PackageService;
use App\Domains\Virtual\Repositories\OrderRepository; use App\Domains\Virtual\Repositories\OrderRepository;
use App\Domains\Virtual\Repositories\OrderCardPartitionRepository;
class OrderController extends Controller class OrderController extends Controller
{ {
@ -38,32 +41,56 @@ class OrderController extends Controller
$conditions = $this->request->all(); $conditions = $this->request->all();
$conditions['limit'] = $this->request->get('limit', 20); $conditions['limit'] = $this->request->get('limit', 20);
if (isset($conditions['sim'])) {
$conditions['sim'] = array_map('intval', array_map('trim', str_to_array($conditions['sim'], "\n")));
}
$orders = $this->orderService->paginate($conditions); $orders = $this->orderService->paginate($conditions);
$carrierOperators = $dicts->get('carrier_operator'); $carrierOperators = $dicts->get('carrier_operator');
$orderStatues = $dicts->get('order_status'); $orderStatues = $dicts->get('order_status');
$transactionStatuses = $dicts->get('transaction_status'); $transactionStatuses = $dicts->get('transaction_status');
$logistics = app(ConfigService::class)->get('logistics');
$orders->transform(function ($item) use ($carrierOperators, $orderStatues, $transactionStatuses) { $orders->transform(function ($item) use ($carrierOperators, $orderStatues, $transactionStatuses, $logistics) {
return collect([ return collect([
'id' => $item->id, 'id' => $item->id,
'sn' => $item->sn, 'sn' => $item->sn,
'transaction_no' => $item->transaction_no, 'transaction_no' => $item->transaction_no,
'package_id' => $item->package_id,
'package_name' => $item->package->name, 'package_name' => $item->package->name,
'company_id' => $item->company_id,
'company_name' => $item->company->name, 'company_name' => $item->company->name,
'pay_channel' => CommonService::namePayChannel($item->pay_channel), 'pay_channel' => $item->pay_channel,
'carrier_operator' => $carrierOperators[$item->package->carrier_operator], 'pay_channel_name' => CommonService::namePayChannel($item->pay_channel),
'carrier_operator' => $item->package->carrier_operator,
'carrier_operator_name' => $carrierOperators[$item->package->carrier_operator],
'unit_price' => $item->unit_price, 'unit_price' => $item->unit_price,
'counts' => $item->counts, 'counts' => $item->counts,
'total_price' => $item->total_price, 'total_price' => $item->total_price,
'custom_price' => $item->custom_price, 'custom_price' => $item->custom_price,
'shipments' => $item->shipments, 'shipments' => $item->shipments,
'refunds' => $item->refunds,
'order_status' => $item->order_status, 'order_status' => $item->order_status,
'order_status_name' => $orderStatues[$item->order_status], 'order_status_name' => $orderStatues[$item->order_status],
'transaction_status' => $item->transaction_status, 'transaction_status' => $item->transaction_status,
'transaction_status_name' => $transactionStatuses[$item->transaction_status], 'transaction_status_name' => $transactionStatuses[$item->transaction_status],
'remark' => $item->remark ?? '',
'order_at' => (string) $item->order_at, 'order_at' => (string) $item->order_at,
'deleted_at' => (string) $item->deleted_at, 'deleted_at' => (string) $item->deleted_at,
'area' => $item->area ?? [],
'address' => $item->address ?? '',
'contacts' => $item->contacts,
'mobile' => $item->mobile,
'logistics_remark' => $item->logistics_remark ?? '',
'logistics_company_name' => $logistics[$item->logistics_company] ?? '',
'logistics_no' => $item->logistics_no,
'extends' => [
'cancel_remark' => $item->extends['cancel_remark'] ?? '',
'refund_channel' => $item->extends['refund_channel'] ?? '',
'refund_account' => $item->extends['refund_account'] ?? '',
'refund_remark' => $item->extends['refund_remark'] ?? '',
],
]); ]);
}); });
@ -168,6 +195,37 @@ class OrderController extends Controller
return res(true, '重置成功'); return res(true, '重置成功');
} }
/**
* 导出订单.
*
* @return \Illuminate\Http\Response
*/
public function export()
{
$conditions = $this->request->all();
if (isset($conditions['sim'])) {
$conditions['sim'] = array_map('intval', array_map('trim', str_to_array($conditions['sim'], "\n")));
}
try {
$total = app(OrderCardPartitionRepository::class)->withConditions($conditions)->count();
if ($total > 200000) {
throw new NotAllowedException('数据量过大,请筛选后再进行导出');
}
$queue = $total > 30000;
$export = new OrderExport($conditions);
$url = ExportService::store($export, 'public', $queue);
} catch (\Exception $e) {
throw $e;
}
return res($url, '导出成功', 201);
}
/** /**
* 卡清单. * 卡清单.
* *

View File

@ -107,6 +107,18 @@ trait OrderCardConcern
// $conditions['month'] = (int)Carbon::parse($conditions['month'])->format('Ym'); // $conditions['month'] = (int)Carbon::parse($conditions['month'])->format('Ym');
// $query->whereRaw("timelines_index(id, sim) @> '{{$conditions['month']}}'"); // $query->whereRaw("timelines_index(id, sim) @> '{{$conditions['month']}}'");
} }
if (isset($conditions['sn'])) {
$query->whereHas('order', function ($relation) use ($conditions) {
$relation->where('sn', 'like', "%{$conditions['sn']}%");
});
}
if (isset($conditions['transaction_no'])) {
$query->whereHas('order', function ($relation) use ($conditions) {
$relation->where('transaction_no', 'like', "%{$conditions['transaction_no']}%");
});
}
}); });
return $this; return $this;

View File

@ -77,7 +77,11 @@ class OrderRepository extends Repository
} }
if (!empty($conditions['sn'])) { if (!empty($conditions['sn'])) {
$query->where('sn', "%{$conditions['sn']}%"); $query->where('sn', 'like', "%{$conditions['sn']}%");
}
if (!empty($conditions['transaction_no'])) {
$query->where('transaction_no', 'like', "%{$conditions['transaction_no']}%");
} }
if (isset($conditions['order_status'])) { if (isset($conditions['order_status'])) {
@ -110,6 +114,14 @@ class OrderRepository extends Repository
}); });
} }
if (isset($conditions['sim'])) {
$conditions['sim'] = array_wrap($conditions['sim']);
$query->whereHas('cards', function ($relation) use ($conditions) {
$relation->whereIn('sim', $conditions['sim']);
});
}
if (isset($conditions['starttime'])) { if (isset($conditions['starttime'])) {
$query->where('order_at', '>=', Carbon::parse($conditions['starttime'])); $query->where('order_at', '>=', Carbon::parse($conditions['starttime']));
} }

View File

@ -49,6 +49,7 @@ $router->group(['prefix' => 'virtual', 'as' => 'virtual', 'middleware' => ['admi
$router->post('/orders/update/{id}', ['as' => 'orders.update', 'uses' => 'OrderController@update']); $router->post('/orders/update/{id}', ['as' => 'orders.update', 'uses' => 'OrderController@update']);
$router->post('/orders/destroy', ['as' => 'orders.destroy', 'uses' => 'OrderController@destroy']); $router->post('/orders/destroy', ['as' => 'orders.destroy', 'uses' => 'OrderController@destroy']);
$router->post('/orders/reset', ['as' => 'orders.reset', 'uses' => 'OrderController@reset']); $router->post('/orders/reset', ['as' => 'orders.reset', 'uses' => 'OrderController@reset']);
$router->get('/orders/export', ['as' => 'orders.export', 'uses' => 'OrderController@export']);
$router->get('/orders/cards', ['as' => 'orders.cards', 'uses' => 'OrderController@cards']); $router->get('/orders/cards', ['as' => 'orders.cards', 'uses' => 'OrderController@cards']);
$router->get('/orders/cards-export', ['as' => 'orders.cardsExport', 'uses' => 'OrderController@cardsExport']); $router->get('/orders/cards-export', ['as' => 'orders.cardsExport', 'uses' => 'OrderController@cardsExport']);

View File

@ -61,7 +61,10 @@ class OrderService extends Service
$orderShipments = $this->orderCardPartitionRepository->select([ $orderShipments = $this->orderCardPartitionRepository->select([
'order_id', 'order_id',
DB::raw('SUM(counts) as counts'), DB::raw('SUM(counts) as counts'),
])->withConditions($conditions)->groupBy('order_id')->get()->keyBy('order_id'); DB::raw('SUM(CASE WHEN refunded_at IS NULL THEN 0 ELSE 1 END) as refunds')
])->withConditions([
'order_id' => $res->pluck('id')->toArray(),
])->groupBy('order_id')->get()->keyBy('order_id');
$res->map(function ($item) use ($orderShipments) { $res->map(function ($item) use ($orderShipments) {
$item->company = CompanyService::load($item->company_id); $item->company = CompanyService::load($item->company_id);
@ -70,6 +73,7 @@ class OrderService extends Service
$item->total_price = sprintf('%.02f', $item->total_price/100); $item->total_price = sprintf('%.02f', $item->total_price/100);
$item->custom_price = sprintf('%.02f', $item->custom_price/100); $item->custom_price = sprintf('%.02f', $item->custom_price/100);
$item->shipments = $orderShipments[$item->id]['counts'] ?? 0; $item->shipments = $orderShipments[$item->id]['counts'] ?? 0;
$item->refunds = $orderShipments[$item->id]['refunds'] ?? 0;
}); });
return $res; return $res;
@ -134,12 +138,15 @@ class OrderService extends Service
'address.required' => '请选择收货地址', 'address.required' => '请选择收货地址',
]; ];
if (isset($attributes['unit_price'])) {
$attributes['unit_price'] = intval($attributes['unit_price'] * 100);
}
if (!$attributes['id']) { if (!$attributes['id']) {
$attributes['sn'] = $attributes['sn'] ?: $this->generateSn(); $attributes['sn'] = $attributes['sn'] ?: $this->generateSn();
$attributes['transaction_no'] = $attributes['transaction_no'] ?: $this->generateTransactionNo($attributes['pay_channel']); $attributes['transaction_no'] = $attributes['transaction_no'] ?: $this->generateTransactionNo($attributes['pay_channel']);
if ($attributes['company_id'] && $attributes['package_id'] && isset($attributes['unit_price'])) { if ($attributes['company_id'] && $attributes['package_id'] && isset($attributes['unit_price'])) {
$attributes['unit_price'] = intval($attributes['unit_price'] * 100);
$product = ProductService::getProduct($attributes['company_id'], $attributes['package_id'], $attributes['unit_price']); $product = ProductService::getProduct($attributes['company_id'], $attributes['package_id'], $attributes['unit_price']);
} elseif ($attributes['product_id']) { } elseif ($attributes['product_id']) {
$product = app(ProductRepository::class)->find($attributes['product_id']); $product = app(ProductRepository::class)->find($attributes['product_id']);
@ -185,7 +192,7 @@ class OrderService extends Service
return ['sim' => $item['sim'], 'virtual_activated_at' => $attributes['order_at']]; return ['sim' => $item['sim'], 'virtual_activated_at' => $attributes['order_at']];
}, $attributes['selected']); }, $attributes['selected']);
Card::upsert($array, ['sim', 'deleted'], ['virtual_activated_at']); Card::upsert($array, 'sim', ['virtual_activated_at']);
$attributes['type'] = 0; $attributes['type'] = 0;
$originType = $attributes['type']; $originType = $attributes['type'];
@ -208,7 +215,20 @@ class OrderService extends Service
$attributes['selected'] = $selected; $attributes['selected'] = $selected;
} }
if (!$attributes['id']) { if ($attributes['id']) {
if (!$node = $this->orderRepository->find($attributes['id'])) {
throw new NotExistException('订单不存在或已删除');
}
if (!empty($attributes['extends']) && is_array($attributes['extends'])) {
$attributes['extends'] = array_merge($node->extends ?: [], $attributes['extends']);
}
$this->orderRepository->setModel($node)->update($attributes);
} else {
$maxId = Order::withTrashed()->max('id');
$attributes['id'] = ++$maxId;
if ($product->company_id != $attributes['company_id']) { if ($product->company_id != $attributes['company_id']) {
throw new NotAllowedException('非法操作'); throw new NotAllowedException('非法操作');
} }
@ -222,18 +242,6 @@ class OrderService extends Service
$node = $this->orderRepository->create($attributes); $node = $this->orderRepository->create($attributes);
} }
if ($attributes['id']) {
if (!$node = $this->orderRepository->find($attributes['id'])) {
throw new NotExistException('订单不存在或已删除');
}
if (!empty($attributes['extends']) && is_array($attributes['extends'])) {
$attributes['extends'] = array_merge($node->extends ?: [], $attributes['extends']);
}
$this->orderRepository->setModel($node)->update($attributes);
}
if ($attributes['selected']) { if ($attributes['selected']) {
try { try {
$this->upsertOrderCards($attributes['selected'], $node); $this->upsertOrderCards($attributes['selected'], $node);
@ -552,6 +560,16 @@ class OrderService extends Service
} }
if ($node->type === 0) { if ($node->type === 0) {
$sql = 'SELECT COUNT(*) as counts FROM virtual_order_cards_partition WHERE type != 0 AND sim In (
SELECT sim FROM virtual_order_cards_partition WHERE order_id = ?
)';
$counts = DB::select($sql, [$id])[0]->counts;
if ($counts) {
throw new NotAllowedException('订单中的卡已存在于其他类型订单中,不能进行重置');
}
// 转销售重置 // 转销售重置
$sql = 'UPDATE virtual_order_cards_partition SET sim=original_sim,original_sim=0 $sql = 'UPDATE virtual_order_cards_partition SET sim=original_sim,original_sim=0
WHERE original_sim IN ( WHERE original_sim IN (
@ -655,7 +673,7 @@ class OrderService extends Service
{ {
$conditions['limit'] = $conditions['limit'] ?? 20; $conditions['limit'] = $conditions['limit'] ?? 20;
$cards = $this->orderCardPartitionRepository->select(['sim', 'counts']) $cards = $this->orderCardPartitionRepository->withRefunded()->select(['sim', 'counts', 'refunded_at'])
->withConditions($conditions)->orderBy('sim') ->withConditions($conditions)->orderBy('sim')
->paginate($conditions['limit']); ->paginate($conditions['limit']);

View File

@ -129,6 +129,6 @@ class Order extends Model
public function cards() public function cards()
{ {
return $this->belongsToMany(Card::class, 'virtual_order_cards', 'sim', 'sim'); return $this->hasMany(OrderCardPartition::class, 'order_id', 'id');
} }
} }

View File

@ -5,6 +5,7 @@ namespace App\Models\Virtual;
use App\Core\Model; use App\Core\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\Virtual\Relations\OrderRelations; use App\Models\Virtual\Relations\OrderRelations;
use App\Models\Virtual\Scopes\OrderCardPartitionNotRefundedScope;
/** /**
* App\Models\Virtual\OrderCardPartition * App\Models\Virtual\OrderCardPartition
@ -56,4 +57,16 @@ class OrderCardPartition extends Model
use SoftDeletes, OrderRelations; use SoftDeletes, OrderRelations;
protected $table = 'virtual_order_cards_partition'; protected $table = 'virtual_order_cards_partition';
/**
* 模型的「启动」方法
*
* @return void
*/
protected static function boot()
{
parent::boot();
static::addGlobalScope(new OrderCardPartitionNotRefundedScope);
}
} }

View File

@ -0,0 +1,43 @@
<?php
namespace App\Models\Virtual\Scopes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Builder;
class OrderCardPartitionNotRefundedScope implements Scope
{
/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function apply(Builder $builder, Model $model)
{
$builder->whereNull('refunded_at');
}
/**
* Extend the query builder with the needed functions.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function extend(Builder $builder)
{
$builder->macro('refunded', function (Builder $builder) {
return $builder->withoutGlobalScope($this)->whereNotNull('refunded_at');
});
$builder->macro('withRefunded', function (Builder $builder, $withRefunded = true) {
if (! $withRefunded) {
return $builder->withoutRefunded();
}
return $builder->withoutGlobalScope($this);
});
}
}

View File

@ -27,7 +27,7 @@ class CreateRealOrderCardsTable extends Migration
$table->integer('counts')->unsigned()->default(0)->comment('数量'); $table->integer('counts')->unsigned()->default(0)->comment('数量');
$table->integer('unit_price')->unsigned()->default(0)->comment('单价'); $table->integer('unit_price')->unsigned()->default(0)->comment('单价');
$table->integer('virtual_order_id')->unsigned()->default(0)->comment('VD 订单ID'); $table->integer('virtual_order_id')->unsigned()->default(0)->comment('VD 订单ID');
$table->tinyInteger('refunded')->unsigned()->default(0)->comment('退货标志 0:未退货 1:已退货'); $table->timestamp('refunded_at')->nullable()->comment('退货时间');
$table->timestamps(); $table->timestamps();
$table->softDeletes(); $table->softDeletes();

View File

@ -35,7 +35,7 @@ class CreateVirtualOrderCardsTables extends Migration
$table->timestamp('service_start_at')->nullable()->comment('服务开始时间'); $table->timestamp('service_start_at')->nullable()->comment('服务开始时间');
$table->timestamp('service_end_at')->nullable()->comment('服务结束时间'); $table->timestamp('service_end_at')->nullable()->comment('服务结束时间');
$table->bigInteger('original_sim')->unsigned()->default(0)->comment('原始sim号'); $table->bigInteger('original_sim')->unsigned()->default(0)->comment('原始sim号');
$table->tinyInteger('refunded')->unsigned()->default(0)->comment('退货标志 0:未退货 1:已退货'); $table->timestamp('refunded_at')->nullable()->comment('退货时间');
$table->timestamps(); $table->timestamps();
$table->softDeletes(); $table->softDeletes();

View File

@ -167,12 +167,14 @@ BEGIN
OVERLAY(cards.sim::TEXT PLACING (4 + t.counts)::TEXT FROM 4 FOR 1)::INT8 as sim, OVERLAY(cards.sim::TEXT PLACING (4 + t.counts)::TEXT FROM 4 FOR 1)::INT8 as sim,
OVERLAY(imsi::TEXT PLACING (1 + t.counts)::TEXT FROM 3 FOR 1) as imsi, OVERLAY(imsi::TEXT PLACING (1 + t.counts)::TEXT FROM 3 FOR 1) as imsi,
OVERLAY(iccid::TEXT PLACING (1 + t.counts)::TEXT FROM 5 FOR 1) as iccid, OVERLAY(iccid::TEXT PLACING (1 + t.counts)::TEXT FROM 5 FOR 1) as iccid,
carrier_operator, activated_at, virtual_activated_at, type, real_company_id, cancelled_at, created_at, updated_at carrier_operator, activated_at, virtual_activated_at, 1 as type, cancelled_at, created_at, updated_at
FROM cards JOIN ( FROM cards JOIN (
SELECT OVERLAY(sim::TEXT PLACING $1 FROM 4 FOR 1), COUNT ( * ) AS counts, MIN ( sim ) AS sim FROM cards WHERE sim::TEXT SIMILAR TO $2 GROUP BY 1 SELECT OVERLAY(sim::TEXT PLACING $1 FROM 4 FOR 1), COUNT ( * ) AS counts, MIN ( sim ) AS sim FROM cards WHERE sim::TEXT SIMILAR TO $2 GROUP BY 1
) AS t ON t.sim = cards.sim ) AS t ON t.sim = cards.sim
), new_inserts AS ( ), new_inserts AS (
INSERT INTO cards SELECT sim,imsi,iccid, carrier_operator, activated_at, virtual_activated_at, type, real_company_id, cancelled_at, created_at, updated_at FROM new_cards INSERT INTO cards
(sim,imsi,iccid, carrier_operator, activated_at, virtual_activated_at, type, cancelled_at, created_at, updated_at)
SELECT sim,imsi,iccid, carrier_operator, activated_at, virtual_activated_at, type, cancelled_at, created_at, updated_at FROM new_cards
) )
UPDATE virtual_order_cards_partition SET original_sim=t.original_sim,sim=t.sim FROM (SELECT sim,original_sim FROM new_cards) as t UPDATE virtual_order_cards_partition SET original_sim=t.original_sim,sim=t.sim FROM (SELECT sim,original_sim FROM new_cards) as t
WHERE virtual_order_cards_partition.sim=t.original_sim'; WHERE virtual_order_cards_partition.sim=t.original_sim';

View File

@ -13,6 +13,17 @@ export function index(data) {
}); });
} }
/**
* [exportOrders 订单列表]
* @param {[type]} data [description]
* @return {[type]} [description]
*/
export function exportOrders(data) {
return service.get('api/virtual/orders/export', {
params: data
});
}
/** /**
* [show 订单详情] * [show 订单详情]
* @param {[type]} id [description] * @param {[type]} id [description]

View File

@ -1057,6 +1057,7 @@ export default {
}, 1800); }, 1800);
}, },
clear() { clear() {
this.scrollTop = 0;
this.currentIndex = -1; this.currentIndex = -1;
this.placeholderHeight = 0; this.placeholderHeight = 0;
this.topPlaceholderHeight = 0; this.topPlaceholderHeight = 0;
@ -1161,6 +1162,7 @@ export default {
watch: { watch: {
data: { data: {
handler() { handler() {
this.clear();
const oldDataLen = this.rebuildData.length; const oldDataLen = this.rebuildData.length;
this.objData = this.makeObjData(); this.objData = this.makeObjData();
this.rebuildData = this.makeDataWithSortAndFilter(); this.rebuildData = this.makeDataWithSortAndFilter();

View File

@ -20,6 +20,8 @@ export default {
return array; return array;
} }
console.log(array);
const pinyinEngine = new PinyinEngine(array, [key]); const pinyinEngine = new PinyinEngine(array, [key]);
let res = []; let res = [];

View File

@ -48,7 +48,7 @@ const getters = {
}, 0); }, 0);
}, },
getFilterUsedCards: () => (cards) => { getFilterUsedCards: () => (cards) => {
return cards.filter(item => item.virtual_order_id === 0); return cards.filter(item => item.virtual_order_id === 0 && !item.refunded_at);
}, },
getSelectedByOrderId: (state) => (order_id) => { getSelectedByOrderId: (state) => (order_id) => {
if (typeof order_id !== 'object') { if (typeof order_id !== 'object') {

View File

@ -11,15 +11,17 @@
<ui-loading :show="page_loading.show"></ui-loading> <ui-loading :show="page_loading.show"></ui-loading>
<Steps :current="current" :status="status"> <Steps :current="current" :status="status">
<Step <Step v-for="(item, index) in steps" :key="index" :title="item.title">
:title="item.title" <div class="ivu-steps-content" @click="changeStep(index)">{{item.content}}</div>
:content="item.content" </Step>
v-for="(item, index) in steps"
:key="index"
></Step>
</Steps> </Steps>
<Row type="flex" justify="center" class="umar-t15" v-if="steps[current] && steps[current]['datePicker']"> <Row
type="flex"
justify="center"
class="umar-t15"
v-if="steps[current] && steps[current]['datePicker']"
>
<DatePicker <DatePicker
:editable="false" :editable="false"
placeholder="请选择时间" placeholder="请选择时间"

View File

@ -14,6 +14,10 @@
<Button @click="openEdit(true)" icon="md-add" type="primary">执行同步</Button> <Button @click="openEdit(true)" icon="md-add" type="primary">执行同步</Button>
</div> </div>
<div class="handle-item">
<Button @click="openRefund(true)" icon="md-arrow-dropleft" type="primary">退货同步</Button>
</div>
<div class="handle-item"> <div class="handle-item">
<Button @click="search.show=!search.show" ghost icon="ios-search" type="primary">搜索</Button> <Button @click="search.show=!search.show" ghost icon="ios-search" type="primary">搜索</Button>
</div> </div>
@ -28,7 +32,7 @@
<ul class="handle-wraper"> <ul class="handle-wraper">
<li class="handle-item w-250"> <li class="handle-item w-250">
<Select clearable placeholder="命令类型" v-model="options.command"> <Select clearable placeholder="命令类型" v-model="options.command">
<Option :value="index" v-for="(name, index) in commands" :key="index">{{name}}</Option> <Option :value="index" v-for="(name, index) in commands" :key="index">{{name}}</Option>
</Select> </Select>
</li> </li>
@ -70,12 +74,16 @@
</div> </div>
<ui-edit <ui-edit
:data="editObj.data"
:isUpdate.sync="editObj.isUpdate"
:show.sync="editObj.show" :show.sync="editObj.show"
@add-success="index" @add-success="index"
@update-success="index(list_data.current_page)" @update-success="index(list_data.current_page)"
></ui-edit> ></ui-edit>
<ui-refund
:show.sync="refundObj.show"
@add-success="index"
@update-success="index(list_data.current_page)"
></ui-refund>
</div> </div>
</template> </template>

View File

@ -61,7 +61,7 @@ export default {
content: '未开始' content: '未开始'
}, },
status: 'wait', status: 'wait',
month: this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM') month: this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM')
}; };
}, },
methods: { methods: {
@ -123,7 +123,9 @@ export default {
clearInterval(interval); clearInterval(interval);
}); });
}, },
changeStep(value) {
this.current = value;
},
visibleChange(bool) { visibleChange(bool) {
if (!bool) { if (!bool) {
this.$emit('update:show', false); this.$emit('update:show', false);

View File

@ -1,7 +1,8 @@
export default { export default {
name: 'RealSync', name: 'RealSync',
components: { components: {
UiEdit: resolve => require(['views/artisan/real-sync/edit'], resolve) UiEdit: resolve => require(['views/artisan/real-sync/edit'], resolve),
UiRefund: resolve => require(['views/artisan/real-sync/refund'], resolve)
}, },
data() { data() {
return { return {
@ -10,7 +11,8 @@ export default {
'real:sync-company': '同步RD企业数据', 'real:sync-company': '同步RD企业数据',
'real:sync-mongo': '同步卡基础信息数据', 'real:sync-mongo': '同步卡基础信息数据',
'real:sync-order': '同步RD基础订单数据', 'real:sync-order': '同步RD基础订单数据',
'real:sync-package': '同步RD套餐数据' 'real:sync-package': '同步RD套餐数据',
'real:sync-refund': '同步RD退货数据'
}, },
options: { options: {
command: null, command: null,
@ -18,8 +20,10 @@ export default {
}, },
list_data: null, list_data: null,
editObj: { editObj: {
show: false, show: false
data: null },
refundObj: {
show: false
}, },
search: { search: {
show: false show: false
@ -87,6 +91,16 @@ export default {
}; };
}, },
/**
* [openRefund 打开编辑弹窗]
* @return {[type]} [description]
*/
openRefund(bool) {
this.refundObj = {
show: bool
};
},
/** /**
* [request 刷新] * [request 刷新]
* @return {[type]} [description] * @return {[type]} [description]

View File

@ -0,0 +1,115 @@
export default {
props: {
show: {
type: Boolean,
default: false
}
},
watch: {
show(bool) {
this.my_show = bool;
if (bool) {
this.current = 0;
this.status = 'wait';
this.circle.percent = 0;
this.circle.content = '未开始';
}
}
},
data() {
return {
my_show: false,
loading: false,
disabled: false,
steps: [
{
'title': '同步退货',
'content': '指定月份的退货数据',
'command': 'real:sync-refund',
'max': 100,
'datePicker': true
}
],
current: 0,
circle: {
percent: 0,
content: '未开始'
},
status: 'wait',
month: this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM')
};
},
methods: {
call() {
if (!this.steps[this.current]) {
return;
}
this.disabled = true;
let params = {};
params.command = this.steps[this.current]['command'];
if (!params.command) {
return this.$Message.error('命令错误');
}
if (this.steps[this.current]['datePicker']) {
if (!this.month) {
return this.$Message.error('请选择要同步的月份');
}
params.parameters = {
month: this.moment(this.month).format('YYYY-MM')
};
}
let max = this.steps[this.current]['max'];
this.status = 'process';
this.circle.content = '正在' + this.steps[this.current]['title'];
let interval = setInterval(() => {
if (this.circle.percent < max) {
this.circle.percent++;
}
}, 1000);
service.post('/api/artisan/call', params).then(res => {
if (res.code == 0) {
this.circle.content = this.steps[this.current]['title'] + '完成';
this.circle.percent = max;
this.status = (max == 100) ? 'finish' : 'wait';
this.current++;
} else {
this.circle.content = '同步失败';
this.circle.percent = this.steps[this.current - 1] ? this.steps[this.current - 1]['max'] : 0;
this.status = 'error';
}
this.disabled = false;
clearInterval(interval);
}).catch((err) => {
this.circle.content = '同步失败';
this.circle.percent = this.steps[this.current - 1]['max'];
this.status = 'error';
this.disabled = false;
clearInterval(interval);
});
},
changeStep(value) {
this.current = value + 1;
},
visibleChange(bool) {
if (!bool) {
this.$emit('update:show', false);
}
},
clear() {
this.my_show = false;
}
}
};

View File

@ -0,0 +1,64 @@
<template>
<Modal
:closable="false"
:mask-closable="false"
:title="'RD数据同步'"
@on-visible-change="visibleChange"
v-model="my_show"
:width="1200"
>
<div class="page-edit-wrap uinn-lr20">
<ui-loading :show="page_loading.show"></ui-loading>
<Steps :current="current" :status="status">
<Step
:title="item.title"
:content="item.content"
v-for="(item, index) in steps"
:key="index"
></Step>
</Steps>
<Row type="flex" justify="center" class="umar-t15" v-if="steps[current] && steps[current]['datePicker']">
<DatePicker
:editable="false"
placeholder="请选择时间"
placement="bottom-start"
type="month"
v-model.trim="month"
></DatePicker>
</Row>
<Row type="flex" justify="center" class="umar-t15">
<Circle :size="250" :percent="circle.percent" stroke-linecap="square">
<div class="circle-text">
<h1>{{circle.percent}}%</h1>
<br>
<p>{{circle.content}}</p>
</div>
</Circle>
</Row>
</div>
<footer class="ta-c" slot="footer">
<Button @click="clear" class="w-80" ghost type="primary" :disabled="disabled">取消</Button>
<Button
:loading="loading"
@click="call"
class="w-80"
type="primary"
v-if="this.status === 'wait'"
:disabled="disabled"
>{{ current ? '下一步' : '开始同步'}}</Button>
<Button
:loading="loading"
@click="clear"
class="w-80"
type="primary"
v-if="this.status === 'finish'"
>完成</Button>
</footer>
</Modal>
</template>
<script src="./js/refund.js"></script>

View File

@ -61,7 +61,6 @@
<th><div class="ivu-table-cell">{{stats.total}}</div></th> <th><div class="ivu-table-cell">{{stats.total}}</div></th>
<th><div class="ivu-table-cell">{{stats.counts}}</div></th> <th><div class="ivu-table-cell">{{stats.counts}}</div></th>
<th><div class="ivu-table-cell">{{stats.renewed_counts}}</div></th> <th><div class="ivu-table-cell">{{stats.renewed_counts}}</div></th>
<th><div class="ivu-table-cell">{{stats.valid_counts}}</div></th>
<th v-if="page.limit > 12" rowspan="1"></th> <th v-if="page.limit > 12" rowspan="1"></th>
</tr> </tr>
</thead> </thead>

View File

@ -4,11 +4,14 @@ export default {
data() { data() {
return { return {
search: { search: {
show: false show: true
}, },
options: { options: {
name: '', name: '',
time: '' time: [
this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM-DD'),
this.moment().subtract('1', 'months').endOf('month').format('YYYY-MM-DD')
]
}, },
data: [], data: [],
list: [], list: [],
@ -42,11 +45,6 @@ export default {
title: '续费用户数', title: '续费用户数',
key: 'renewed_counts', key: 'renewed_counts',
width: 120 width: 120
},
{
title: '服务期内用户数',
key: 'valid_counts',
width: 200
} }
] ]
}; };
@ -104,7 +102,11 @@ export default {
resetSearch() { resetSearch() {
for (let k in this.options) { for (let k in this.options) {
this.options[k] = ''; if (k === 'month') {
this.options[k] = this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM');
} else {
this.options[k] = '';
}
} }
this.index(); this.index();
@ -120,8 +122,7 @@ export default {
this.stats = { this.stats = {
total: sumBy(this.list, 'total'), total: sumBy(this.list, 'total'),
counts: sumBy(this.list, 'counts'), counts: sumBy(this.list, 'counts'),
renewed_counts: sumBy(this.list, 'renewed_counts'), renewed_counts: sumBy(this.list, 'renewed_counts')
valid_counts: sumBy(this.list, 'valid_counts')
}; };
this.$nextTick(() => { this.$nextTick(() => {

View File

@ -20,7 +20,7 @@ export default {
company_name: '', company_name: '',
package_name: '', package_name: '',
type: [], type: [],
month: this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM') month: this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM')
}, },
data: [], data: [],
list: [], list: [],
@ -185,7 +185,7 @@ export default {
}, },
params() { params() {
if (!this.options.month) { if (!this.options.month) {
this.options.month = this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM'); this.options.month = this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM');
} }
if (!this.options.type.length) { if (!this.options.type.length) {
@ -223,7 +223,7 @@ export default {
resetSearch() { resetSearch() {
for (let k in this.options) { for (let k in this.options) {
if (k === 'month') { if (k === 'month') {
this.options[k] = this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM'); this.options[k] = this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM');
} else if (k === 'type') { } else if (k === 'type') {
this.options[k] = []; this.options[k] = [];
} else { } else {

View File

@ -20,8 +20,8 @@ export default {
package_name: '', package_name: '',
pay_channel: '', pay_channel: '',
time: [ time: [
this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM-DD'), this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM-DD'),
this.moment().subtract('2', 'months').endOf('month').format('YYYY-MM-DD') this.moment().subtract('1', 'months').endOf('month').format('YYYY-MM-DD')
] ]
}, },
data: [], data: [],
@ -187,8 +187,8 @@ export default {
for (let k in this.options) { for (let k in this.options) {
if (k === 'time') { if (k === 'time') {
this.options[k] = [ this.options[k] = [
this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM-DD'), this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM-DD'),
this.moment().subtract('2', 'months').endOf('month').format('YYYY-MM-DD') this.moment().subtract('1', 'months').endOf('month').format('YYYY-MM-DD')
]; ];
} else { } else {
this.options[k] = ''; this.options[k] = '';

View File

@ -13,7 +13,7 @@ export default {
company_name: '', company_name: '',
name: '', name: '',
carrier_operator: '', carrier_operator: '',
month: this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM') month: this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM')
}, },
list_data: null, list_data: null,
reals: [], reals: [],
@ -294,7 +294,7 @@ export default {
params() { params() {
if (!this.options.month) { if (!this.options.month) {
this.options.month = this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM'); this.options.month = this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM');
} }
let params = { let params = {
@ -360,7 +360,7 @@ export default {
resetSearch() { resetSearch() {
for (let k in this.options) { for (let k in this.options) {
if (k === 'month') { if (k === 'month') {
this.options[k] = this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM'); this.options[k] = this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM');
} else { } else {
this.options[k] = ''; this.options[k] = '';
} }

View File

@ -12,26 +12,28 @@
<div class="search-wrap"> <div class="search-wrap">
<ul class="handle-wraper"> <ul class="handle-wraper">
<li class="handle-item w-250"> <li class="handle-item w-250">
<Select clearable placeholder="运营商" v-model="params.carrier_operator"> <Input clearable placeholder="订单编号" v-model.trim="params.sn"></Input>
<Option :value="0">联通</Option>
<Option :value="1">移动</Option>
<Option :value="2">电信</Option>
</Select>
</li> </li>
<li class="handle-item w-250"> <li class="handle-item w-250">
<Select clearable placeholder="支付方式" v-model="params.pay_channel"> <Input clearable placeholder="流水号" v-model.trim="params.transaction_no"></Input>
<Option :value="0">联通</Option> </li>
<Option :value="1">移动</Option>
<Option :value="2">电信</Option> <li class="handle-item w-250">
<Select clearable placeholder="支付方式" v-model="params.pay_channel_name">
<Option :value="'银行转账'">银行转账</Option>
<Option :value="'微信支付'">微信支付</Option>
<Option :value="'支付宝'">支付宝</Option>
<Option :value="'余额支付'">余额支付</Option>
<Option :value="'天猫续费'">天猫续费</Option>
</Select> </Select>
</li> </li>
<li class="handle-item w-250"> <li class="handle-item w-250">
<Select clearable placeholder="使用状态" v-model="params.used"> <Select clearable placeholder="使用状态" v-model="params.used">
<Option :value="0">未使用</Option> <Option :value="0">未使用</Option>
<Option :value="1">部分使</Option> <Option :value="1">部分</Option>
<Option :value="2">全部使</Option> <Option :value="2">不可</Option>
</Select> </Select>
</li> </li>
@ -44,15 +46,6 @@
v-model.trim="params.time" v-model.trim="params.time"
></DatePicker> ></DatePicker>
</li> </li>
<li class="f-r">
<div class="handle-item">
<Button @click="index()" ghost type="primary">立即搜索</Button>
</div>
<div class="handle-item">
<Button @click="resetSearch" ghost type="warning">重置搜索</Button>
</div>
</li>
</ul> </ul>
<ul class="handle-wraper"> <ul class="handle-wraper">
@ -72,6 +65,14 @@
</Select> </Select>
</li> </li>
<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"> <li class="handle-item w-250">
<Select <Select
icon="ios-search" icon="ios-search"
@ -91,6 +92,19 @@
<li class="handle-item w-250"> <li class="handle-item w-250">
<Input placeholder="SIM" type="textarea" v-model="params.sim"/> <Input placeholder="SIM" type="textarea" v-model="params.sim"/>
</li> </li>
<li class="f-r">
<div class="handle-item">
<Button @click="index()" ghost type="primary">立即搜索</Button>
</div>
<div class="handle-item">
<Button @click="resetSearch" ghost type="warning">重置搜索</Button>
</div>
<div class="handle-item">
<Button @click="exportOrders" type="warning">导出订单</Button>
</div>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -114,9 +128,12 @@
<a @click="sort" class="umar-r10"> <a @click="sort" class="umar-r10">
<b>已选 {{counts}} </b> <b>已选 {{counts}} </b>
</a> </a>
<a @click="clearSelect"> <a @click="clearSelect" class="umar-r10">
<b>清空</b> <b>清空</b>
</a> </a>
<a @click="exportOrders">
<b>导出</b>
</a>
</Row> </Row>
<Row v-else> <Row v-else>
<b class="umar-r10"> {{filterTotal}} / {{total}} </b> <b class="umar-r10"> {{filterTotal}} / {{total}} </b>

View File

@ -1,182 +1,35 @@
<template> <template>
<Drawer <Drawer :mask-closable="false" @on-visible-change="visibleChange" v-model="my_show" width="500">
:mask-closable="false" <div slot="header">
@on-visible-change="visibleChange" <div class="ivu-drawer-header-inner uinn-tb5" style="height: 30px;">
title="订单详情" <span class="umar-r10">清单</span>
v-model="my_show" <Button @click="exportExcel" icon="md-download" size="small">导出</Button>
width="500" </div>
>
<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.sn}}</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.carrier_operator_name}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">套餐名称:</div>
<div class="ui-list-content">{{data.package_name}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">套餐单价:</div>
<div class="ui-list-content">{{data.unit_price}} /服务周期</div>
</li>
<li class="ui-list">
<div class="ui-list-title">订单卡量:</div>
<div class="ui-list-content">{{data.counts}} </div>
</li>
<li class="ui-list">
<div class="ui-list-title">订单总计:</div>
<div class="ui-list-content">{{data.custom_price}} </div>
</li>
<li class="ui-list">
<div class="ui-list-title">支付方式:</div>
<div class="ui-list-content">{{data.pay_channel}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">支付流水号:</div>
<div class="ui-list-content">{{data.transaction_no}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">下单时间:</div>
<div class="ui-list-content">{{data.order_at}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">订单状态:</div>
<div class="ui-list-content">
<Button ghost size="small" type="primary">{{data.order_status_name}}</Button>
</div>
</li>
<li class="ui-list" v-if="data.order_status === 1">
<div class="ui-list-title">取消理由:</div>
<div class="ui-list-content">{{data.extends.cancel_remark}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">支付状态:</div>
<div class="ui-list-content">
<Button
ghost
size="small"
type="info"
v-if="data.transaction_status === 0"
>{{data.transaction_status_name}}</Button>
<Button
ghost
size="small"
type="success"
v-if="data.transaction_status === 1"
>{{data.transaction_status_name}}</Button>
<Button
ghost
size="small"
type="error"
v-if="data.transaction_status === 2"
>{{data.transaction_status_name}}</Button>
</div>
</li>
<li class="ui-list" v-if="data.transaction_status === 2">
<div class="ui-list-title">退款方式:</div>
<div class="ui-list-content">{{data.extends.refund_channel}}</div>
</li>
<li class="ui-list" v-if="data.transaction_status === 2">
<div class="ui-list-title">退款账号:</div>
<div class="ui-list-content">{{data.extends.refund_account}}</div>
</li>
<li class="ui-list" v-if="data.transaction_status === 2">
<div class="ui-list-title">退款备注:</div>
<div class="ui-list-content">{{data.extends.refund_remark}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">订单备注:</div>
<div class="ui-list-content">{{data.remark}}</div>
</li>
</ul>
<Divider>物流信息</Divider>
<ul>
<li class="ui-list">
<div class="ui-list-title">收货地址:</div>
<div class="ui-list-content">{{data.area ? data.area.join(' ') : ''}} {{data.address}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">收货人:</div>
<div class="ui-list-content">{{data.contacts}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">联系电话:</div>
<div class="ui-list-content">{{data.mobile}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">物流备注:</div>
<div class="ui-list-content">{{data.logistics_remark}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">物流公司:</div>
<div class="ui-list-content">{{data.logistics_company_name}}</div>
</li>
<li class="ui-list">
<div class="ui-list-title">物流单号:</div>
<div class="ui-list-content">{{data.logistics_no}}</div>
</li>
</ul>
<Divider>
<span class="umar-r10">出库卡清单</span>
<Button @click="exportExcel" icon="md-download">导出</Button>
</Divider>
<Row class="ta-r"></Row>
<Table
class="umar-t10"
:columns="columns"
:data="cards"
:loading="loading"
disabled-hover
stripe
border
size="small"
></Table>
<Row justify="center" class="umar-tb10 ta-c">
<Page
:current="Number(page.page)"
:page-size="Number(page.limit)"
:page-size-opts="[10, 20, 50, 100]"
:total="Number(page.total)"
@on-change="changePage"
@on-page-size-change="changeLimit"
show-total
size="small"
></Page>
</Row>
</div> </div>
<Table
class="umar-t10"
:columns="columns"
:data="cards"
:loading="loading"
disabled-hover
stripe
border
size="small"
></Table>
<Row justify="center" class="umar-tb10 ta-c">
<Page
:current="Number(page.page)"
:page-size="Number(page.limit)"
:page-size-opts="[10, 20, 50, 100]"
:total="Number(page.total)"
@on-change="changePage"
@on-page-size-change="changeLimit"
show-total
size="small"
></Page>
</Row>
</Drawer> </Drawer>
</template> </template>

View File

@ -145,41 +145,42 @@
<DatePicker type="datetime" placeholder="请选择时间" v-model.trim="params.order_at"></DatePicker> <DatePicker type="datetime" placeholder="请选择时间" v-model.trim="params.order_at"></DatePicker>
</div> </div>
</li> </li>
<div v-if="type === 0">
<li class="ui-list">
<div class="ui-list-title">收货人</div>
<div class="ui-list-content">
<Input :maxlength="32" v-model.trim="params.contacts"></Input>
</div>
</li>
<li class="ui-list"> <li class="ui-list">
<div class="ui-list-title">收货人</div> <div class="ui-list-title">联系电话</div>
<div class="ui-list-content"> <div class="ui-list-content">
<Input :maxlength="32" v-model.trim="params.contacts"></Input> <Input :maxlength="11" v-model.trim="params.mobile"></Input>
</div> </div>
</li> </li>
<li class="ui-list"> <li class="ui-list">
<div class="ui-list-title">联系电话</div> <div class="ui-list-title">收货区域</div>
<div class="ui-list-content"> <div class="ui-list-content">
<Input :maxlength="11" v-model.trim="params.mobile"></Input> <al-selector :data-type="'name'" :level="2" v-model="params.area"/>
</div> </div>
</li> </li>
<li class="ui-list"> <li class="ui-list">
<div class="ui-list-title">收货区域</div> <div class="ui-list-title">收货地址</div>
<div class="ui-list-content"> <div class="ui-list-content">
<al-selector :data-type="'name'" :level="2" v-model="params.area"/> <Input :maxlength="255" v-model.trim="params.address"></Input>
</div> </div>
</li> </li>
<li class="ui-list"> <li class="ui-list">
<div class="ui-list-title">收货地址</div> <div class="ui-list-title">订单备注</div>
<div class="ui-list-content"> <div class="ui-list-content">
<Input :maxlength="255" v-model.trim="params.address"></Input> <Input v-model.trim="params.remark" type="textarea" placeholder="..."/>
</div> </div>
</li> </li>
</div>
<li class="ui-list">
<div class="ui-list-title">订单备注</div>
<div class="ui-list-content">
<Input v-model.trim="params.remark" type="textarea" placeholder="..."/>
</div>
</li>
</ul> </ul>
</div> </div>

View File

@ -43,33 +43,36 @@
</li> </li>
<li class="handle-item w-250"> <li class="handle-item w-250">
<AutoComplete <Input clearable placeholder="流水号" v-model.trim="params.transaction_no"></Input>
@on-search="handleCompleteCompanies" </li>
icon="ios-search"
placeholder="企业名称" <li class="handle-item w-120" v-if="type === 0">
v-model.trim="params.company_name" <Select clearable placeholder="订单状态" v-model="params.order_status">
> <Option :value="0">已下单</Option>
<Option <Option :value="1">已取消</Option>
:key="item.id" <Option :value="2">已排单</Option>
:value="item.name" <Option :value="3">已出库</Option>
v-for="item in completeHandledCompanies" <Option :value="4">已发货</Option>
>{{ item.name }}</Option> <Option :value="5">已签收</Option>
</AutoComplete> </Select>
</li>
<li class="handle-item w-120" v-if="type === 0">
<Select clearable placeholder="收款状态" v-model="params.transaction_status">
<Option :value="0">未收款</Option>
<Option :value="1">已收款</Option>
<Option :value="2">已退款</Option>
</Select>
</li> </li>
<li class="handle-item w-250"> <li class="handle-item w-250">
<AutoComplete <Select clearable placeholder="支付方式" v-model="params.pay_channel">
@on-search="handleCompletePackages(type)" <Option :value="'bank'">银行转账</Option>
icon="ios-search" <Option :value="'wx'">微信支付</Option>
placeholder="套餐名称" <Option :value="'alipay'">支付宝</Option>
v-model.trim="params.package_name" <Option :value="'account'">余额支付</Option>
> <Option :value="'tmall'">天猫续费</Option>
<Option </Select>
:key="item.id"
:value="item.name"
v-for="item in completeHandledPackages"
>{{ item.name }}</Option>
</AutoComplete>
</li> </li>
<li class="handle-item w-250"> <li class="handle-item w-250">
@ -85,22 +88,18 @@
<ul class="handle-wraper"> <ul class="handle-wraper">
<li class="handle-item w-250"> <li class="handle-item w-250">
<Select clearable placeholder="订单状态" v-model="params.order_status"> <AutoComplete
<Option :value="0">已下单</Option> @on-search="handleCompleteCompanies"
<Option :value="1">已取消</Option> icon="ios-search"
<Option :value="2">已排单</Option> placeholder="企业名称"
<Option :value="3">已出库</Option> v-model.trim="params.company_name"
<Option :value="4">已发货</Option> >
<Option :value="5">已签收</Option> <Option
</Select> :key="item.id"
</li> :value="item.name"
v-for="item in completeHandledCompanies"
<li class="handle-item w-250"> >{{ item.name }}</Option>
<Select clearable placeholder="收款状态" v-model="params.transaction_status"> </AutoComplete>
<Option :value="0">未收款</Option>
<Option :value="1">已收款</Option>
<Option :value="2">已退款</Option>
</Select>
</li> </li>
<li class="handle-item w-250"> <li class="handle-item w-250">
@ -111,6 +110,25 @@
</Select> </Select>
</li> </li>
<li class="handle-item w-250">
<AutoComplete
@on-search="handleMyCompletePackages"
icon="ios-search"
placeholder="套餐名称"
v-model.trim="params.package_name"
placement="bottom"
>
<Option
:key="item.id"
:value="item.name"
v-for="item in completeHandledPackages"
>{{ item.name }}</Option>
</AutoComplete>
</li>
<li class="handle-item w-250">
<Input placeholder="SIM" type="textarea" v-model="params.sim"/>
</li>
<li class="f-r"> <li class="f-r">
<div class="handle-item"> <div class="handle-item">
<Button @click="index(1)" ghost type="primary">立即搜索</Button> <Button @click="index(1)" ghost type="primary">立即搜索</Button>
@ -118,6 +136,9 @@
<div class="handle-item"> <div class="handle-item">
<Button @click="resetSearch" ghost type="warning">重置搜索</Button> <Button @click="resetSearch" ghost type="warning">重置搜索</Button>
</div> </div>
<div class="handle-item">
<Button @click="exportOrders" type="warning">导出订单</Button>
</div>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -48,12 +48,15 @@ export default {
page: 1 page: 1
}, },
params: { params: {
sn: '',
company_name: '', company_name: '',
package_name: '', package_name: '',
carrier_operator: '', carrier_operator: '',
transaction_no: '',
pay_channel_name: '',
time: [ time: [
this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM-DD'), this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM-DD'),
this.moment().subtract('2', 'months').endOf('month').format('YYYY-MM-DD') this.moment().subtract('1', 'months').endOf('month').format('YYYY-MM-DD')
], ],
used: '', used: '',
sim: '' sim: ''
@ -63,6 +66,35 @@ export default {
showOrders: [], showOrders: [],
showCards: [], showCards: [],
orderColumns: [ orderColumns: [
{
type: 'expand',
width: 50,
render: (h, context) => {
let row = context.row;
let html = [];
let col = [];
col.push(h('Col', { props: { span: 8 }, class: [] }, '订单编号: ' + row.sn));
col.push(h('Col', { props: { span: 8 }, class: [] }, '支付流水号: ' + row.transaction_no));
html.push(h('Row', { class: [] }, col));
if (this.type === 0) {
col = [];
col.push(h('Col', { props: { span: 8 }, class: [] }, '收货人: ' + row.contacts));
col.push(h('Col', { props: { span: 8 }, class: [] }, '联系电话: ' + row.mobile));
html.push(h('Row', { class: [] }, col));
col = [];
col.push(h('Col', { props: { span: 16 }, class: [] }, '收货地址: ' + row.address));
html.push(h('Row', { class: [] }, col));
}
return h('div', { class: ['fz-13'] }, html);
}
},
{ {
width: 60, width: 60,
align: "center", align: "center",
@ -81,7 +113,7 @@ export default {
on: { on: {
input: value => { input: value => {
let order_id = this.showOrders.filter(el => { let order_id = this.showOrders.filter(el => {
return el.shipments !== el.counts; return el.counts - el.shipments - el.refunds > 0;
}).map(item => { }).map(item => {
return item.id; return item.id;
}); });
@ -104,7 +136,7 @@ export default {
props: { props: {
indeterminate: value && !!indeterminate, indeterminate: value && !!indeterminate,
value: value, value: value,
disabled: context.row.counts === context.row.shipments disabled: context.row.counts - context.row.shipments - context.row.refunds <= 0
}, },
on: { on: {
input: value => { input: value => {
@ -115,12 +147,11 @@ export default {
} }
}, },
{ {
title: "订单编号", title: "ID",
key: "sn", key: "id",
width: 220, width: 80,
sortable: true sortable: true
}, },
{ {
title: "企业名称", title: "企业名称",
key: "company_name", key: "company_name",
@ -144,28 +175,33 @@ export default {
width: 90 width: 90
}, },
{ {
title: "数量", title: "可用量",
key: "",
width: 90,
render: (h, context) => {
return h('span', context.row.counts - context.row.shipments - context.row.refunds);
}
},
{
title: "总量",
key: "counts", key: "counts",
width: 100, width: 100,
sortable: true sortable: true
}, },
{
title: "已用数量",
key: "shipments",
width: 90
},
{ {
title: "订单金额", title: "订单金额",
key: "total_price", key: "total_price",
width: 120, width: 120,
sortable: true sortable: true
}, },
{ {
title: "订单时间", title: '下单时间',
key: "order_at", key: 'order_at',
width: 150, minWidth: 110,
sortable: true sortable: true,
render: (h, context) => {
return h('span', this.moment(context.row.order_at).format('YYYY-MM-DD'));
}
}, },
{ {
title: "所需卡量", title: "所需卡量",
@ -181,7 +217,7 @@ export default {
return h("InputNumber", { return h("InputNumber", {
props: { props: {
max: context.row.counts - context.row.shipments, max: context.row.counts - context.row.shipments - context.row.refunds,
min: 0, min: 0,
value: value, value: value,
precision: 0 precision: 0
@ -229,7 +265,7 @@ export default {
return h("Checkbox", { return h("Checkbox", {
props: { props: {
value: value, value: value,
disabled: !!context.row.virtual_order_id disabled: Boolean(context.row.virtual_order_id || context.row.refunded_at)
}, },
on: { on: {
input: value => { input: value => {
@ -251,13 +287,27 @@ export default {
key: "", key: "",
width: 100, width: 100,
render: (h, { row, column, index }) => { render: (h, { row, column, index }) => {
let color = 'success';
let status_name = '未使用';
if (row.refunded_at && row.virtual_order_id) {
color = 'error';
status_name = '退货使用';
} else if (row.virtual_order_id) {
color = 'primary';
status_name = '已使用';
} else if (row.refunded_at) {
color = 'warning';
status_name = '已退货';
}
return h( return h(
"Tag", { "Tag", {
props: { props: {
color: row.virtual_order_id ? "error" : "primary" color: color
} }
}, },
row.virtual_order_id ? "已使用" : "未使用" status_name
); );
} }
}, },
@ -312,9 +362,10 @@ export default {
if (this.params.sim !== '') { if (this.params.sim !== '') {
params.sim = this.params.sim; params.sim = this.params.sim;
let cardParams = { sim: this.params.sim };
this.params.time = [];
this.cardLoading = true; this.cardLoading = true;
this.$store.dispatch("getCardsByParams", params).then((cards) => { this.$store.dispatch("getCardsByParams", cardParams).then((cards) => {
this.showCards = cards; this.showCards = cards;
this.cardLoading = false; this.cardLoading = false;
}).catch(() => { }).catch(() => {
@ -360,6 +411,24 @@ export default {
}); });
} }
if (this.params.pay_channel_name !== '' && this.params.pay_channel_name !== undefined) {
filterOrders = filterOrders.filter(el => {
return el.pay_channel_name && el.pay_channel_name.indexOf(this.params.pay_channel_name) !== -1;
});
}
if (this.params.transaction_no !== '' && this.params.transaction_no !== undefined) {
filterOrders = filterOrders.filter(el => {
return el.transaction_no && el.transaction_no.indexOf(this.params.transaction_no) !== -1;
});
}
if (this.params.sn !== '' && this.params.sn !== undefined) {
filterOrders = filterOrders.filter(el => {
return el.sn && el.sn.indexOf(this.params.sn) !== -1;
});
}
if (this.params.carrier_operator !== '' && this.params.carrier_operator !== undefined) { if (this.params.carrier_operator !== '' && this.params.carrier_operator !== undefined) {
filterOrders = filterOrders.filter(el => { filterOrders = filterOrders.filter(el => {
return el.carrier_operator === this.params.carrier_operator; return el.carrier_operator === this.params.carrier_operator;
@ -370,11 +439,11 @@ export default {
filterOrders = filterOrders.filter(el => { filterOrders = filterOrders.filter(el => {
switch (this.params.used) { switch (this.params.used) {
case 0: case 0:
return el.shipments === 0; return el.shipments + el.refunds === 0 && el.counts;
case 1: case 1:
return el.shipments > 0 && el.shipments !== el.counts; return el.shipments + el.refunds > 0 && el.shipments + el.refunds !== el.counts;
case 2: case 2:
return el.shipments > 0 && el.shipments === el.counts; return el.shipments + el.refunds === el.counts;
default: default:
break; break;
} }
@ -405,13 +474,81 @@ export default {
clearSelect() { clearSelect() {
this.$store.dispatch('setSelected', []); this.$store.dispatch('setSelected', []);
}, },
exportOrders() {
let columns = [
{ title: "订单编号", key: "sn" },
{ title: "企业名称", key: "company_name" },
{ title: "运营商", key: "carrier_operator_name" },
{ title: "套餐名称", key: "package_name" },
{ title: "套餐单价", key: "unit_price" },
{ title: "支付方式", key: "pay_channel_name" },
{ title: "支付流水号", key: "transaction_no" },
{ title: "订单时间", key: "order_at" },
{ title: "SIM", key: "sim" },
{ title: "数量", key: "counts" },
{ title: "使用状态", key: "virtual_order_id" },
{ title: "VD企业", key: "virtual_company_name" },
{ title: "VD套餐", key: "virtual_package_name" }
];
if (this.type === 0) {
columns.push({ title: "退货", key: "refunded" });
}
let data = [];
let orders = {};
for (let index = 0; index < this.orders.length; index++) {
const element = this.orders[index];
orders[element.id] = element;
}
for (let index = 0; index < this.cards.length; index++) {
const element = this.cards[index];
let order = orders[element.order_id];
let obj = {
sn: order.sn,
company_name: order.company_name,
carrier_operator_name: order.carrier_operator_name,
package_name: order.package_name,
unit_price: order.unit_price,
pay_channel_name: order.pay_channel_name,
transaction_no: order.transaction_no,
order_at: order.order_at,
sim: element.sim,
counts: element.counts,
virtual_order_id: element.virtual_order_id ? '已使用' : '未使用',
virtual_company_name: element.company_name,
virtual_package_name: element.package_name
};
if (this.type === 0) {
obj.refunded = element.refunded_at ? '是' : '否';
}
data.push(obj);
}
this.$refs.cardSelection.exportCsv({
filename: '订单导出' + this.moment().format('YYYYMMDDhhmmss'),
columns: columns,
data: data
});
},
cannel() { cannel() {
this.clear(); this.clear();
this.close(); this.close();
}, },
resetParams() { resetParams() {
for (let k in this.params) { for (let k in this.params) {
if (k !== 'time') { if (k === 'time') {
this.params[k] = [
this.moment().subtract('1', 'months').startOf('month').format('YYYY-MM-DD'),
this.moment().subtract('1', 'months').endOf('month').format('YYYY-MM-DD')
];
} else {
this.params[k] = ''; this.params[k] = '';
} }
} }
@ -428,14 +565,6 @@ export default {
this.$store.dispatch('getCards', params).then((cards) => { this.$store.dispatch('getCards', params).then((cards) => {
this.cardLoading = false; this.cardLoading = false;
this.showCards = cards; this.showCards = cards;
// 跳转到选择的行
// this.$nextTick(() => {
// if (typeof order_id !== 'object') {
// let index = this.showCards.findIndex(el => { return el.order_id === order_id; });
// let toIndex = index - 5 > 0 ? index - 5 : 0;
// this.$refs.cardSelection.scrollToRow(toIndex);
// }
// });
resolve(cards); resolve(cards);
}).catch((err) => { }).catch((err) => {
this.cardLoading = false; this.cardLoading = false;
@ -568,7 +697,7 @@ export default {
}); });
mapped.sort((a, b) => { mapped.sort((a, b) => {
if (a.shipments === a.counts) { if (a.counts - a.shipments - a.refunds <= 0) {
return -1; return -1;
} }
@ -618,7 +747,7 @@ export default {
}, },
selectAll() { selectAll() {
let order_id = this.filterOrders.filter(el => { let order_id = this.filterOrders.filter(el => {
return el.shipments !== el.counts; return el.counts - el.shipments - el.refunds >= 0;
}).map(item => { }).map(item => {
return item.id; return item.id;
}); });

View File

@ -8,7 +8,7 @@ export default {
}, },
data: { data: {
type: Object, type: Object,
default () { default() {
return null; return null;
} }
} }
@ -29,30 +29,28 @@ export default {
page: { page: {
total: 0, total: 0,
page: 1, page: 1,
limit: 10 limit: 20
}, },
columns: [ columns: [
{ {
title: "SIM卡号", title: "SIM卡号",
key: "column1", key: "sim",
align: 'center' align: 'center'
}, },
{ {
title: "数量", title: "数量",
key: "counts1", key: "counts",
width: 75, width: 75,
align: 'center' align: 'center'
}, },
{ {
title: "SIM卡号", title: "退货",
key: "column2", key: "",
align: 'center'
},
{
title: "数量",
key: "counts2",
width: 75, width: 75,
align: 'center' align: 'center',
render: (h, context) => {
return h('span', context.row.refunded_at ? '√' : '');
}
} }
], ],
cards: [] cards: []
@ -72,20 +70,7 @@ export default {
if (res.code === 0) { if (res.code === 0) {
this.page.total = res.data.total; this.page.total = res.data.total;
let cards = res.data.data; this.cards = res.data.data;
let array = [];
for (let index = 0; index < cards.length; index = index + 2) {
array.push({
column1: cards[index] ? cards[index]['sim'] : '',
counts1: cards[index] ? cards[index]['counts'] : '',
column2: cards[index + 1] ? cards[index + 1]['sim'] : '',
counts2: cards[index + 1] ? cards[index + 1]['counts'] : ''
});
}
this.cards = array;
} }
}); });
}, },

View File

@ -12,11 +12,13 @@ export default {
params: { params: {
type: 0, type: 0,
sn: '', sn: '',
transaction_no: '',
company_name: '', company_name: '',
package_name: '', package_name: '',
order_status: '', order_status: '',
carrier_operator: '', carrier_operator: '',
trashed: '', trashed: '',
sim: '',
time: [] time: []
}, },
type: 0, type: 0,
@ -50,56 +52,108 @@ export default {
}, },
table_titles: [ table_titles: [
{ {
title: '订单编号', type: 'expand',
key: 'sn', width: 50,
width: 280 render: (h, params) => {
let row = params.row;
let html = [];
html.push(h('div', { class: ['umar-b5'] }, '---- 订单信息 ----'));
let col = [];
col.push(h('Col', { props: { span: 6 }, class: [] }, '订单编号: ' + row.sn));
col.push(h('Col', { props: { span: 6 }, class: [] }, '支付流水号: ' + row.transaction_no));
col.push(h('Col', { props: { span: 6 }, class: [] }, '订单备注: ' + row.remark));
if (row.order_status === 1) {
col.push(h('Col', { props: { span: 6 }, class: [] }, '订单取消理由: ' + row.extends.cancel_remark));
}
html.push(h('Row', { class: [] }, col));
if (row.transaction_status === 2) {
col = [];
col.push(h('Col', { props: { span: 6 }, class: [] }, '退款方式: ' + row.extends.refund_channel));
col.push(h('Col', { props: { span: 6 }, class: [] }, '退款账号: ' + row.extends.refund_account));
col.push(h('Col', { props: { span: 12 }, class: [] }, '退款备注: ' + row.extends.refund_remark));
html.push(h('Row', {}, col));
}
if (this.type === 0) {
html.push(h('div', { class: ['umar-t10', 'umar-b5'] }, '---- 物流信息 ----'));
col = [];
col.push(h('Col', { props: { span: 6 }, class: [] }, '收货人: ' + row.contacts));
col.push(h('Col', { props: { span: 6 }, class: [] }, '联系电话: ' + row.mobile));
col.push(h('Col', { props: { span: 12 }, class: [] }, '收货地址: ' + (row.area ? row.area.join(' ') : '') + ' ' + row.address));
html.push(h('Row', { class: [] }, col));
col = [];
col.push(h('Col', { props: { span: 6 }, class: [] }, '物流单号: ' + row.logistics_no));
col.push(h('Col', { props: { span: 6 }, class: [] }, '物流公司: ' + row.logistics_company_name));
col.push(h('Col', { props: { span: 12 }, class: [] }, '物流备注: ' + row.logistics_remark));
html.push(h('Row', { class: [] }, col));
}
return h('div', { class: ['fz-13'] }, html);
}
},
{
title: 'ID',
key: 'id',
minWidth: 80
}, },
{ {
title: '企业名称', title: '企业名称',
key: 'company_name', key: 'company_name',
width: 320 minWidth: 240,
tooltip: true
}, },
{ {
title: '运营商', title: '运营商',
key: 'carrier_operator', key: 'carrier_operator_name',
width: 90 minWidth: 90
}, },
{ {
title: '套餐名称', title: '套餐名称',
key: 'package_name', key: 'package_name',
width: 120 minWidth: 120
}, },
{ {
title: '套餐单价', title: '套餐单价',
key: 'unit_price', key: 'unit_price',
width: 100 minWidth: 100
}, },
{ {
title: '订单数量', title: '订单量',
key: '', key: '',
width: 100, minWidth: 80,
render: (h, { render: (h, context) => {
row, return h('span', Number(context.row.counts));
column,
index
}) => {
return h('span', Number(row.counts));
} }
}, },
{ {
title: '订单金额', title: '订单金额',
key: 'custom_price', key: 'custom_price',
width: 120 minWidth: 120
},
{
title: '支付方式',
key: 'pay_channel_name',
minWidth: 120
}, },
{ {
title: '订单状态', title: '订单状态',
key: '', key: '',
width: 100, minWidth: 100,
render: (h, { render: (h, context) => {
row, let row = context.row;
column,
index
}) => {
let status = ['error', 'default', 'warning', 'primary', 'success']; let status = ['error', 'default', 'warning', 'primary', 'success'];
return h('Button', { return h('Button', {
@ -228,12 +282,9 @@ export default {
{ {
title: '收款状态', title: '收款状态',
key: '', key: '',
width: 100, minWidth: 100,
render: (h, { render: (h, context) => {
row, let row = context.row;
column,
index
}) => {
let status = ['error', 'success', 'default']; let status = ['error', 'success', 'default'];
return h('Button', { return h('Button', {
@ -371,18 +422,18 @@ export default {
{ {
title: '下单时间', title: '下单时间',
key: 'order_at', key: 'order_at',
width: 170 minWidth: 110,
render: (h, context) => {
return h('span', this.moment(context.row.order_at).format('YYYY-MM-DD'));
}
}, },
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 190, minWidth: 300,
fixed: 'right', render: (h, context) => {
render: (h, { let row = context.row;
row, row.unit_price = Number(row.unit_price);
column,
index
}) => {
let html = []; let html = [];
if (row.deleted_at) { if (row.deleted_at) {
@ -399,7 +450,7 @@ export default {
type: 'dashed', type: 'dashed',
size: 'small', size: 'small',
disabled: false, disabled: false,
icon: 'md-eye' icon: 'ios-list'
}, },
class: ['btn'], class: ['btn'],
on: { on: {
@ -407,7 +458,24 @@ export default {
this.show(row); this.show(row);
} }
} }
}, '查看')); }, '清单'));
}
if (this.haveJurisdiction('update')) {
html.push(h('Button', {
props: {
type: 'primary',
size: 'small',
disabled: false,
icon: 'md-create'
},
class: ['btn'],
on: {
click: (event) => {
this.openEdit(true, 2, row);
}
}
}, '编辑'));
} }
if (this.haveJurisdiction('update')) { if (this.haveJurisdiction('update')) {
@ -421,7 +489,8 @@ export default {
}, [h('Button', { }, [h('Button', {
props: { props: {
type: 'success', type: 'success',
size: 'small' size: 'small',
icon: 'md-list-box'
}, },
class: ['btn'], class: ['btn'],
on: { on: {
@ -438,7 +507,8 @@ export default {
props: { props: {
type: 'warning', type: 'warning',
size: 'small', size: 'small',
disabled: false disabled: false,
icon: 'md-timer'
}, },
class: ['btn'], class: ['btn'],
on: { on: {
@ -451,10 +521,13 @@ export default {
API.reset({ API.reset({
ids: row.id ids: row.id
}).then(res => { }).then(res => {
this.isShowLoading(false);
if (res.code == 0) { if (res.code == 0) {
this.$Message.success('操作成功'); this.$Message.success('操作成功');
this.request(); this.request();
} }
}).catch(() => {
this.isShowLoading(false);
}); });
} }
}); });
@ -468,7 +541,8 @@ export default {
props: { props: {
type: 'error', type: 'error',
size: 'small', size: 'small',
disabled: false disabled: false,
icon: 'md-trash'
}, },
class: ['btn'], class: ['btn'],
on: { on: {
@ -504,21 +578,26 @@ export default {
created() { created() {
this.index(1); this.index(1);
}, },
mounted() {
if (this.type === 0) {
this.table_titles.splice(7, 0, {
title: '退货量',
key: 'refunds',
width: 80
});
}
if (this.type !== 0) {
this.table_titles.splice(9, 2);
}
},
methods: { methods: {
// 查看订单明细 // 查看订单明细
show(row) { show(row) {
this.isShowLoading(true); this.detailObj = {
API.show(row.id).then(res => { show: true,
this.isShowLoading(false); data: row
if (res.code === 0) { };
this.detailObj = {
show: true,
data: res.data
};
}
}).catch(() => {
this.isShowLoading(false);
});
}, },
/** /**
* [index 列表] * [index 列表]
@ -539,6 +618,25 @@ export default {
this.isShowLoading(false); this.isShowLoading(false);
}); });
}, },
exportOrders() {
this.isShowLoading(true);
let params = this.parseParams(this.params);
params.type = Number(this.$route.params.type);
API.exportOrders(params).then(res => {
if (res.code === 0) {
this.downloadFile(res.data);
} else {
this.$Modal.success({
title: '提示',
content: '当前导出数据量大,已进入后台队列导出模式,请稍后至导出列表查看下载。'
});
}
this.isShowLoading(false);
}).catch(() => {
this.isShowLoading(false);
});
},
/** /**
* [openEdit 打开编辑弹窗] * [openEdit 打开编辑弹窗]
@ -673,6 +771,9 @@ export default {
this.cardsObj.show = false; this.cardsObj.show = false;
this.$store.dispatch('initOrder'); this.$store.dispatch('initOrder');
this.index(page); this.index(page);
},
handleMyCompletePackages(value) {
this.handleCompletePackages(this.type, value);
} }
} }
}; };

View File

@ -1,14 +1,31 @@
<?php <?php
use App\Domains\Card\Services\CardService; use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
require_once realpath(dirname(__FILE__) . '/TestCase.php'); require_once realpath(dirname(__FILE__) . '/TestCase.php');
$simArray = [ $handle = fopen(__DIR__ . '/interval.csv', 'w');
$custom_no = DB::connection('vd_old')->table('ckb_custom_handle_log')->select('custom_no')->distinct()->where('type', 11)->get()->pluck('custom_no')->toArray();
]; fputcsv($handle, ['客户编号', '间隔时间']);
$values = CardService::getMongoCardsInfo($simArray); foreach (array_chunk($custom_no, 1000) as $values) {
$res = DB::connection('vd_old')->table('ckb_custom_handle_log')->whereIn('custom_no', $values)->whereIn('type', [10, 11])->orderBy('valid_start_time')->get()->groupBy('custom_no');
dd($values); foreach ($res as $no => $group) {
echo $no . PHP_EOL;
for ($i=1; $i < count($group); $i++) {
$item1 = $group[$i - 1];
$item2 = $group[$i];
$interval = Carbon::createFromTimestamp(intval($item2->valid_start_time))->diffInMonths(Carbon::createFromTimestamp(intval($item1->valid_end_time)));
fputcsv($handle, [$no, $interval]);
}
}
}
fclose($handle);
dd(1);

426075
tests/interval.csv Normal file

File diff suppressed because it is too large Load Diff