mirror of
https://gitee.com/hzchunfen/erp.git
synced 2025-11-30 22:20:45 +00:00
V1版本,商品入库、各类报表、商品预警
This commit is contained in:
parent
2484090058
commit
bbc89a2355
58
app/Console/Commands/ChkOrderServer.php
Normal file
58
app/Console/Commands/ChkOrderServer.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\MessageStock;
|
||||
use App\Models\Shop;
|
||||
use App\Models\StockNotice;
|
||||
use App\Services\Business\BusinessFactory;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Pool\Core\Redis;
|
||||
class ChkOrderServer extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'check:orderServer';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '快团团根据更新时间获取增量售后单';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$shops = Shop::query()->where('plat_id', Shop::$PLAT_KTT)->where('status', Shop::$STATUS_AUTHORIZED)->get();
|
||||
$endTime = DateTimeUtils::getMicroTime();
|
||||
$beginTime = $endTime-(24*60*60*1000);
|
||||
foreach ($shops as $shop) {
|
||||
BusinessFactory::init()->make($shop->plat_id)->setShop($shop)->downloadOrdersAndSaveServer($beginTime, $endTime);
|
||||
}
|
||||
|
||||
Log::info('任务完成:快团团根据更新时间获取增量售后单');
|
||||
}
|
||||
}
|
||||
71
app/Console/Commands/ChkPriceearly.php
Normal file
71
app/Console/Commands/ChkPriceearly.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\MessageStock;
|
||||
use App\Models\StockNotice;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Pool\Core\Redis;
|
||||
class ChkPriceearly extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'check:priceearly';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '检查价格异常';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$stock=StockNotice::where('id',2)->first();
|
||||
$results = DB::table('business_order_items as a')
|
||||
->select('c.title as cn_name', 'b.title as title', DB::raw('FORMAT(a.goods_price / 100, 2) AS goods_price'), 'b.cost','a.created_at','a.business_order_id')
|
||||
->leftJoin('goods_skus as b', 'a.external_sku_id', '=', 'b.external_sku_id')
|
||||
->leftJoin('goods as c', 'b.goods_id', '=', 'c.id')
|
||||
->where('b.title', '!=', '')
|
||||
->groupBy('a.id')
|
||||
->havingRaw('goods_price < cost')
|
||||
->get();
|
||||
$redis=new Redis();
|
||||
$arr=[];
|
||||
foreach ($results as $k=>$v){
|
||||
if (!$redis->exists($stock->cn_name.'::'.$v->title)){
|
||||
$redis->set($stock->cn_name.'::'.$v->title,$v->business_order_id);
|
||||
$arr[$k]['title']=$stock->cn_name;
|
||||
$arr[$k]['user_id']=$stock->user_id;
|
||||
$arr[$k]['stock_notice_id']=$stock->id;
|
||||
$arr[$k]['content']=Carbon::now()->format('Y-m-d')." 订单号:{$v->business_order_id} 商品{$v->cn_name}规格{$v->title}价格有异常,当前售价{$v->goods_price}/支,当前成本价{$v->cost}/支";
|
||||
$arr[$k]['created_at']=Carbon::now();
|
||||
MessageStock::insert($arr);
|
||||
}
|
||||
}
|
||||
Log::info('任务完成:check-ChkPriceearly');
|
||||
}
|
||||
}
|
||||
83
app/Console/Commands/ChkReplenish.php
Normal file
83
app/Console/Commands/ChkReplenish.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\MessageStock;
|
||||
use App\Models\StockNotice;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Pool\Core\Redis;
|
||||
class ChkReplenish extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'check:replenish';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '检查库存缺货';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
// Log::info('任务完成:check-replenish');
|
||||
$stock=StockNotice::where('id',1)->first();
|
||||
$stocksQuery = DB::table('goods_skus AS a')
|
||||
->select(
|
||||
'a.id',
|
||||
'a.title',
|
||||
'a.num',
|
||||
'a.stock','a.updated_at',
|
||||
DB::raw('b.title AS good_name'),
|
||||
DB::raw('SUM(a.num - a.stock) AS stocks')
|
||||
)
|
||||
->leftJoin('goods AS b', 'a.goods_id', '=', 'b.id')
|
||||
->where('a.num', '!=', 0)
|
||||
->where('a.stock', '!=', 0)
|
||||
->groupBy('id')
|
||||
->havingRaw("stocks < $stock->active_piece");
|
||||
$stocks = $stocksQuery->get();
|
||||
$currentDateTime = Carbon::now();
|
||||
$endOfDay = Carbon::today()->endOfDay();
|
||||
$secondsRemaining = $currentDateTime->diffInSeconds($endOfDay);
|
||||
$redis=new Redis();
|
||||
$arr=[];
|
||||
foreach ($stocks as $k=>$v){
|
||||
if (!$redis->exists($stock->cn_name.'::'.$v->title)){
|
||||
$redis->setex($stock->cn_name.'::'.$v->title,$secondsRemaining,$v->stock);
|
||||
$arr[$k]['title']=$stock->cn_name;
|
||||
$arr[$k]['user_id']=$stock->user_id;
|
||||
$arr[$k]['stock_notice_id']=$stock->id;
|
||||
$arr[$k]['content']=Carbon::now()->format('Y-m-d')." 商品{$v->good_name}规格{$v->title}需要补货,当前库存{$v->num}/支,可售库存{$v->stock}/支";
|
||||
$arr[$k]['created_at']=Carbon::now();
|
||||
MessageStock::insert($arr);
|
||||
}
|
||||
|
||||
}
|
||||
Log::info('任务完成:check-replenish');
|
||||
}
|
||||
}
|
||||
80
app/Console/Commands/ChkShelflife.php
Normal file
80
app/Console/Commands/ChkShelflife.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\MessageStock;
|
||||
use App\Models\StockNotice;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Pool\Core\Redis;
|
||||
class ChkShelflife extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'check:shelflife';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '检查商品即将过期';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$stock=StockNotice::where('id',3)->first();
|
||||
$results = DB::table('warehouse_stock_item as a')
|
||||
->leftJoin('goods_skus as b', 'a.good_sku_id', '=', 'b.id')
|
||||
->leftJoin('goods as c', 'a.good_id', '=', 'c.id')
|
||||
->select('c.title as cn_name', 'b.title as title','a.buyer_at as buyer_ats', DB::row('DATE(a.buyer_at) as buyer_at'),'a.stock')
|
||||
->where('b.title', '!=', '')
|
||||
->groupBy('a.id')
|
||||
->get();
|
||||
$today=Carbon::today()->toDateString();
|
||||
$currentDateTime = Carbon::now();
|
||||
$endOfDay = Carbon::today()->endOfDay();
|
||||
$secondsRemaining = $currentDateTime->diffInSeconds($endOfDay);
|
||||
$redis=new Redis();
|
||||
foreach ($results as $k =>$v){
|
||||
$ymd=explode('-',$v->buyer_at);
|
||||
$date = Carbon::create($ymd[0], $ymd[1], $ymd[2]);
|
||||
$date->addDays($stock->day_num);
|
||||
if ($today >= $date->toDateString()){
|
||||
//报警
|
||||
if (!$redis->exists($stock->cn_name.'::'.$v->title)){
|
||||
$redis->setex($stock->cn_name.'::'.$v->title,$secondsRemaining,$v->stock);
|
||||
$arr[$k]['title']=$stock->cn_name;
|
||||
$arr[$k]['user_id']=$stock->user_id;
|
||||
$arr[$k]['stock_notice_id']=$stock->id;
|
||||
$arr[$k]['content']=Carbon::now()->format('Y-m-d')." 商品{$v->cn_name}规格{$v->title}即将过期,入库库存{$v->stock}/支";
|
||||
$arr[$k]['created_at']=Carbon::now();
|
||||
MessageStock::insert($arr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log::info('任务完成:check-shelflife');
|
||||
}
|
||||
}
|
||||
@ -45,7 +45,7 @@ class KttOrderQuery extends Command
|
||||
$endTime = DateTimeUtils::getMicroTime();
|
||||
$beginTime = $endTime - 63000;
|
||||
foreach ($shops as $shop) {
|
||||
BusinessFactory::init()->make($shop->plat_id)->setShop($shop)->downloadOrdersAndSave($beginTime, $endTime + 3000);
|
||||
BusinessFactory::init()->make($shop->plat_id)->setShop($shop)->downloadOrdersAndSave($beginTime, $endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,13 +2,20 @@
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Console\Commands\ChkOrderServer;
|
||||
use App\Console\Commands\ChkPriceearly;
|
||||
use App\Console\Commands\ChkReplenish;
|
||||
use App\Console\Commands\ChkShelflife;
|
||||
use App\Console\Commands\DailySalesReport;
|
||||
use App\Console\Commands\GoodsSkuDailyReport;
|
||||
use App\Console\Commands\Inventory;
|
||||
use App\Models\StockNotice;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
use App\Console\Commands\KttOrderQuery;
|
||||
use App\Console\Commands\DeleteKttQuery;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use function RingCentral\Psr7\str;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
@ -19,6 +26,7 @@ class Kernel extends ConsoleKernel
|
||||
*/
|
||||
protected $commands = [
|
||||
//
|
||||
\App\Console\Commands\ChkReplenish::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@ -29,22 +37,34 @@ class Kernel extends ConsoleKernel
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
|
||||
// 服务器/etc/crontab添加cron入口
|
||||
// * * * * * cd /home/wwwroot/erp.chutang66.com && php artisan schedule:run >> /dev/null 2>&1
|
||||
$schedule->command(KttOrderQuery::class)->everyMinute();
|
||||
// $schedule->command(KttOrderQuery::class)->everyMinute();
|
||||
//
|
||||
// $schedule->command(GoodsSkuDailyReport::class)->dailyAt('06:00');
|
||||
// $schedule->command(Inventory::class)->dailyAt('07:00');
|
||||
//
|
||||
// $schedule->command(DailySalesReport::class, ['S1'])->dailyAt('12:00');
|
||||
// $schedule->command(DailySalesReport::class, ['S2'])->dailyAt('13:30');
|
||||
// $schedule->command(DailySalesReport::class, ['S3'])->dailyAt('15:00');
|
||||
// $schedule->command(DailySalesReport::class, ['S4'])->dailyAt('16:00');
|
||||
// $schedule->command(DailySalesReport::class, ['S5'])->dailyAt('17:30');
|
||||
// $schedule->command(DailySalesReport::class, ['S6'])->dailyAt('20:00');
|
||||
// $schedule->command(DailySalesReport::class, ['S7'])->dailyAt('09:30');
|
||||
//
|
||||
// $schedule->command(DeleteKttQuery::class)->daily();
|
||||
|
||||
$schedule->command(GoodsSkuDailyReport::class)->dailyAt('06:00');
|
||||
$schedule->command(Inventory::class)->dailyAt('07:00');
|
||||
// $schedule->command('check:replenish')->everyMinute();
|
||||
// $active_time=StockNotice::pluck('active_time');
|
||||
$schedule->command(ChkReplenish::class);
|
||||
$schedule->command(ChkOrderServer::class)->everyFifteenMinutes();
|
||||
$schedule->command(ChkPriceearly::class)->everyFifteenMinutes();
|
||||
$schedule->command(ChkShelflife::class)->everyFifteenMinutes();
|
||||
// $schedule->command('check:priceearly')->dailyAt((string)$active_time[1]);
|
||||
// $schedule->command('check:shelflife')->dailyAt((string)$active_time[2]);
|
||||
// $schedule->command('check:orderServer')->everyFifteenMinutes();
|
||||
|
||||
$schedule->command(DailySalesReport::class, ['S1'])->dailyAt('12:00');
|
||||
$schedule->command(DailySalesReport::class, ['S2'])->dailyAt('13:30');
|
||||
$schedule->command(DailySalesReport::class, ['S3'])->dailyAt('15:00');
|
||||
$schedule->command(DailySalesReport::class, ['S4'])->dailyAt('16:00');
|
||||
$schedule->command(DailySalesReport::class, ['S5'])->dailyAt('17:30');
|
||||
$schedule->command(DailySalesReport::class, ['S6'])->dailyAt('20:00');
|
||||
$schedule->command(DailySalesReport::class, ['S7'])->dailyAt('09:30');
|
||||
|
||||
$schedule->command(DeleteKttQuery::class)->daily();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -48,7 +48,7 @@ class LoginController extends Controller
|
||||
public function login(Request $request)
|
||||
{
|
||||
$credentials = $request->only('name', 'password');
|
||||
|
||||
// dd($credentials);
|
||||
if (Auth::attempt($credentials)) {
|
||||
// 通过认证..
|
||||
return response()->json(['token' => $request->user()->api_token]);
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Helpers\ApiResponse;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
@ -9,7 +10,8 @@ use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests,ApiResponse;
|
||||
|
||||
|
||||
protected $res = [
|
||||
'httpCode' => 200,
|
||||
|
||||
@ -9,7 +9,6 @@ use App\Models\GoodsSku;
|
||||
use App\Models\Shop;
|
||||
use App\Http\Resources\ShopsResource;
|
||||
use App\Models\ShopSender;
|
||||
use App\Models\ShopShip;
|
||||
use App\Services\Business\KuaiTuanTuan\FaceSheet;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@ -20,6 +19,10 @@ use App\Models\BusinessOrderItem;
|
||||
|
||||
class ShopsController extends Controller
|
||||
{
|
||||
public function test()
|
||||
{
|
||||
return ["msg"=>'ok','code'=>200];
|
||||
}
|
||||
public function index(Request $request)
|
||||
{
|
||||
$shops = Shop::query()->filter()->paginate($request->get('per_page'));
|
||||
@ -228,18 +231,11 @@ class ShopsController extends Controller
|
||||
|
||||
public function pddPrintAuth(Request $request)
|
||||
{
|
||||
[$shopId, $platId] = explode('_', $request->get('state'));
|
||||
[$shopId, $type] = explode('_', $request->get('state'));
|
||||
$faceSheet = new FaceSheet();
|
||||
$faceSheet->setCode($request->get('code'));
|
||||
$faceSheet->setShopWithId($shopId);
|
||||
$faceSheet->auth('ship');
|
||||
$shopShip = ShopShip::query()
|
||||
->where('shop_id', $shopId)
|
||||
->first();
|
||||
if (empty($shopShip)) {
|
||||
exit();
|
||||
}
|
||||
$faceSheet->setShop($shopShip);
|
||||
$shopShip = $faceSheet->auth('ship', $type);
|
||||
$resp = $faceSheet->searchWayBill();
|
||||
if (!isset($resp['pdd_waybill_search_response']['waybill_apply_subscription_cols'])) {
|
||||
exit();
|
||||
|
||||
141
app/Http/Helpers/ApiResponse.php
Normal file
141
app/Http/Helpers/ApiResponse.php
Normal file
@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Helpers;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response as FoundationResponse;
|
||||
|
||||
trait ApiResponse
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $statusCode = FoundationResponse::HTTP_OK;
|
||||
protected $token = '';
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getStatusCode()
|
||||
{
|
||||
return $this->statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $statusCode
|
||||
* @return $this
|
||||
*/
|
||||
public function setStatusCode($statusCode)
|
||||
{
|
||||
$this->statusCode = $statusCode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $token
|
||||
* @return $this
|
||||
*/
|
||||
public function setToken($token)
|
||||
{
|
||||
$this->token = $token;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function respond($data)
|
||||
{
|
||||
$response = response()->json($data, $this->getStatusCode());
|
||||
if ($this->token) {
|
||||
$response->headers->set('Authorization', 'Bearer ' . $this->token);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $status
|
||||
* @param array $data
|
||||
* @param null $code
|
||||
* @return mixed
|
||||
*/
|
||||
public function status($status, array $data, $code = null)
|
||||
{
|
||||
if ($code) {
|
||||
$this->setStatusCode($code);
|
||||
}
|
||||
$status = [
|
||||
'status' => $status,
|
||||
'code' => $this->statusCode
|
||||
];
|
||||
|
||||
$data = array_merge($status, $data);
|
||||
return $this->respond($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param int $code
|
||||
* @param string $status
|
||||
* @return mixed
|
||||
*/
|
||||
public function failed($message, $code = FoundationResponse::HTTP_BAD_REQUEST, $status = 'error')
|
||||
{
|
||||
return $this->setStatusCode($code)->message($message, $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param string $status
|
||||
* @return mixed
|
||||
*/
|
||||
public function message($message, $status = "success")
|
||||
{
|
||||
if(!is_array($message)) {
|
||||
$message = [$message];
|
||||
}
|
||||
return $this->status($status, [
|
||||
'message' => $message
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @return mixed
|
||||
*/
|
||||
public function internalError($message = "Internal Error!")
|
||||
{
|
||||
return $this->failed($message, FoundationResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @return mixed
|
||||
*/
|
||||
public function created($message = "created")
|
||||
{
|
||||
return $this->setStatusCode(FoundationResponse::HTTP_CREATED)
|
||||
->message($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @param string $status
|
||||
* @return mixed
|
||||
*/
|
||||
public function success($data=[], $status = "success")
|
||||
{
|
||||
return $this->status($status, compact('data'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @return mixed
|
||||
*/
|
||||
public function notFond($message = 'Not Fond!')
|
||||
{
|
||||
return $this->failed($message, Foundationresponse::HTTP_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
114
app/Http/Helpers/ExceptionReport.php
Normal file
114
app/Http/Helpers/ExceptionReport.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Helpers;
|
||||
|
||||
use ErrorException;
|
||||
use Exception;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
|
||||
|
||||
class ExceptionReport
|
||||
{
|
||||
use ApiResponse;
|
||||
|
||||
/**
|
||||
* @var Exception
|
||||
*/
|
||||
public $exception;
|
||||
/**
|
||||
* @var Request
|
||||
*/
|
||||
public $request;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $report;
|
||||
|
||||
/**
|
||||
* ExceptionReport constructor.
|
||||
* @param Request $request
|
||||
* @param Exception $exception
|
||||
*/
|
||||
function __construct(Request $request, Exception $exception)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->exception = $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
//当抛出这些异常时,可以使用我们定义的错误信息与HTTP状态码
|
||||
//可以把常见异常放在这里
|
||||
public $doReport = [
|
||||
AuthenticationException::class => ['未登录或登录状态失效', 401],
|
||||
ModelNotFoundException::class => ['该模型未找到', 404],
|
||||
AuthorizationException::class => ['没有此权限', 403],
|
||||
ValidationException::class => [],
|
||||
UnauthorizedHttpException::class => ['未登录或登录状态失效', 401],
|
||||
// TokenInvalidException::class => ['未登录或登录状态失效', 401],
|
||||
NotFoundHttpException::class => ['没有找到该页面', 404],
|
||||
MethodNotAllowedHttpException::class => ['访问方式不正确', 405],
|
||||
ErrorException::class => ['服务器内部错误', 500],
|
||||
QueryException::class => ['参数错误', 400],
|
||||
];
|
||||
|
||||
public function register($className, callable $callback)
|
||||
{
|
||||
|
||||
$this->doReport[$className] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldReturn()
|
||||
{
|
||||
foreach (array_keys($this->doReport) as $report) {
|
||||
if ($this->exception instanceof $report) {
|
||||
$this->report = $report;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Exception $e
|
||||
* @return static
|
||||
*/
|
||||
public static function make(Exception $e)
|
||||
{
|
||||
|
||||
return new static(\request(), $e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function report()
|
||||
{
|
||||
if ($this->exception instanceof ValidationException) {
|
||||
return $this->failed(current($this->exception->errors()), $this->exception->status);
|
||||
}
|
||||
$message = $this->doReport[$this->report];
|
||||
return $this->failed($message[0], $message[1]);
|
||||
}
|
||||
|
||||
public function prodReport()
|
||||
{
|
||||
return $this->failed('服务器错误', '500');
|
||||
}
|
||||
}
|
||||
|
||||
255
app/Http/Libraries/ExcelUtil/export.php
Normal file
255
app/Http/Libraries/ExcelUtil/export.php
Normal file
@ -0,0 +1,255 @@
|
||||
<?php
|
||||
namespace App\Http\Libraries\ExcelUtil;
|
||||
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
use Maatwebsite\Excel\Concerns\WithEvents;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Events\AfterSheet;
|
||||
|
||||
class export implements FromCollection,WithHeadings, WithEvents
|
||||
{
|
||||
protected $data;
|
||||
protected $headings;
|
||||
protected $sheetName; //设置sheet页名称
|
||||
protected $columnWidth = [];//设置列宽 key:列 value:宽
|
||||
protected $rowHeight = []; //设置行高 key:行 value:高
|
||||
protected $mergeCells = []; //合并单元格 key:第一个单元格 value:第二个单元格
|
||||
protected $font = []; //设置字体 key:A1:K8 value:11
|
||||
protected $bold = []; //设置粗体 key:A1:K8 value:true
|
||||
protected $background = []; //设置背景颜色 key:A1:K8 value:#F0F0F0F
|
||||
protected $vertical = []; //设置定位 key:A1:K8 value:center
|
||||
protected $horizontal = []; //设置水平定位 key:A1:K8 value:center
|
||||
protected $wrapText = []; //设置是否自动换行 key:A1:K8 value:bool
|
||||
|
||||
|
||||
//设置页面属性时如果无效 更改excel格式尝试即可
|
||||
|
||||
//构造函数传值
|
||||
public function __construct($data, $headings)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->headings = $headings;
|
||||
$this->createData();
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return $this->headings;
|
||||
}
|
||||
|
||||
//数组转集合
|
||||
public function collection()
|
||||
{
|
||||
return new Collection($this->data);
|
||||
}
|
||||
//业务代码
|
||||
public function createData()
|
||||
{
|
||||
$this->data = collect($this->data)->toArray();
|
||||
}
|
||||
|
||||
public function registerEvents(): array
|
||||
{
|
||||
return [
|
||||
AfterSheet::class => function(AfterSheet $event) {
|
||||
//设置sheet页名称
|
||||
$event->getSheet()->getDelegate()->setTitle($this->sheetName);
|
||||
|
||||
//设置自动换行
|
||||
foreach ($this->wrapText as $column => $bool) {
|
||||
$event->sheet->getDelegate()
|
||||
->getStyle($column)
|
||||
->getAlignment()
|
||||
->setWrapText(true);
|
||||
}
|
||||
//设置列宽
|
||||
foreach ($this->columnWidth as $column => $width) {
|
||||
$event->sheet->getDelegate()
|
||||
->getColumnDimension($column)
|
||||
->setWidth($width);
|
||||
}
|
||||
//设置行高,$i为数据行数
|
||||
foreach ($this->rowHeight as $row => $height) {
|
||||
$event->sheet->getDelegate()
|
||||
->getRowDimension($row)
|
||||
->setRowHeight($height);
|
||||
}
|
||||
|
||||
//设置区域单元格垂直居中
|
||||
foreach ($this->vertical as $region => $position) {
|
||||
$event->sheet->getDelegate()
|
||||
->getStyle($region)
|
||||
->getAlignment()
|
||||
->setVertical($position);
|
||||
}
|
||||
|
||||
//设置区域单元格水平定位
|
||||
foreach ($this->horizontal as $region => $position) {
|
||||
$event->sheet->getDelegate()
|
||||
->getStyle($region)
|
||||
->getAlignment()
|
||||
->setHorizontal($position);
|
||||
}
|
||||
|
||||
//设置区域单元格字体
|
||||
foreach ($this->font as $region => $value) {
|
||||
$event->sheet->getDelegate()
|
||||
->getStyle($region)
|
||||
->getFont()
|
||||
->setSize($value);
|
||||
}
|
||||
|
||||
//设置区域单元格字体粗体
|
||||
foreach ($this->bold as $region => $bool) {
|
||||
$event->sheet->getDelegate()
|
||||
->getStyle($region)
|
||||
->getFont()
|
||||
->setBold($bool);
|
||||
}
|
||||
|
||||
|
||||
//设置区域单元格背景颜色
|
||||
foreach ($this->background as $region => $item) {
|
||||
$event->sheet->getDelegate()->getStyle($region)->applyFromArray([
|
||||
'fill' => [
|
||||
'fillType' => 'linear', //线性填充,类似渐变
|
||||
'startColor' => [
|
||||
'rgb' => $item //初始颜色
|
||||
],
|
||||
//结束颜色,如果需要单一背景色,请和初始颜色保持一致
|
||||
'endColor' => [
|
||||
'argb' => $item
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
//合并单元格
|
||||
foreach ($this->mergeCells as $start => $end) {
|
||||
$event->sheet->getDelegate()->mergeCells($start.':'.$end);
|
||||
}
|
||||
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @2020/3/22 10:33
|
||||
*/
|
||||
public function setSheetName(string $sheetName)
|
||||
{
|
||||
$this->sheetName = trim($sheetName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @2020/3/22 10:33
|
||||
* [
|
||||
* A1:K7 => true
|
||||
* ]
|
||||
*/
|
||||
public function setWrapText (array $wrapText)
|
||||
{
|
||||
$this->wrapText = array_change_key_case($this->symbol($wrapText),CASE_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @2020/3/22 10:33
|
||||
* [
|
||||
* A1:K7 => center
|
||||
* ]
|
||||
*/
|
||||
public function setVertical (array $vertical)
|
||||
{
|
||||
$this->vertical = array_change_key_case($this->symbol($vertical),CASE_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @2020/3/22 10:33
|
||||
* [
|
||||
* A1:K7 => center
|
||||
* ]
|
||||
*/
|
||||
public function setHorizontal (array $horizontal)
|
||||
{
|
||||
$this->horizontal = array_change_key_case($this->symbol($horizontal),CASE_UPPER);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @2020/3/22 10:33
|
||||
* [
|
||||
* 'B' => 40,
|
||||
* 'C' => 60
|
||||
* ]
|
||||
*/
|
||||
public function setColumnWidth (array $columnwidth)
|
||||
{
|
||||
$this->columnWidth = array_change_key_case($columnwidth, CASE_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @2020/3/22 10:33
|
||||
* [
|
||||
* 1 => 40,
|
||||
* 2 => 60
|
||||
* ]
|
||||
*/
|
||||
public function setRowHeight (array $rowHeight)
|
||||
{
|
||||
$this->rowHeight = $rowHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @2020/3/22 10:33
|
||||
* [
|
||||
* A1:K7 => 12
|
||||
* ]
|
||||
*/
|
||||
public function setFont (array $fount)
|
||||
{
|
||||
$this->font = array_change_key_case($fount, CASE_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @2020/3/22 10:33
|
||||
* [
|
||||
* A1:K7 => true
|
||||
* ]
|
||||
*/
|
||||
public function setBold (array $bold)
|
||||
{
|
||||
$this->bold = array_change_key_case($bold, CASE_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @2020/3/22 10:33
|
||||
* [
|
||||
* A1:K7 => F0FF0F
|
||||
* ]
|
||||
*/
|
||||
public function setBackground (array $background)
|
||||
{
|
||||
$this->background = array_change_key_case($background, CASE_UPPER);
|
||||
}
|
||||
|
||||
|
||||
public function symbol ($param) {
|
||||
$record = [];
|
||||
$count = count($this->data) + 1;//加上表头
|
||||
foreach ($param as $key => $value) {
|
||||
$str = str_replace("*", $count, $key);
|
||||
$record[$str] = $value;
|
||||
}
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
29
app/Http/Libraries/ExcelUtil/import.php
Normal file
29
app/Http/Libraries/ExcelUtil/import.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Libraries\ExcelUtil;
|
||||
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Maatwebsite\Excel\Concerns\ToCollection;
|
||||
|
||||
class import implements ToCollection
|
||||
{
|
||||
public $data;
|
||||
protected $delTitle;
|
||||
public function __construct($delTitle = 1)
|
||||
{
|
||||
$this->delTitle = $delTitle;
|
||||
}
|
||||
|
||||
|
||||
public function collection(Collection $rows)
|
||||
{
|
||||
$this->delTitle($rows);
|
||||
//$rows 是数组格式
|
||||
$this->data = $rows;
|
||||
}
|
||||
|
||||
public function delTitle (&$rows) {
|
||||
$rows = $rows->slice($this->delTitle)->values();
|
||||
}
|
||||
}
|
||||
22
app/Models/BusinessOrderServer.php
Normal file
22
app/Models/BusinessOrderServer.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
class BusinessOrderServer extends Model
|
||||
{
|
||||
|
||||
protected $table='business_order_server';
|
||||
public $timestamps = false;
|
||||
protected $dates = ['lasted_at'];
|
||||
public function save(array $options = [])
|
||||
{
|
||||
if(!$this->exists) {
|
||||
} else {
|
||||
$this->lasted_at = Carbon::now();
|
||||
}
|
||||
parent::save($options);
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
class GoodsType extends Model
|
||||
{
|
||||
protected $table='goods_types';
|
||||
/**
|
||||
* 数组中的属性会被隐藏。
|
||||
*
|
||||
|
||||
11
app/Models/MessageStock.php
Normal file
11
app/Models/MessageStock.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
class MessageStock extends Model
|
||||
{
|
||||
|
||||
protected $table='message_stock';
|
||||
}
|
||||
11
app/Models/StockNotice.php
Normal file
11
app/Models/StockNotice.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class StockNotice extends Model
|
||||
{
|
||||
|
||||
protected $table='stock_notice';
|
||||
}
|
||||
10
app/Models/StockTackItem.php
Normal file
10
app/Models/StockTackItem.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
class StockTackItem extends Model
|
||||
{
|
||||
protected $table='stock_tack_item';
|
||||
}
|
||||
11
app/Models/Supplier.php
Normal file
11
app/Models/Supplier.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Supplier extends Model
|
||||
{
|
||||
protected $table='supplier';
|
||||
|
||||
}
|
||||
11
app/Models/SupplierType.php
Normal file
11
app/Models/SupplierType.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class SupplierType extends Model
|
||||
{
|
||||
|
||||
protected $table='supplier_type';
|
||||
}
|
||||
11
app/Models/WarehouseStock.php
Normal file
11
app/Models/WarehouseStock.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class WarehouseStock extends Model
|
||||
{
|
||||
protected $table='warehouse_stock';
|
||||
|
||||
}
|
||||
11
app/Models/WarehouseStockItem.php
Normal file
11
app/Models/WarehouseStockItem.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class WarehouseStockItem extends Model
|
||||
{
|
||||
protected $table='warehouse_stock_item';
|
||||
|
||||
}
|
||||
912
app/Pool/Core/Redis.php
Normal file
912
app/Pool/Core/Redis.php
Normal file
@ -0,0 +1,912 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Pool\Core;
|
||||
|
||||
class Redis
|
||||
{
|
||||
protected $redis;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->redis = app('redis.connection');
|
||||
$this->redis->auth(env('REDIS_PASSWORD','123456'));
|
||||
}
|
||||
|
||||
/*****************hash表操作函数*******************/
|
||||
|
||||
/**
|
||||
* hGet 得到hash表中一个字段的值
|
||||
* @param string $key 缓存key
|
||||
* @param string $field 字段
|
||||
* @return mixed string|false
|
||||
*/
|
||||
public function hGet($key, $field)
|
||||
{
|
||||
return $this->redis->hGet($key, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为hash表设定一个字段的值
|
||||
* @param string $key 缓存key
|
||||
* @param string $field 字段
|
||||
* @param string $value 值。
|
||||
* @return bool
|
||||
*/
|
||||
public function hSet($key, $field, $value)
|
||||
{
|
||||
return $this->redis->hSet($key,$field,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* hExists 判断hash表中,指定field是不是存在
|
||||
* @param string $key 缓存key
|
||||
* @param string $field 字段
|
||||
* @return bool
|
||||
*/
|
||||
public function hExists($key, $field)
|
||||
{
|
||||
return $this->redis->hExists($key, $field);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hDel 删除hash表中指定字段 ,支持批量删除
|
||||
* @param string $key 缓存key
|
||||
* @param string $field 字段
|
||||
* @return int
|
||||
*/
|
||||
public function hDel($key, $field)
|
||||
{
|
||||
$fieldArr = explode(',', $field);
|
||||
$delNum = 0;
|
||||
|
||||
foreach($fieldArr as $row)
|
||||
{
|
||||
$row = trim($row);
|
||||
$delNum += $this->redis->hDel($key,$row);
|
||||
}
|
||||
|
||||
return $delNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* hLen 返回hash表元素个数
|
||||
* @param string $key 缓存key
|
||||
* @return int|bool
|
||||
*/
|
||||
public function hLen($key)
|
||||
{
|
||||
return $this->redis->hLen($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* hSetNx 为hash表设定一个字段的值,如果字段存在,返回false
|
||||
* @param string $key 缓存key
|
||||
* @param string $field 字段
|
||||
* @param string $value 值。
|
||||
* @return bool
|
||||
*/
|
||||
public function hSetNx($key, $field, $value)
|
||||
{
|
||||
return $this->redis->hSetNx($key, $field, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* hMset 为hash表多个字段设定值。
|
||||
* @param string $key
|
||||
* @param array $value
|
||||
* @return array|bool
|
||||
*/
|
||||
public function hMset($key, $value)
|
||||
{
|
||||
if(!is_array($value))
|
||||
return false;
|
||||
return $this->redis->hMset($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* hMget 为hash表多个字段设定值。
|
||||
* @param string $key
|
||||
* @param array|string $value string以','号分隔字段
|
||||
* @return array|bool
|
||||
*/
|
||||
public function hMget($key, $value)
|
||||
{
|
||||
if(!is_array($value))
|
||||
$value = explode(',', $value);
|
||||
return $this->redis->hMget($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* hIncrBy 为hash表设这累加,可以负数
|
||||
* @param string $key
|
||||
* @param int $field
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public function hIncrBy($key, $field, $value)
|
||||
{
|
||||
$value = intval($value);
|
||||
return $this->redis->hIncrBy($key, $field, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* hKeys 返回所有hash表的所有字段
|
||||
* @param string $key
|
||||
* @return array|bool
|
||||
*/
|
||||
public function hKeys($key)
|
||||
{
|
||||
return $this->redis->hKeys($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* hVals 返回所有hash表的字段值,为一个索引数组
|
||||
* @param string $key
|
||||
* @return array|bool
|
||||
*/
|
||||
public function hVals($key)
|
||||
{
|
||||
return $this->redis->hVals($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* hGetAll 返回所有hash表的字段值,为一个关联数组
|
||||
* @param string $key
|
||||
* @return array|bool
|
||||
*/
|
||||
public function hGetAll($key)
|
||||
{
|
||||
return $this->redis->hGetAll($key);
|
||||
}
|
||||
|
||||
/*********************有序集合操作*********************/
|
||||
|
||||
/**
|
||||
* zAdd 给当前集合添加一个元素
|
||||
* 如果value已经存在,会更新order的值。
|
||||
* @param string $key
|
||||
* @param string $order 序号
|
||||
* @param string $value 值
|
||||
* @return bool
|
||||
*/
|
||||
public function zAdd($key, $order, $value)
|
||||
{
|
||||
return $this->redis->zAdd($key, $order, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* zincrby 给$value成员的order值,增加$num,可以为负数
|
||||
* @param string $key
|
||||
* @param string $num 序号
|
||||
* @param string $value 值
|
||||
* @return mixed 返回新的order
|
||||
*/
|
||||
public function zincrby($key, $num, $value)
|
||||
{
|
||||
return $this->redis->zincrby($key, $num, $value);
|
||||
}
|
||||
public function incrby($key, $num=1)
|
||||
{
|
||||
return $this->redis->incrby($key,$num);
|
||||
}
|
||||
|
||||
/**
|
||||
* zRem 删除值为value的元素
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public function zRem($key, $value)
|
||||
{
|
||||
return $this->redis->zRem($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* zRange 集合以order递增排列后,0表示第一个元素,-1表示最后一个元素
|
||||
* @param string $key
|
||||
* @param int $start
|
||||
* @param int $end
|
||||
* @return mixed array|bool
|
||||
*/
|
||||
public function zRange($key, $start, $end)
|
||||
{
|
||||
return $this->redis->zRange($key, $start, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
* zRevRange 集合以order递减排列后,0表示第一个元素,-1表示最后一个元素
|
||||
* @param string $key
|
||||
* @param int $start
|
||||
* @param int $end
|
||||
* @return array|bool
|
||||
*/
|
||||
public function zRevRange($key, $start, $end)
|
||||
{
|
||||
return $this->redis->zRevRange($key, $start, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
* 集合以order递增排列后,返回指定order之间的元素。
|
||||
* min和max可以是-inf和+inf 表示最大值,最小值
|
||||
* @param string $key
|
||||
* @param int $start '-inf'
|
||||
* @param int $end "+inf"
|
||||
* @param array $option 参数 package
|
||||
* withscores=>true,表示数组下标为Order值,默认返回索引数组
|
||||
* limit=>array(0,1) 表示从0开始,取一条记录。
|
||||
* @return array|bool
|
||||
*/
|
||||
public function zRangeByScore($key, $start = 0, $end = 0, $option = [])
|
||||
{
|
||||
return $this->redis->zRangeByScore($key, $start, $end, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* 集合以order递减排列后,返回指定order之间的元素。
|
||||
* min和max可以是-inf和+inf 表示最大值,最小值
|
||||
* @param string $key
|
||||
* @param int $start '-inf'
|
||||
* @param int $end "+inf"
|
||||
* @param array $option 参数 package
|
||||
* withscores=>true,表示数组下标为Order值,默认返回索引数组
|
||||
* limit=>array(0,1) 表示从0开始,取一条记录。
|
||||
* @return array|bool
|
||||
*/
|
||||
public function zRevRangeByScore($key, $start = 0, $end = 0, $option = [])
|
||||
{
|
||||
return $this->redis->zRevRangeByScore($key,$start,$end,$option);
|
||||
}
|
||||
|
||||
/**
|
||||
* zCount 返回order值在start end之间的数量
|
||||
* @param $key
|
||||
* @param $start
|
||||
* @param $end
|
||||
* @return mixed
|
||||
*/
|
||||
public function zCount($key, $start, $end)
|
||||
{
|
||||
return $this->redis->zCount($key, $start, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
* zScore 返回值为value的order值
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function zScore($key, $value)
|
||||
{
|
||||
return $this->redis->zScore($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* zRank 返回集合以score递增加排序后,指定成员的排序号,从0开始。
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function zRank($key,$value)
|
||||
{
|
||||
return $this->redis->zRank($key,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* zRevRank 返回集合以score递增加排序后,指定成员的排序号,从0开始。
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function zRevRank($key,$value)
|
||||
{
|
||||
return $this->redis->zRevRank($key,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* zRemRangeByScore 删除集合中,score值在start end之间的元素 包括start end
|
||||
* min和max可以是-inf和+inf 表示最大值,最小值
|
||||
* @param $key
|
||||
* @param $start
|
||||
* @param $end
|
||||
* @return mixed 删除成员的数量
|
||||
*/
|
||||
public function zRemRangeByScore($key,$start,$end)
|
||||
{
|
||||
return $this->redis->zRemRangeByScore($key,$start,$end);
|
||||
}
|
||||
|
||||
/**
|
||||
* zCard 返回集合元素个数
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function zCard($key)
|
||||
{
|
||||
return $this->redis->zCard($key);
|
||||
}
|
||||
/*********************队列操作命令************************/
|
||||
|
||||
/**
|
||||
* rPush 在队列尾部插入一个元素
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed 返回队列长度
|
||||
*/
|
||||
public function rPush($key,$value)
|
||||
{
|
||||
return $this->redis->rPush($key,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* rPushx 在队列尾部插入一个元素 如果key不存在,什么也不做
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed 返回队列长度
|
||||
*/
|
||||
public function rPushx($key,$value)
|
||||
{
|
||||
return $this->redis->rPushx($key,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* lPush 在队列头部插入一个元素
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed 返回队列长度
|
||||
*/
|
||||
public function lPush($key,$value)
|
||||
{
|
||||
return $this->redis->lPush($key,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* lPushx 在队列头插入一个元素 如果key不存在,什么也不做
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed 返回队列长度
|
||||
*/
|
||||
public function lPushx($key,$value)
|
||||
{
|
||||
return $this->redis->lPushx($key,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* lLen 返回队列长度
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function lLen($key)
|
||||
{
|
||||
return $this->redis->lLen($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* lRange 返回队列指定区间的元素
|
||||
* @param $key
|
||||
* @param $start
|
||||
* @param $end
|
||||
* @return mixed
|
||||
*/
|
||||
public function lRange($key,$start,$end)
|
||||
{
|
||||
return $this->redis->lrange($key,$start,$end);
|
||||
}
|
||||
|
||||
/**
|
||||
* lIndex 返回队列中指定索引的元素
|
||||
* @param $key
|
||||
* @param $index
|
||||
* @return mixed
|
||||
*/
|
||||
public function lIndex($key,$index)
|
||||
{
|
||||
return $this->redis->lIndex($key,$index);
|
||||
}
|
||||
|
||||
/**
|
||||
* lSet 设定队列中指定index的值。
|
||||
* @param $key
|
||||
* @param $index
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function lSet($key,$index,$value)
|
||||
{
|
||||
return $this->redis->lSet($key,$index,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* lRem 删除值为value的count个元素
|
||||
* PHP-REDIS扩展的数据顺序与命令的顺序不太一样,不知道是不是bug
|
||||
* count>0 从尾部开始
|
||||
* >0 从头部开始
|
||||
* =0 删除全部
|
||||
* @param $key
|
||||
* @param $count
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function lRem($key,$count,$value)
|
||||
{
|
||||
return $this->redis->lRem($key,$value,$count);
|
||||
}
|
||||
|
||||
/**
|
||||
* lPop 删除并返回队列中的头元素
|
||||
* Created by PhpStorm.
|
||||
* User: w
|
||||
* Date: 2018-12-09
|
||||
* Time: 12:13
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function lPop($key)
|
||||
{
|
||||
return $this->redis->lPop($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* rPop 删除并返回队列中的尾元素
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function rPop($key)
|
||||
{
|
||||
return $this->redis->rPop($key);
|
||||
}
|
||||
|
||||
/*************redis字符串操作命令*****************/
|
||||
|
||||
/**
|
||||
* set 设置一个key
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function set($key,$value)
|
||||
{
|
||||
return $this->redis->set($key,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* get 得到一个key
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
return $this->redis->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* setex 设置一个有过期时间的key
|
||||
* @param $key
|
||||
* @param $expire
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function setex($key,$expire,$value)
|
||||
{
|
||||
return $this->redis->setex($key,$expire,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* setnx 设置一个key,如果key存在,不做任何操作.
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function setnx($key,$value)
|
||||
{
|
||||
return $this->redis->setnx($key,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* mset 批量设置key
|
||||
* @param $arr
|
||||
* @return mixed
|
||||
*/
|
||||
public function mset($arr)
|
||||
{
|
||||
return $this->redis->mset($arr);
|
||||
}
|
||||
|
||||
/*************redis 无序集合操作命令*****************/
|
||||
|
||||
/**
|
||||
* sMembers 返回集合中所有元素
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function sMembers($key)
|
||||
{
|
||||
return $this->redis->sMembers($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* sDiff 求2个集合的差集
|
||||
* @param $key1
|
||||
* @param $key2
|
||||
* @return mixed
|
||||
*/
|
||||
public function sDiff($key1,$key2)
|
||||
{
|
||||
return $this->redis->sDiff($key1,$key2);
|
||||
}
|
||||
|
||||
/**
|
||||
* sAdd 添加集合。由于版本问题,扩展不支持批量添加。
|
||||
* @param $key
|
||||
* @param string|array $value
|
||||
*/
|
||||
public function sAdd($key,$value)
|
||||
{
|
||||
if(!is_array($value))
|
||||
$arr = array($value);
|
||||
else
|
||||
$arr = $value;
|
||||
|
||||
foreach($arr as $row)
|
||||
$this->redis->sAdd($key,$row);
|
||||
}
|
||||
|
||||
/**
|
||||
* scard 返回无序集合的元素个数
|
||||
* Created by PhpStorm.
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function scard($key)
|
||||
{
|
||||
return $this->redis->scard($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* srem 从集合中删除一个元素
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function srem($key,$value)
|
||||
{
|
||||
return $this->redis->srem($key,$value);
|
||||
}
|
||||
|
||||
/*************redis管理操作命令*****************/
|
||||
|
||||
/**
|
||||
* 选择数据库
|
||||
* @param int $dbId 数据库ID号
|
||||
* @return bool
|
||||
*/
|
||||
public function select($dbId)
|
||||
{
|
||||
$this->dbId = $dbId;
|
||||
return $this->redis->select($dbId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空当前数据库
|
||||
* @return bool
|
||||
*/
|
||||
public function flushDB()
|
||||
{
|
||||
return $this->redis->flushDB();
|
||||
}
|
||||
|
||||
/**
|
||||
* info 返回当前库状态
|
||||
* @return string
|
||||
*/
|
||||
public function info()
|
||||
{
|
||||
return $this->redis->info();
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步保存数据到磁盘
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
return $this->redis->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步保存数据到磁盘
|
||||
*/
|
||||
public function bgSave()
|
||||
{
|
||||
return $this->redis->bgSave();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回最后保存到磁盘的时间
|
||||
*/
|
||||
public function lastSave()
|
||||
{
|
||||
return $this->redis->lastSave();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回key,支持*多个字符,?一个字符
|
||||
* 只有* 表示全部
|
||||
* @param string $key
|
||||
* @return array
|
||||
*/
|
||||
public function keys($key)
|
||||
{
|
||||
return $this->redis->keys($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* del 删除指定key
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function del($key)
|
||||
{
|
||||
return $this->redis->del($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* exists 判断一个key值是不是存在
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
return $this->redis->exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* expire 为一个key设定过期时间 单位为秒
|
||||
* @param $key
|
||||
* @param $expire
|
||||
* @return mixed
|
||||
*/
|
||||
public function expire($key,$expire)
|
||||
{
|
||||
return $this->redis->expire($key,$expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* ttl 返回一个key还有多久过期,单位秒
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function ttl($key)
|
||||
{
|
||||
return $this->redis->ttl($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* expireAt 设定一个key什么时候过期,time为一个时间戳
|
||||
* @param $key
|
||||
* @param $time
|
||||
* @return mixed
|
||||
*/
|
||||
public function expireAt($key,$time)
|
||||
{
|
||||
return $this->redis->expireAt($key,$time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭服务器链接
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
return $this->redis->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭所有连接
|
||||
*/
|
||||
public static function closeAll()
|
||||
{
|
||||
foreach(static::$_instance as $o)
|
||||
{
|
||||
if($o instanceof self)
|
||||
$o->close();
|
||||
}
|
||||
}
|
||||
|
||||
/** 这里不关闭连接,因为session写入会在所有对象销毁之后。
|
||||
public function __destruct()
|
||||
{
|
||||
return $this->redis->close();
|
||||
}
|
||||
**/
|
||||
/**
|
||||
* 返回当前数据库key数量
|
||||
*/
|
||||
public function dbSize()
|
||||
{
|
||||
return $this->redis->dbSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回一个随机key
|
||||
*/
|
||||
public function randomKey()
|
||||
{
|
||||
return $this->redis->randomKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前数据库ID
|
||||
* @return int
|
||||
*/
|
||||
public function getDbId()
|
||||
{
|
||||
return $this->dbId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前密码
|
||||
*/
|
||||
public function getAuth()
|
||||
{
|
||||
return $this->auth;
|
||||
}
|
||||
|
||||
public function getHost()
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
public function getPort()
|
||||
{
|
||||
return $this->port;
|
||||
}
|
||||
|
||||
public function getConnInfo()
|
||||
{
|
||||
return [
|
||||
'host' => $this->host,
|
||||
'port' => $this->port,
|
||||
'auth' => $this->auth
|
||||
];
|
||||
}
|
||||
/*********************事务的相关方法************************/
|
||||
|
||||
/**
|
||||
* watch 监控key,就是一个或多个key添加一个乐观锁
|
||||
* 在此期间如果key的值如果发生的改变,刚不能为key设定值
|
||||
* 可以重新取得Key的值。
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function watch($key)
|
||||
{
|
||||
return $this->redis->watch($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消当前链接对所有key的watch
|
||||
* EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了
|
||||
*/
|
||||
public function unwatch()
|
||||
{
|
||||
return $this->redis->unwatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* multi 开启一个事务
|
||||
* 事务的调用有两种模式Redis::MULTI和Redis::PIPELINE,
|
||||
* 默认是Redis::MULTI 模式,
|
||||
* Redis::PIPELINE管道模式速度更快,但没有任何保证原子性有可能造成数据的丢失
|
||||
* @param $type
|
||||
* @return mixed
|
||||
*/
|
||||
public function multi($type = \Redis::MULTI)
|
||||
{
|
||||
return $this->redis->multi($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行一个事务
|
||||
* 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
return $this->redis->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* 回滚一个事务
|
||||
*/
|
||||
public function discard()
|
||||
{
|
||||
return $this->redis->discard();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试当前链接是不是已经失效
|
||||
* 没有失效返回+PONG
|
||||
* 失效返回false
|
||||
*/
|
||||
public function ping()
|
||||
{
|
||||
return $this->redis->ping();
|
||||
}
|
||||
|
||||
public function auth($auth)
|
||||
{
|
||||
return $this->redis->auth($auth);
|
||||
}
|
||||
|
||||
/*********************自定义的方法,用于简化操作************************/
|
||||
|
||||
/**
|
||||
* hashAll 得到一组的ID号
|
||||
* @param $prefix
|
||||
* @param $ids
|
||||
* @return array|bool
|
||||
*/
|
||||
public function hashAll($prefix,$ids)
|
||||
{
|
||||
if($ids == false)
|
||||
return false;
|
||||
|
||||
if( is_string($ids) )
|
||||
$ids = explode(',', $ids);
|
||||
|
||||
$arr = [];
|
||||
foreach($ids as $id) {
|
||||
$key = $prefix.'.'.$id;
|
||||
$res = $this->hGetAll($key);
|
||||
if($res != false)
|
||||
$arr[] = $res;
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* pushMessage 生成一条消息,放在redis数据库中。使用0号库。
|
||||
* @param $lkey
|
||||
* @param string|array $msg
|
||||
* @return string
|
||||
*/
|
||||
public function pushMessage($lkey, $msg)
|
||||
{
|
||||
if(is_array($msg))
|
||||
$msg = json_encode($msg);
|
||||
|
||||
$key = md5($msg);
|
||||
|
||||
//如果消息已经存在,删除旧消息,已当前消息为准
|
||||
//echo $n=$this->lRem($lkey, 0, $key)."\n";
|
||||
//重新设置新消息
|
||||
$this->lPush($lkey, $key);
|
||||
$this->setex($key, 3600, $msg);
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* delKeys 得到条批量删除key的命令
|
||||
* @param $keys
|
||||
* @param $dbId
|
||||
* @return string
|
||||
*/
|
||||
public function delKeys($keys,$dbId)
|
||||
{
|
||||
$redisInfo = $this->getConnInfo();
|
||||
$cmdArr = [
|
||||
'redis-cli',
|
||||
'-a',
|
||||
$redisInfo['auth'],
|
||||
'-h',
|
||||
$redisInfo['host'],
|
||||
'-p',
|
||||
$redisInfo['port'],
|
||||
'-n',
|
||||
$dbId,
|
||||
];
|
||||
$redisStr = implode(' ', $cmdArr);
|
||||
$cmd = "{$redisStr} KEYS \"{$keys}\" | xargs {$redisStr} del";
|
||||
return $cmd;
|
||||
}
|
||||
}
|
||||
@ -7,12 +7,15 @@ use App\Events\BusinessOrdersUpdate;
|
||||
use App\Models\BusinessGoodsSku;
|
||||
use App\Models\BusinessOrder;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\BusinessOrderServer;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\Log;
|
||||
use App\Models\Shop;
|
||||
use App\Pool\Core\Redis;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use GuzzleHttp\Promise;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log as LogFile;
|
||||
|
||||
abstract class BusinessClient
|
||||
@ -37,6 +40,7 @@ abstract class BusinessClient
|
||||
abstract public function incrQuantity($businessGoodsSku, $num, $incremental);
|
||||
|
||||
abstract public function downloadOrdersAndSave($beginTime, $endTime, $downloadType = 'default', $page = 1);
|
||||
abstract public function downloadOrdersAndSaveServer($beginTime, $endTime, $page = 1);
|
||||
|
||||
public function saveOrders($orders)
|
||||
{
|
||||
@ -101,6 +105,41 @@ abstract class BusinessClient
|
||||
$orderRecord->save();
|
||||
}
|
||||
}
|
||||
public function saveOrdersServer($orders)
|
||||
{
|
||||
$shopId = $this->getShop()->id;
|
||||
$model=new BusinessOrderServer();
|
||||
$redis=new Redis();
|
||||
foreach ($orders as $k=>$v){
|
||||
$key='orderReturn::'.$v['order_sn'];
|
||||
if (!$redis->exists($key)){
|
||||
$redis->set($key,md5(json_encode($v)));
|
||||
$model->shop_id=$shopId;
|
||||
// $model->refund_amount=number_format($v['apply_extension']['refund_amount']/100,2);
|
||||
$model->refund_amount=$v['apply_extension']['refund_amount'];
|
||||
$model->refund_shipping_amount=$v['apply_extension']['refund_shipping_amount'];
|
||||
$model->description=$v['apply_extension']['description'];
|
||||
$model->reason=$v['apply_extension']['reason'];
|
||||
$model->sub_extensions=isset($v['apply_extension']['sub_extensions'])?json_encode($v['apply_extension']['sub_extensions']):'';
|
||||
$model->order_sn=$v['order_sn'];
|
||||
$model->after_sales_status=$v['after_sales_status'];
|
||||
$model->apply_type=$v['apply_type'];
|
||||
$model->created_at=$v['created_at'];
|
||||
$model->updated_at=$v['updated_at'];
|
||||
$model->save();
|
||||
if (isset($v['apply_extension']['sub_extensions'])){
|
||||
$arr=$v['apply_extension']['sub_extensions'];
|
||||
foreach ($arr as $k1=>$v1){
|
||||
$v1[$k1]['shop_id']=$shopId;
|
||||
$v1[$k1]['order_sn']=$v['order_sn'];
|
||||
$v1[$k1]['business_order_server_id']=$model->id;
|
||||
}
|
||||
DB::table('business_order_server_item')->insert($arr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function authCallback($code, $shop)
|
||||
{
|
||||
@ -156,12 +195,12 @@ abstract class BusinessClient
|
||||
if (strlen($paramsJson) > 1024) {
|
||||
$paramsJson = '';
|
||||
}
|
||||
if (!in_array($params['type'], ['pdd.ktt.increment.order.query', 'pdd.ktt.order.list'], true)) {
|
||||
if (!in_array($params['type'], ['pdd.ktt.increment.order.query', 'pdd.ktt.order.list','pdd.ktt.after.sales.increment.list'], true)) {
|
||||
$log = new Log();
|
||||
$log->module = 'plat';
|
||||
$log->action = $method;
|
||||
$log->target_type = $this->getShop()->plat_id . '--' . $this->getShop()->name;
|
||||
$log->target_id = $this->getShop()->id;
|
||||
$log->target_type = 2 . '--' . '花甜悦事';
|
||||
$log->target_id = 2;
|
||||
$log->target_field = $params['type'];
|
||||
$log->user_id = Auth::id() ?? 999;
|
||||
if ($size < 48000) {
|
||||
@ -171,7 +210,7 @@ abstract class BusinessClient
|
||||
}
|
||||
$log->save();
|
||||
}
|
||||
if (in_array($params['type'], ['pdd.ktt.increment.order.query', 'pdd.ktt.order.list'], true)) {
|
||||
if (in_array($params['type'], ['pdd.ktt.increment.order.query', 'pdd.ktt.order.list','pdd.ktt.after.sales.increment.list'], true)) {
|
||||
LogFile::info('快团团请求: ' . $paramsJson);
|
||||
LogFile::info('快团团返回: ' . json_encode($res, 256));
|
||||
}
|
||||
|
||||
@ -122,6 +122,23 @@ class KuaiTuanTuan extends BusinessClient
|
||||
$this->downloadOrdersAndSave($beginTime, $endTime, $downloadType, $page + 1);
|
||||
}
|
||||
}
|
||||
public function downloadOrdersAndSaveServer($beginTime, $endTime, $page = 1)
|
||||
{
|
||||
[$type, $appendParams] = OrderServer::getIncrementOrdersServer($beginTime, $endTime, $page);
|
||||
$responseName = 'ktt_after_sales_incermet_list_response';
|
||||
$res = $this->doRequest($type, $appendParams);
|
||||
if (!isset($res[$responseName])) {
|
||||
return;
|
||||
}
|
||||
$this->saveOrdersServer($res[$responseName]['list']);
|
||||
if ($res[$responseName]['has_next']==false){
|
||||
return;
|
||||
}
|
||||
$pageNum = ceil($res[$responseName]['total_count'] / $appendParams['page_size']);
|
||||
if ($pageNum > $page && 30 >= $page) {
|
||||
$this->downloadOrdersAndSaveServer($beginTime, $endTime, $page + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public function getOrderInfo($orderSn)
|
||||
{
|
||||
|
||||
@ -92,5 +92,6 @@ class Order
|
||||
|
||||
return [$type, $appendParams];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
20
app/Services/Business/KuaiTuanTuan/OrderServer.php
Normal file
20
app/Services/Business/KuaiTuanTuan/OrderServer.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Services\Business\KuaiTuanTuan;
|
||||
class OrderServer
|
||||
{
|
||||
|
||||
public static function getIncrementOrdersServer($beginTime, $endTime, $page = 1)
|
||||
{
|
||||
$type = 'pdd.ktt.after.sales.increment.list';
|
||||
$appendParams = [
|
||||
'start_updated_at' => $beginTime, // 更新起始时间
|
||||
'end_updated_at' => $endTime, // 更新结束时间
|
||||
'page_number' => $page, // 页码
|
||||
'page_size' => 100, // 数量
|
||||
];
|
||||
|
||||
return [$type, $appendParams];
|
||||
}
|
||||
}
|
||||
@ -2,11 +2,15 @@
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
use App\Imports\CombinationGoodsImport;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Intervention\Image\Facades\Image;
|
||||
use Maatwebsite\Excel\Events\ImportFailed;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use OSS\Core\OssException;
|
||||
use OSS\OssClient;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Http\Libraries\ExcelUtil\import;
|
||||
|
||||
class UploadUtils
|
||||
{
|
||||
@ -119,5 +123,19 @@ class UploadUtils
|
||||
{
|
||||
return config('filesystems.disks.aliyun.url') . $filePath;
|
||||
}
|
||||
public static function uploadExcel ($file){
|
||||
if($file->isValid()){
|
||||
$vailExtension = ['xlsx','xls'];
|
||||
if(! in_array($file->getClientOriginalExtension() ,$vailExtension) ){
|
||||
throw new \Exception("文件格式错误");
|
||||
}
|
||||
|
||||
// return Excel::toArray(new Import, $file)[0];
|
||||
return Excel::toArray($file)[0];
|
||||
}else{
|
||||
throw new \Exception("文件无效");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"laravel/framework": "^6.20.26",
|
||||
"laravel/tinker": "^2.5",
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"predis/predis": "^2.2",
|
||||
"spatie/laravel-permission": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
|
||||
69
composer.lock
generated
69
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "037b06c1b26399725a1d9c0687402942",
|
||||
"content-hash": "964631bbee47f895975146a783331c50",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aliyuncs/oss-sdk-php",
|
||||
@ -2587,6 +2587,73 @@
|
||||
],
|
||||
"time": "2022-07-30T15:51:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "predis/predis",
|
||||
"version": "v2.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/predis/predis.git",
|
||||
"reference": "b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/predis/predis/zipball/b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1",
|
||||
"reference": "b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.3",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^8.0 || ~9.4.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-relay": "Faster connection with in-memory caching (>=0.6.2)"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Predis\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Till Krüss",
|
||||
"homepage": "https://till.im",
|
||||
"role": "Maintainer"
|
||||
}
|
||||
],
|
||||
"description": "A flexible and feature-complete Redis client for PHP.",
|
||||
"homepage": "http://github.com/predis/predis",
|
||||
"keywords": [
|
||||
"nosql",
|
||||
"predis",
|
||||
"redis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/predis/predis/issues",
|
||||
"source": "https://github.com/predis/predis/tree/v2.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/tillkruss",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-13T16:42:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "1.1.1",
|
||||
|
||||
@ -58,8 +58,16 @@ return [
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'modes' => [
|
||||
'STRICT_ALL_TABLES',
|
||||
'ERROR_FOR_DIVISION_BY_ZERO',
|
||||
'NO_ZERO_DATE',
|
||||
'NO_ZERO_IN_DATE',
|
||||
'NO_AUTO_CREATE_USER',
|
||||
],
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET sql_mode=(SELECT REPLACE(@@sql_mode, "ONLY_FULL_GROUP_BY", ""))'
|
||||
]) : [],
|
||||
],
|
||||
|
||||
|
||||
5
resources/frontend/.env
Normal file
5
resources/frontend/.env
Normal file
@ -0,0 +1,5 @@
|
||||
# VUE_APP_BASE_URL=http://cf-erp.com
|
||||
VUE_APP_BASE_URL=https://erp.lookthere.cn
|
||||
VUE_APP_BASE_URL_UPLOAD=http://cf-erp.com/upload/
|
||||
VUE_APP_API_PROXY_PREFIX=/api
|
||||
VUE_APP_API_NODE=development
|
||||
@ -10,9 +10,13 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"echarts": "^5.5.0",
|
||||
"element-china-area-data": "^6.1.0",
|
||||
"element-ui": "^2.15.6",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "^3.4.4",
|
||||
"nprogress": "^0.2.0",
|
||||
"qs": "^6.12.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0",
|
||||
"vue-socket.io": "^3.0.10",
|
||||
|
||||
BIN
resources/frontend/src/assets/img/avatar.png
Normal file
BIN
resources/frontend/src/assets/img/avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
BIN
resources/frontend/src/assets/img/error.png
Normal file
BIN
resources/frontend/src/assets/img/error.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
BIN
resources/frontend/src/assets/img/ic_bike.png
Normal file
BIN
resources/frontend/src/assets/img/ic_bike.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
resources/frontend/src/assets/img/original.png
Normal file
BIN
resources/frontend/src/assets/img/original.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
BIN
resources/frontend/src/assets/img/sucess.png
Normal file
BIN
resources/frontend/src/assets/img/sucess.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
490
resources/frontend/src/assets/scss/_base.scss
vendored
Normal file
490
resources/frontend/src/assets/scss/_base.scss
vendored
Normal file
@ -0,0 +1,490 @@
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
::-webkit-scrollbar{
|
||||
width:7px;
|
||||
height:7px;
|
||||
}
|
||||
::-webkit-scrollbar-track-piece{
|
||||
background:#EFEFEF;
|
||||
}
|
||||
::-webkit-scrollbar-thumb{
|
||||
background: #C7D1DA;
|
||||
border-radius: 3.5px;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
ul,
|
||||
li,
|
||||
ol,
|
||||
dl,
|
||||
dd,
|
||||
dt,
|
||||
p,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
form,
|
||||
img,
|
||||
textarea,
|
||||
::before,
|
||||
::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.15;
|
||||
color: #303133;
|
||||
background-color: #fff;
|
||||
}
|
||||
.page{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
a {
|
||||
color: mix(#fff, $--color-primary, 20%);
|
||||
text-decoration: none;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: $--color-primary;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
border: none;
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol,
|
||||
li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
border: none;
|
||||
resize: none;
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
input::-webkit-input-placeholder {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
button {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
cite,
|
||||
i,
|
||||
em,
|
||||
s {
|
||||
font-style: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Utils
|
||||
------------------------------ */
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
content: " ";
|
||||
display: table;
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
/* Animation
|
||||
------------------------------ */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity .5s;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Reset element-ui
|
||||
------------------------------ */
|
||||
.site-wrapper {
|
||||
.el-pagination {
|
||||
margin-top: 15px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Layout
|
||||
------------------------------ */
|
||||
.site-wrapper {
|
||||
position: relative;
|
||||
min-width: 1180px;
|
||||
}
|
||||
|
||||
|
||||
/* Sidebar fold
|
||||
------------------------------ */
|
||||
.site-sidebar--fold {
|
||||
|
||||
.site-navbar__header,
|
||||
.site-navbar__brand,
|
||||
.site-sidebar,
|
||||
.site-sidebar__inner,
|
||||
.el-menu.site-sidebar__menu {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.site-navbar__body,
|
||||
.site-content__wrapper {
|
||||
margin-left: 64px;
|
||||
}
|
||||
|
||||
.site-navbar__brand {
|
||||
&-lg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-mini {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.site-sidebar,
|
||||
.site-sidebar__inner {
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
.site-sidebar__menu-icon {
|
||||
margin-right: 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.site-content--tabs>.el-tabs>.el-tabs__header {
|
||||
left: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
// animation
|
||||
.site-navbar__header,
|
||||
.site-navbar__brand,
|
||||
.site-navbar__body,
|
||||
.site-sidebar,
|
||||
.site-sidebar__inner,
|
||||
.site-sidebar__menu.el-menu,
|
||||
.site-sidebar__menu-icon,
|
||||
.site-content__wrapper,
|
||||
.site-content--tabs>.el-tabs .el-tabs__header {
|
||||
transition: inline-block .3s, left .3s, width .3s, margin-left .3s, font-size .3s;
|
||||
}
|
||||
|
||||
|
||||
/* Navbar
|
||||
------------------------------ */
|
||||
.site-navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 1030;
|
||||
height: 50px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, .08);
|
||||
background-color: $navbar--background-color;
|
||||
|
||||
&--inverse {
|
||||
.site-navbar__body {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
|
||||
>.el-menu-item,
|
||||
>.el-submenu>.el-submenu__title {
|
||||
color: #fff;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: mix(#000, $navbar--background-color, 15%);
|
||||
}
|
||||
}
|
||||
|
||||
>.el-menu-item.is-active,
|
||||
>.el-submenu.is-active>.el-submenu__title {
|
||||
border-bottom-color: mix(#fff, $navbar--background-color, 85%);
|
||||
}
|
||||
|
||||
.el-menu-item i,
|
||||
.el-submenu__title i,
|
||||
.el-dropdown {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu--popup-bottom-start {
|
||||
background-color: $navbar--background-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__header {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 230px;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__brand {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
width: 230px;
|
||||
height: 50px;
|
||||
margin: 0;
|
||||
line-height: 50px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
color: #fff;
|
||||
|
||||
&-lg,
|
||||
&-mini {
|
||||
margin: 0 5px;
|
||||
color: #fff;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-mini {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__switch {
|
||||
font-size: 18px;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
border-bottom: none !important;
|
||||
|
||||
* {
|
||||
vertical-align: inherit;
|
||||
}
|
||||
|
||||
.el-dropdown-link {
|
||||
>img {
|
||||
width: 36px;
|
||||
height: auto;
|
||||
margin-right: 5px;
|
||||
border-radius: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__body {
|
||||
position: relative;
|
||||
margin-left: 230px;
|
||||
padding-right: 15px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
&__menu {
|
||||
float: left;
|
||||
background-color: transparent;
|
||||
border-bottom: 0;
|
||||
|
||||
&--right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
a:focus,
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.el-menu-item,
|
||||
.el-submenu>.el-submenu__title {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
.el-submenu>.el-menu {
|
||||
top: 55px;
|
||||
}
|
||||
|
||||
.el-badge {
|
||||
display: inline;
|
||||
z-index: 2;
|
||||
|
||||
&__content {
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Sidebar
|
||||
------------------------------ */
|
||||
.site-sidebar {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 1020;
|
||||
width: 230px;
|
||||
overflow: hidden;
|
||||
|
||||
&--dark,
|
||||
&--dark-popper {
|
||||
background-color: $sidebar--background-color-dark;
|
||||
|
||||
.site-sidebar__menu.el-menu,
|
||||
>.el-menu--popup {
|
||||
background-color: $sidebar--background-color-dark;
|
||||
|
||||
.el-menu-item,
|
||||
.el-submenu>.el-submenu__title {
|
||||
color: $sidebar--color-text-dark;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: mix(#fff, $sidebar--color-text-dark, 50%);
|
||||
background-color: mix(#fff, $sidebar--background-color-dark, 2.5%);
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu,
|
||||
.el-submenu.is-opened {
|
||||
background-color: mix(#000, $sidebar--background-color-dark, 15%);
|
||||
}
|
||||
|
||||
.el-menu-item.is-active,
|
||||
.el-submenu.is-active>.el-submenu__title {
|
||||
color: mix(#fff, $sidebar--color-text-dark, 80%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__inner {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
padding-bottom: 15px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
&__menu.el-menu {
|
||||
width: 230px;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
&__menu-icon {
|
||||
width: 24px;
|
||||
margin-right: 5px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: inherit !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Content
|
||||
------------------------------ */
|
||||
.site-content {
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
|
||||
&__wrapper {
|
||||
position: relative;
|
||||
padding-top: 50px;
|
||||
margin-left: 230px;
|
||||
min-height: 100%;
|
||||
background: $content--background-color;
|
||||
}
|
||||
|
||||
&--tabs {
|
||||
padding: 55px 0 0;
|
||||
}
|
||||
|
||||
>.el-tabs {
|
||||
>.el-tabs__header {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 230px;
|
||||
right: 0;
|
||||
z-index: 930;
|
||||
padding: 0 55px 0 15px;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .12), 0 0 6px 0 rgba(0, 0, 0, .04);
|
||||
background-color: #fff;
|
||||
|
||||
>.el-tabs__nav-wrap {
|
||||
margin-bottom: 0;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.el-tabs__content {
|
||||
padding: 0 15px 15px;
|
||||
|
||||
>.site-tabs__tools {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
right: 0;
|
||||
z-index: 931;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
font-size: 16px;
|
||||
line-height: 40px;
|
||||
background-color: $content--background-color;
|
||||
cursor: pointer;
|
||||
|
||||
.el-icon--right {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__expand-icon {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
vertical-align: middle;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
117
resources/frontend/src/assets/scss/_flex.scss
vendored
Normal file
117
resources/frontend/src/assets/scss/_flex.scss
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
.flex{
|
||||
display: flex;
|
||||
}
|
||||
.page{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.flex-cc{
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-items:center;
|
||||
justify-content:space-around;
|
||||
}
|
||||
.flex-cc-t{
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-items:center;
|
||||
}
|
||||
.flex-col-center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items:center;
|
||||
margin:10px 0px;
|
||||
}
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.flex-row-wrap {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.column{
|
||||
flex-direction: column !important;
|
||||
}
|
||||
|
||||
.flex_a{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex_j{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.flex_aj{
|
||||
@extend .flex_a;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.flex_column{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.flex-col{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex_sb{
|
||||
@extend .flex_a;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.sb{
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.jce{
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.flex_sa{
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
@for $i from 1 through 5 {
|
||||
.flex#{$i}{
|
||||
flex: $i;
|
||||
}
|
||||
}
|
||||
|
||||
.flexWrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.font-red {
|
||||
color: #e54d42 !important;
|
||||
}
|
||||
|
||||
.font-orange {
|
||||
color: #f37b1d !important;
|
||||
}
|
||||
|
||||
.font-yellow {
|
||||
color: #fbbd08 !important;
|
||||
}
|
||||
|
||||
.font-olive {
|
||||
color: #8dc63f !important;
|
||||
}
|
||||
|
||||
.font-green {
|
||||
color: #39b54a !important;
|
||||
}
|
||||
13
resources/frontend/src/assets/scss/_font.scss
vendored
Normal file
13
resources/frontend/src/assets/scss/_font.scss
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
@for $i from 12 through 100 {
|
||||
.ft#{$i}{
|
||||
font-size: $i *1px;
|
||||
}
|
||||
}
|
||||
|
||||
.ft0{
|
||||
font-size:0;
|
||||
}
|
||||
|
||||
.fw{
|
||||
font-weight: bold;
|
||||
}
|
||||
447
resources/frontend/src/assets/scss/_normalize.scss
vendored
Normal file
447
resources/frontend/src/assets/scss/_normalize.scss
vendored
Normal file
@ -0,0 +1,447 @@
|
||||
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/* Document
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in
|
||||
* IE on Windows Phone and in iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/* Sections
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers (opinionated).
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
footer,
|
||||
header,
|
||||
nav,
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the font size and margin on `h1` elements within `section` and
|
||||
* `article` contexts in Chrome, Firefox, and Safari.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
* 1. Add the correct display in IE.
|
||||
*/
|
||||
|
||||
figcaption,
|
||||
figure,
|
||||
main { /* 1 */
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct margin in IE 8.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Remove the gray background on active links in IE 10.
|
||||
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent; /* 1 */
|
||||
-webkit-text-decoration-skip: objects; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font style in Android 4.3-.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct background and color in IE 9-.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
audio,
|
||||
video {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in iOS 4-7.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the border on images inside links in IE 10-.
|
||||
*/
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the overflow in IE.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Change the font styles in all browsers (opinionated).
|
||||
* 2. Remove the margin in Firefox and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: sans-serif; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the overflow in IE.
|
||||
* 1. Show the overflow in Edge.
|
||||
*/
|
||||
|
||||
button,
|
||||
input { /* 1 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||
* 1. Remove the inheritance of text transform in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select { /* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
|
||||
* controls in Android 4.
|
||||
* 2. Correct the inability to style clickable types in iOS and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
html [type="button"], /* 1 */
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner border and padding in Firefox.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the focus styles unset by the previous rule.
|
||||
*/
|
||||
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the padding in Firefox.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
padding: 0.35em 0.75em 0.625em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the text wrapping in Edge and IE.
|
||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
* 3. Remove the padding so developers are not caught out when they zero out
|
||||
* `fieldset` elements in all browsers.
|
||||
*/
|
||||
|
||||
legend {
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct display in IE 9-.
|
||||
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
display: inline-block; /* 1 */
|
||||
vertical-align: baseline; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in IE 10-.
|
||||
* 2. Remove the padding in IE 10-.
|
||||
*/
|
||||
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the odd appearance in Chrome and Safari.
|
||||
* 2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type="search"]::-webkit-search-cancel-button,
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/* Interactive
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Add the correct display in IE 9-.
|
||||
* 1. Add the correct display in Edge, IE, and Firefox.
|
||||
*/
|
||||
|
||||
details, /* 1 */
|
||||
menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* Scripting
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
canvas {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE.
|
||||
*/
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hidden
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10-.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
115
resources/frontend/src/assets/scss/_space.scss
vendored
Normal file
115
resources/frontend/src/assets/scss/_space.scss
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
.mt1 {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.mt24 {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.mr24 {
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
.ml24 {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
.pt24 {
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
.pr24 {
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
.pb24 {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.pl24 {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.pt88 {
|
||||
padding-top: 88px;
|
||||
}
|
||||
|
||||
.mlr24 {
|
||||
margin-left: 24px;
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
.ptb24 {
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.plr24 {
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
}
|
||||
.p20 {
|
||||
padding: 20upx;
|
||||
}
|
||||
|
||||
.p24 {
|
||||
padding: 24upx;
|
||||
}
|
||||
|
||||
.p30 {
|
||||
padding: 30upx;
|
||||
}
|
||||
|
||||
.p40 {
|
||||
padding: 40upx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@for $i from 1 through 30 {
|
||||
.mt#{$i*10}{
|
||||
margin-top: $i * 10px;
|
||||
}
|
||||
.pt#{$i*10}{
|
||||
padding-top: $i * 10px;
|
||||
}
|
||||
.pb#{$i*10}{
|
||||
padding-bottom: $i * 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 20 {
|
||||
.pl#{$i*10}{
|
||||
padding-left: $i * 10px;
|
||||
}
|
||||
.pr#{$i*10}{
|
||||
padding-right: $i * 10px;
|
||||
}
|
||||
.mb#{$i*10}{
|
||||
margin-bottom: $i * 10px;
|
||||
}
|
||||
.ml#{$i*10}{
|
||||
margin-left: $i * 10px;
|
||||
}
|
||||
.mr#{$i*10}{
|
||||
margin-right: $i * 10px;
|
||||
}
|
||||
.mlr#{$i*10}{
|
||||
margin-left: $i * 10px;
|
||||
margin-right: $i * 10px;
|
||||
}
|
||||
.mtb#{$i*10}{
|
||||
margin-top: $i * 10px;
|
||||
margin-bottom: $i * 10px;
|
||||
}
|
||||
.ptb#{$i*10}{
|
||||
padding-top: $i * 10px;
|
||||
padding-bottom: $i * 10px;
|
||||
}
|
||||
.plr#{$i*10}{
|
||||
padding-left: $i * 10px;
|
||||
padding-right: $i * 10px;
|
||||
}
|
||||
}
|
||||
13
resources/frontend/src/assets/scss/_variables.scss
vendored
Normal file
13
resources/frontend/src/assets/scss/_variables.scss
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// 站点主色
|
||||
// tips: 要达到整站主题修改效果, 请确保[$--color-primary]站点主色与[/src/element-ui-theme/index.js]文件中[import './element-[#17B3A3]/index.css']当前主题色一致
|
||||
$--color-primary: #3E8EF7;
|
||||
|
||||
// Navbar
|
||||
$navbar--background-color: $--color-primary;
|
||||
|
||||
// Sidebar
|
||||
$sidebar--background-color-dark: #263238;
|
||||
$sidebar--color-text-dark: #8a979e;
|
||||
|
||||
// Content
|
||||
$content--background-color: #f1f4f5;
|
||||
9
resources/frontend/src/assets/scss/index.scss
vendored
Normal file
9
resources/frontend/src/assets/scss/index.scss
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
@import "normalize"; // api: https://github.com/necolas/normalize.css/
|
||||
@import "variables"; // 站点变量
|
||||
@import "base";
|
||||
@import "space";
|
||||
@import "font";
|
||||
@import "flex";
|
||||
|
||||
|
||||
|
||||
60
resources/frontend/src/components/global/Board/index.vue
Normal file
60
resources/frontend/src/components/global/Board/index.vue
Normal file
@ -0,0 +1,60 @@
|
||||
<!-- 搜索表单 -->
|
||||
<template>
|
||||
<div>
|
||||
<el-card>
|
||||
<div class="flex-row">
|
||||
<template v-for="(top,index) in boardData">
|
||||
<div class="flex_column flex_aj flex1" style="min-width:150px;padding:10px;" >
|
||||
<span class="ft20 fw">{{top.label}}</span>
|
||||
<span class="ft18" style="margin-top: 5px;">{{top.value}}</span>
|
||||
</div>
|
||||
<div :class="getStyle(boardData,index)"></div>
|
||||
</template>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "Board",
|
||||
props: {
|
||||
boardData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
getStyle(){
|
||||
return (lst,index)=>{
|
||||
let len= Object.keys(lst).length;
|
||||
if (len>0) {
|
||||
if (len==index+1) {
|
||||
return ''
|
||||
}
|
||||
return 'divi';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.divi{
|
||||
display: inline-block;
|
||||
width: 1px;
|
||||
margin: 0 8px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
background-color:#DCDFE6;
|
||||
}
|
||||
</style>
|
||||
|
||||
575
resources/frontend/src/components/global/Form/index.vue
Normal file
575
resources/frontend/src/components/global/Form/index.vue
Normal file
@ -0,0 +1,575 @@
|
||||
<!-- 搜索表单 -->
|
||||
<template>
|
||||
<div class="ces-form">
|
||||
<el-dialog
|
||||
:title="dialogFormTitle"
|
||||
:visible.sync="dialogFormVisible"
|
||||
@close="reset()"
|
||||
:close-on-click-modal="false"
|
||||
:width="dialogWidth"
|
||||
v-if="dialogFormVisible"
|
||||
>
|
||||
<el-form
|
||||
:size="size"
|
||||
:inline="inline"
|
||||
:label-width="labelWidth"
|
||||
:rules="formRules"
|
||||
:model="formData"
|
||||
ref="ruleForm"
|
||||
>
|
||||
<el-form-item
|
||||
v-for="item in formCols"
|
||||
:label="item.label"
|
||||
:key="item.label"
|
||||
:prop="item.prop"
|
||||
>
|
||||
<!-- 输入框 -->
|
||||
<el-input
|
||||
v-if="item.type==='input'"
|
||||
:type="item.mold||'text'"
|
||||
v-model="formData[item.prop]"
|
||||
:size="size || item.size"
|
||||
:style="{width:(item.width?item.width+'px':'300px')}"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:placeholder="item.placeholder || '请输入'+item.label"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData)"
|
||||
></el-input>
|
||||
<!-- 文本域 -->
|
||||
<el-input
|
||||
v-if="item.type==='textarea'"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
:size="size || item.size"
|
||||
:style="{width:(item.width?item.width+'px':'300px')}"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData)"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
v-model="formData[item.prop]"
|
||||
></el-input>
|
||||
<!-- 下拉框 -->
|
||||
<el-select
|
||||
v-if="item.type==='select'"
|
||||
v-model="formData[item.prop]"
|
||||
filterable
|
||||
:multiple="item.multiple"
|
||||
:size="size || item.size"
|
||||
:style="{width:(item.width?item.width+'px':'300px')}"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
@visible-change="item.focus && item.focus($event,formData[item.prop])"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
>
|
||||
<el-option
|
||||
v-for="op in item.options"
|
||||
:label="op.label"
|
||||
:value="op.value"
|
||||
:key="op.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<!-- 级联省市区 -->
|
||||
<!-- <el-cascader
|
||||
v-if="item.type==='cascader'"
|
||||
:style="{width:item.width+'px'}"
|
||||
:placeholder="item.placeholder || '请选择'"
|
||||
:options="cascaderOptions"
|
||||
v-model="formData[item.prop]"
|
||||
@focus="item.focus && item.focus(formData[item.prop])"
|
||||
filterable
|
||||
clearable
|
||||
:show-all-levels="item.showAll && item.showAll(formData[item.prop])"
|
||||
:props="{ expandTrigger: 'hover',checkStrictly: item.checkStrictly && item.checkStrictly(formData[item.prop]) }"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
></el-cascader> -->
|
||||
<el-cascader
|
||||
v-if="item.type==='cascader'"
|
||||
:style="{width:(item.width?item.width+'px':'300px')}"
|
||||
:placeholder="item.placeholder || `请选择${item.label}` "
|
||||
:options="item.options?item.options:options"
|
||||
v-model="formData[item.prop]"
|
||||
@focus="item.focus && item.focus(formData[item.prop])"
|
||||
filterable
|
||||
clearable
|
||||
:show-all-levels="item.showAll && item.showAll(formData[item.prop])"
|
||||
:props="{ expandTrigger: 'hover',checkStrictly: item.checkStrictly && item.checkStrictly(formData[item.prop]) }"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
></el-cascader>
|
||||
<!-- 单选 -->
|
||||
<el-radio-group
|
||||
v-if="item.type==='radio'"
|
||||
v-model="formData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
>
|
||||
<el-radio v-for="rav in item.radios" :label="rav.value" :key="rav.value">{{rav.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
<!-- 单选按钮 -->
|
||||
<el-radio-group
|
||||
v-if="item.type==='radioButton'"
|
||||
v-model="formData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
>
|
||||
<el-radio-button v-for="ra in item.radios" :label="ra.value" :key="ra.value">{{ra.label}}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<!-- 复选框 -->
|
||||
<el-checkbox-group
|
||||
v-if="item.type==='checkbox'"
|
||||
v-model="formData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
>
|
||||
<el-checkbox v-for="ch in item.checkboxs" :label="ch.value" :key="ch.value">{{ch.label}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<!-- 日期 -->
|
||||
<el-date-picker
|
||||
v-if="item.type==='date'"
|
||||
v-model="formData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
:picker-options="expireTimeOption"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
></el-date-picker>
|
||||
<!-- 开始-结束日期 -->
|
||||
<el-date-picker
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
v-if="item.type==='daterange'"
|
||||
type="daterange"
|
||||
v-model="formData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:picker-options="expireTimeOption"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
></el-date-picker>
|
||||
<!-- 时间 -->
|
||||
<el-time-select
|
||||
v-if="item.type==='time'"
|
||||
v-model="formData[item.prop]"
|
||||
format="HH:mm:ss"
|
||||
value-format="HH:mm:ss"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
></el-time-select>
|
||||
<!-- 开始-结束时间 -->
|
||||
<el-time-picker
|
||||
v-if="item.type==='timePicker'"
|
||||
v-model="formData[item.prop]"
|
||||
is-range
|
||||
format="HH:mm"
|
||||
value-format="HH:mm"
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
placeholder="选择时间范围"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
:picker-options="{
|
||||
selectableRange:['00:00:00 - 23:59:59']
|
||||
}"
|
||||
></el-time-picker>
|
||||
<!-- 日期时间 -->
|
||||
<el-date-picker
|
||||
v-if="item.type==='dateTime'"
|
||||
type="datetime"
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
:style="{width:item.width+'px'}"
|
||||
v-model="formData[item.prop]"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
></el-date-picker>
|
||||
<!-- 计数器 -->
|
||||
<el-input-number
|
||||
v-if="item.type==='number'"
|
||||
v-model="formData[item.prop]"
|
||||
controls-position="right"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:min="1"
|
||||
/>
|
||||
<!-- 滑块 -->
|
||||
<!-- <el-slider v-if="item.type==='Slider'" v-model="formData[item.prop]"></el-slider> -->
|
||||
<!-- 开关 -->
|
||||
<el-switch
|
||||
v-if="item.type==='switch'"
|
||||
v-model="formData[item.prop]"
|
||||
:size="size || item.size"
|
||||
:active-value="item.values&&item.values[0]"
|
||||
:inactive-value="item.values&&item.values[1]"
|
||||
@change="item.change && item.change(formData[item.prop])"
|
||||
:style="{width:item.width+'px'}"
|
||||
:disabled="item.isDisabled && item.isDisabled(formData[item.prop])"
|
||||
></el-switch>
|
||||
<!-- 树形菜单弹出框 -->
|
||||
<el-popover
|
||||
v-if="item.type==='popover'"
|
||||
placement="bottom-start"
|
||||
width="200"
|
||||
ref="deptListPopover"
|
||||
trigger="click">
|
||||
<el-tree
|
||||
:data="item.options"
|
||||
accordion
|
||||
node-key="id"
|
||||
ref="popoverTree"
|
||||
:props="defaultProps"
|
||||
:highlight-current="true"
|
||||
:expand-on-click-node="false"
|
||||
@node-click="item.handleNodeClick"/>
|
||||
<el-input
|
||||
slot="reference"
|
||||
v-model="formData[item.prop]"
|
||||
:readonly="true"
|
||||
:style="{width:item.width+'px'}"
|
||||
:placeholder="item.placeholder || '请选择'"
|
||||
></el-input>
|
||||
</el-popover>
|
||||
<!-- 树形控件 -->
|
||||
<el-tree
|
||||
v-if="item.type==='tree'"
|
||||
:data="item.options"
|
||||
show-checkbox
|
||||
node-key="id"
|
||||
ref="tree"
|
||||
:props="defaultProps"
|
||||
@check-change="item.check"/>
|
||||
<!-- 图片上传 -->
|
||||
<section v-if="item.type==='upload'" :style="{width:item.width+'px'}">
|
||||
<el-upload
|
||||
v-loading="loading"
|
||||
class="avatar-uploader"
|
||||
:action="upload_url+'/common/upload'"
|
||||
:show-file-list="false"
|
||||
:on-success="item.success"
|
||||
:on-error="handleAvatarError"
|
||||
:on-progress="handleAvatarProgress"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
|
||||
name="file"
|
||||
>
|
||||
<img v-if="formData[item.prop]" :src="formData[item.prop]|formatImg" class="avatar" />
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</section>
|
||||
|
||||
<!-- 多图片上传 -->
|
||||
<section v-if="item.type==='uploadList'" :style="{width:item.width+'px'}">
|
||||
<el-upload
|
||||
v-loading="loading"
|
||||
:action="upload_url+'/common/upload'"
|
||||
list-type="picture-card"
|
||||
:multiple="true"
|
||||
:limit="9"
|
||||
:fileList="fileList"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:on-error="handleAvatarError"
|
||||
:on-progress="handleAvatarProgress"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
:on-remove="handleRemove"
|
||||
:on-exceed="handleExceed"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:headers="{'Authorization':$cookie.get('token')}"
|
||||
name="file"
|
||||
>
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
<el-dialog :visible.sync="dialogVisible" append-to-body title="预览">
|
||||
<img width="100%" :src="dialogImageUrl" alt />
|
||||
</el-dialog>
|
||||
</section>
|
||||
<!-- 地图 -->
|
||||
<div v-if="item.type==='map'" id="container" :style="{width:(item.width||'900px'),height:(item.height||'300px')}"></div>
|
||||
<MapSearch v-if="item.type==='mapSearch'" @getLocation="item.address":style="{width:(item.width||'900px'),height:(item.height||'500px'),border: 'solid 1px #efefef'}"></MapSearch>
|
||||
<!-- 默认 -->
|
||||
<span
|
||||
v-if="!item.type"
|
||||
:style="{width:item.width+'px','display': 'inline-block'}"
|
||||
:size="size"
|
||||
:class="item.itemClass && item.itemClass(formData[item.prop])"
|
||||
>{{(item.formatter && item.formatter(formData[item.prop])) || formData[item.prop]}}</span>
|
||||
|
||||
<!-- 图片显示 -->
|
||||
<el-image
|
||||
v-if="item.type==='img'"
|
||||
:src="formData[item.prop]|formatImg"
|
||||
:style="{width:item.width+'px',height:item.width+'px'}"
|
||||
></el-image>
|
||||
<!-- 富文本 -->
|
||||
<r-tinymce
|
||||
v-if="item.type==='tinymce'"
|
||||
v-model="formData[item.prop]"
|
||||
:height="300"
|
||||
:width="600"
|
||||
></r-tinymce>
|
||||
</el-form-item>
|
||||
<slot></slot>
|
||||
</el-form>
|
||||
<el-form
|
||||
inline
|
||||
v-if="isHandle"
|
||||
:style="btnStyle || 'justify-content: flex-end;display: flex;margin-top:20px;'"
|
||||
>
|
||||
<el-form-item v-for="item in formHandle" :key="item.label" style="margin-bottom: 0;">
|
||||
<el-button
|
||||
:type="item.type"
|
||||
:size="item.size || size"
|
||||
:icon="item.icon"
|
||||
:disabled="item.disabled"
|
||||
@click="item.handle"
|
||||
>{{item.label}}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import area from "@/util/area2";
|
||||
import MapSearch from "../../local";
|
||||
import * as plugin from "@/util/Tmap";
|
||||
import { regionData, CodeToText } from "element-china-area-data";
|
||||
export default {
|
||||
props: {
|
||||
isHandle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
labelWidth: {
|
||||
type: String,
|
||||
default: "100px",
|
||||
},
|
||||
dialogWidth: {
|
||||
type: String,
|
||||
default: "1000px",
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 搜索框型号:mini,medium,small
|
||||
size: {
|
||||
type: String,
|
||||
default: "small",
|
||||
},
|
||||
formCols: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
formHandle: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
formRules: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
btnStyle: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
fileList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
defaultProps: {
|
||||
type: Object,
|
||||
default: () => ({children: "sysMenuList",label: "interfaceName"}),
|
||||
},
|
||||
destroy: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
name: "Form",
|
||||
data() {
|
||||
return {
|
||||
options:regionData,
|
||||
form:{test:'2'},
|
||||
numbers:0,
|
||||
dialogFormVisible: false,
|
||||
dialogFormTitle: "新增",
|
||||
loading: false,
|
||||
imageUrl: "",
|
||||
upload_url: process.env.NODE_ENV !== 'production'?'/api':process.env.VUE_APP_URL,
|
||||
imgurl: process.env.VUE_APP_IMG,
|
||||
cascaderOptions: area,
|
||||
map: null,
|
||||
expireTimeOption:{
|
||||
disabledDate(date) {
|
||||
return date.getTime() < Date.now() - 8.64e7;
|
||||
}
|
||||
},
|
||||
dialogVisible: false,
|
||||
dialogImageUrl:''
|
||||
};
|
||||
},
|
||||
computed:{
|
||||
getType() {
|
||||
return (type)=>{
|
||||
// console.log('select原类型',typeof type);
|
||||
let istype=/^\d+$/.test(type)
|
||||
if (istype) {
|
||||
console.log('select类型',typeof type.toString());
|
||||
return type.toString();
|
||||
}
|
||||
// console.log('select类型',typeof type);
|
||||
return type
|
||||
}
|
||||
}
|
||||
},
|
||||
components:{MapSearch},
|
||||
created() {
|
||||
console.log('created表单form');
|
||||
},
|
||||
|
||||
methods: {
|
||||
async plugin(point={lat:'',lng:''}) {
|
||||
var qq = await plugin.Tmap();
|
||||
if(point.lat==''|| point.lat==0){
|
||||
point = await this.getLocation()
|
||||
}
|
||||
this.map = await plugin.center(point.lat, point.lng);
|
||||
qq.maps.event.addListener(this.map.marker, "dragend", (e) => {
|
||||
this.map.map.setCenter(e.latLng);
|
||||
this.$emit("position", {
|
||||
lat: e.latLng.lat,
|
||||
lng: e.latLng.lng,
|
||||
});
|
||||
});
|
||||
},
|
||||
getLocation() {//腾讯api
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$jsonp("https://apis.map.qq.com/ws/location/v1/ip", {
|
||||
key: "N6RBZ-AJN35-AACI2-Q2ICF-HYV6O-JRBBZ",
|
||||
output: "jsonp"
|
||||
}).then((res) => {
|
||||
resolve({
|
||||
lat: res.result.location.lat,
|
||||
lng: res.result.location.lng,
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
handleAvatarSuccess(res, file) {
|
||||
this.loading = false;
|
||||
this.imageUrl = URL.createObjectURL(file.raw);
|
||||
if(res.code==200){
|
||||
this.$message({
|
||||
message: "上传成功",
|
||||
type: "success",
|
||||
});
|
||||
this.$emit("imgs", res.data.value);
|
||||
}else{
|
||||
this.$message({
|
||||
message: res.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
reset() {
|
||||
this.$refs.ruleForm.resetFields()
|
||||
this.$parent.$data.formData = this.$parent.$options.data.call(this).formData;
|
||||
if(this.$parent.$data.formTable){
|
||||
this.$parent.$data.formTable.data = this.$parent.$options.data.call(this).formTable.data
|
||||
}
|
||||
},
|
||||
handleAvatarError() {
|
||||
this.loading = false;
|
||||
this.$message.error("上传失败");
|
||||
},
|
||||
beforeAvatarUpload(file) {
|
||||
const isJPG = file.type === "image/jpeg" || "image/png";
|
||||
const isLt5M = file.size / 1024 / 1024 < 5;
|
||||
if (!isJPG) {
|
||||
this.$message.error("上传格式只能是图片格式!");
|
||||
}
|
||||
if (!isLt5M) {
|
||||
this.$message.error("上传头像图片大小不能超过 5MB!");
|
||||
}
|
||||
return isJPG && isLt5M;
|
||||
},
|
||||
handleAvatarProgress(res, file) {
|
||||
this.loading = true;
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
let list = fileList.map((item) => {
|
||||
console.log(item)
|
||||
if(item.url.indexOf('http')!=-1){
|
||||
return item.url.split(process.env.VUE_APP_IMG)[1]
|
||||
}else{
|
||||
return item.url
|
||||
}
|
||||
});
|
||||
this.$emit("imgs", {
|
||||
type: "pictureCard",
|
||||
url: list,
|
||||
});
|
||||
},
|
||||
handleExceed() {
|
||||
this.$message({
|
||||
message: "最多上传9张图片",
|
||||
type: "warning",
|
||||
});
|
||||
},
|
||||
handlePictureCardPreview(file){
|
||||
this.dialogImageUrl = file.url;
|
||||
this.dialogVisible = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.avatar-uploader,
|
||||
.el-upload {
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.avatar-uploader:hover,
|
||||
.el-upload:hover {
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
line-height: 150px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
543
resources/frontend/src/components/global/FormItem/index.vue
Normal file
543
resources/frontend/src/components/global/FormItem/index.vue
Normal file
@ -0,0 +1,543 @@
|
||||
<!-- 搜索表单 -->
|
||||
<template>
|
||||
<div class="ces-search">
|
||||
<el-form :size="size" :inline="inline" :label-position="labelPosition" :label-width="labelWidth" ref="ruleForm" :rules="formRule" :model="itemData">
|
||||
<el-form-item v-for="item in formItem" :label="item.label" :key="item.label" :prop="item.prop" :label-width="item.labelWidth||labelWidth">
|
||||
<!-- 输入框 -->
|
||||
<el-input
|
||||
v-if="item.type==='input'"
|
||||
:type="item.mold||'text'"
|
||||
v-model="itemData[item.prop]"
|
||||
:size="size || item.size"
|
||||
:style="{width:(item.width?item.width+'px':'300px')}"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
:placeholder="`请输入${item.label}`"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
@blur="item.mold==='number'?BlurText($event):''"
|
||||
>
|
||||
<template v-if="item.slot" :slot="item.slot.direction||'append'">{{item.slot.value}}</template>
|
||||
</el-input>
|
||||
<!-- 文本域 -->
|
||||
<el-input
|
||||
v-if="item.type==='textarea'"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
:size="size || item.size"
|
||||
:style="{width:item.width+'px'}"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
v-model="itemData[item.prop]"
|
||||
></el-input>
|
||||
<!-- 下拉框 -->
|
||||
<el-select
|
||||
v-if="item.type==='select'"
|
||||
v-model="itemData[item.prop]"
|
||||
filterable
|
||||
:size="size || item.size"
|
||||
:style="{width:(item.width?item.width+'px':'300px')}"
|
||||
:multiple="item.multiple"
|
||||
:placeholder="`请选择${item.placeholder||item.label}`"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
@visible-change="item.focus && item.focus($event,itemData[item.prop])"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
>
|
||||
<el-option v-for="op in item.options" :label="op.label" :value="op.value" :key="op.value"></el-option>
|
||||
</el-select>
|
||||
<!-- 级联省市区 -->
|
||||
<el-cascader
|
||||
v-if="item.type==='cascader'"
|
||||
:style="{width:(item.width?item.width+'px':'300px')}"
|
||||
:placeholder="item.placeholder || `请选择${item.label}` "
|
||||
:options="options"
|
||||
v-model="itemData[item.prop]"
|
||||
@focus="item.focus && item.focus(itemData[item.prop])"
|
||||
filterable
|
||||
clearable
|
||||
:show-all-levels="item.showAll && item.showAll(itemData[item.prop])"
|
||||
:props="{ expandTrigger: 'hover',checkStrictly: item.checkStrictly && item.checkStrictly(itemData[item.prop]) }"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
></el-cascader>
|
||||
<!-- 单选 -->
|
||||
<el-radio-group
|
||||
v-if="item.type==='radio'"
|
||||
v-model="itemData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
>
|
||||
<el-radio v-for="ra in item.radios" :label="ra.value" :key="ra.value">{{ra.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
<!-- 单选按钮 -->
|
||||
<el-radio-group
|
||||
v-if="item.type==='radioButton'"
|
||||
v-model="itemData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
>
|
||||
<el-radio-button v-for="ra in item.radios" :label="ra.value" :key="ra.value">{{ra.label}}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<!-- 复选框 -->
|
||||
<!-- <el-checkbox-group
|
||||
v-if="item.type==='checkbox'"
|
||||
v-model="itemData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
>
|
||||
<el-checkbox v-for="ch in item.checkboxs" :label="ch.value" :key="ch.value">{{ch.label}}</el-checkbox>
|
||||
</el-checkbox-group> -->
|
||||
|
||||
<el-checkbox-group v-model="itemData[item.prop]" v-if="item.type==='checkbox'">
|
||||
<el-checkbox v-for="ch in item.checkboxs" :label="ch.label" :key="ch.value" :name="item.prop"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<!-- 树形组件 -->
|
||||
<el-tree
|
||||
v-if="item.type==='tree'"
|
||||
:data="item.treeArr"
|
||||
show-checkbox
|
||||
:node-key="treeKey"
|
||||
:default-expanded-keys="treeExpandArr"
|
||||
:default-checked-keys="treeCheckArr"
|
||||
:props="defaultProps"
|
||||
@check-change="handleCheckChange"
|
||||
@check="getChecked"
|
||||
>
|
||||
</el-tree>
|
||||
<!-- 日期 -->
|
||||
<el-date-picker
|
||||
v-if="item.type==='date'"
|
||||
v-model="itemData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
:placeholder="`请选择${item.placeholder||''}`"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
></el-date-picker>
|
||||
<!-- 开始-结束日期 -->
|
||||
<el-date-picker
|
||||
v-if="item.type==='daterange'"
|
||||
type="daterange"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
v-model="itemData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
></el-date-picker>
|
||||
<!-- 时间 -->
|
||||
<el-time-select
|
||||
v-if="item.type==='time'"
|
||||
v-model="itemData[item.prop]"
|
||||
format="HH:mm:ss"
|
||||
value-format="HH:mm:ss"
|
||||
:picker-options="item.options||{
|
||||
start: '00:00',
|
||||
step: '00:30',
|
||||
end: '23:30'
|
||||
}"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:placeholder="`请选择${item.placeholder||''}`"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
></el-time-select>
|
||||
<!-- 日期时间 -->
|
||||
<el-date-picker
|
||||
v-if="item.type==='dateTime'"
|
||||
:type="item.timeType||'datetime'"
|
||||
:style="{width:item.width+'px'}"
|
||||
v-model="itemData[item.prop]"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:placeholder="`请选择${item.placeholder||''}`"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
></el-date-picker>
|
||||
<!-- 滑块 -->
|
||||
<!-- <el-slider v-if="item.type==='Slider'" v-model="itemData[item.prop]"></el-slider> -->
|
||||
<!-- 开关 -->
|
||||
<el-switch
|
||||
v-if="item.type==='switch'"
|
||||
v-model="itemData[item.prop]"
|
||||
:size="size || item.size"
|
||||
:active-value="item.values&&item.values[0]"
|
||||
:inactive-value="item.values&&item.values[1]"
|
||||
@change="item.change && item.change(itemData[item.prop])"
|
||||
:style="{width:item.width+'px'}"
|
||||
:disabled="item.isDisabled && item.isDisabled(itemData[item.prop])"
|
||||
></el-switch>
|
||||
<!-- 图片上传 -->
|
||||
<section v-if="item.type==='upload'" :style="{width:item.width+'px'}">
|
||||
<el-upload
|
||||
v-loading="loading"
|
||||
class="avatar-uploader"
|
||||
:action="upload_url+'/common/upload'"
|
||||
:show-file-list="false"
|
||||
:on-success="item.success"
|
||||
:on-error="handleAvatarError"
|
||||
:on-progress="handleAvatarProgress"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
name="file"
|
||||
>
|
||||
<img v-if="itemData[item.prop]" :src="itemData[item.prop]|formatImg" class="avatar" />
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</section>
|
||||
<!-- 文件上传 -->
|
||||
<section v-if="item.type==='uploadfill'" :style="{width:item.width+'px'}">
|
||||
<el-upload
|
||||
v-loading="loading"
|
||||
class="avatar-uploader"
|
||||
:action="file_url+'common//uploadNotRename'"
|
||||
:show-file-list="false"
|
||||
:on-success="item.success"
|
||||
:on-error="handleAvatarError"
|
||||
:on-progress="handleAvatarProgress"
|
||||
name="file"
|
||||
>
|
||||
<img v-if="itemData[item.prop]" :src="itemData[item.prop]|formatImg" class="avatar" />
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</section>
|
||||
<!-- 多图片上传 -->
|
||||
<section v-if="item.type==='uploadList'" :style="{width:item.width+'px'}">
|
||||
<el-upload
|
||||
ref="pictureCard"
|
||||
v-loading="loading"
|
||||
:action="upload_url+'/common/upload'"
|
||||
list-type="picture-card"
|
||||
:multiple="true"
|
||||
:limit="item.limit||9"
|
||||
:fileList="fileList"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:on-error="handleAvatarError"
|
||||
:on-progress="handleAvatarProgress"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
:on-remove="handleRemove"
|
||||
:on-exceed="handleExceed"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:headers="{'Authorization':$cookie.get('token')}"
|
||||
name="file"
|
||||
>
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
<el-dialog :visible.sync="dialogVisible" title="预览" width="600px">
|
||||
<img width="100%" :src="dialogImageUrl" alt />
|
||||
</el-dialog>
|
||||
</section>
|
||||
<!-- 富文本 -->
|
||||
<r-tinymce
|
||||
v-if="item.type==='tinymce'"
|
||||
v-model="itemData[item.prop]"
|
||||
:height="300"
|
||||
:width="600"
|
||||
></r-tinymce>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item :style="btnRight?`float:right`:''">
|
||||
<el-button
|
||||
v-for="(btnl,btni) in btnList" :key="btni"
|
||||
:type="btnl.type"
|
||||
:size="btnl.size || size"
|
||||
:icon="btnl.icon"
|
||||
:disabled="btnl.disabled"
|
||||
:style="{display:btnl.visible}"
|
||||
@click="getHandle(btnl.handle,btnl.deed)"
|
||||
>{{btnl.label}}</el-button>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { regionData, CodeToText } from "element-china-area-data";
|
||||
export default {
|
||||
name: "FormItem",
|
||||
props: {
|
||||
|
||||
labelPosition:{
|
||||
type: String,
|
||||
default: "none"
|
||||
},
|
||||
isState:{
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
btnRight:{
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isHandle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
labelWidth: {
|
||||
type: String,
|
||||
default: "100px",
|
||||
},
|
||||
// 搜索框型号:mini,medium,small
|
||||
size: {
|
||||
type: String,
|
||||
default: "medium",
|
||||
},
|
||||
btnList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
formItem: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
itemData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
formRule: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
fileList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
treeArr: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
treeExpandArr: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
treeCheckArr: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
treeKey:{
|
||||
type: String,
|
||||
default: "id"
|
||||
},
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'label'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// treeExpandArr:[],
|
||||
// treeCheckArr:[],
|
||||
options:regionData,
|
||||
loading: false,
|
||||
imageUrl: "",
|
||||
upload_url: process.env.NODE_ENV,
|
||||
imgurl: process.env.VUE_APP_IMG,
|
||||
dialogVisible: false,
|
||||
dialogImageUrl:'',
|
||||
isMouse:false,
|
||||
isLoading:false,
|
||||
good:[],
|
||||
file_url:''
|
||||
};
|
||||
},
|
||||
created(){
|
||||
this.file_url=process.env.VUE_APP_IMG
|
||||
},
|
||||
|
||||
methods: {
|
||||
getChecked(checkedNodes,checkedKeys){
|
||||
this.$parent.$emit('treeKeyArr',checkedKeys.checkedKeys);
|
||||
},
|
||||
handleCheckChange(data, checked) {
|
||||
if (data.parent_id==0 && checked) {
|
||||
data.chk=1
|
||||
}else if (data.parent_id==0 && !checked) {
|
||||
data.chk=0
|
||||
}else if (data.parent_id !==0) {
|
||||
data.chk=checked?1:0
|
||||
}
|
||||
},
|
||||
getHandle(func,deed){
|
||||
if (deed=='reset') {
|
||||
this.$refs.ruleForm.resetFields();
|
||||
}else{
|
||||
func.call(func)
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
mouseenter(icon){
|
||||
if (icon==='el-icon-refresh') {
|
||||
this.isMouse=true;
|
||||
}
|
||||
},
|
||||
mouseleave(icon){
|
||||
if (icon==='el-icon-refresh') {
|
||||
this.isMouse=false;
|
||||
}
|
||||
},
|
||||
|
||||
BlurText(e) {
|
||||
let boolean = new RegExp("^[1-9][0-9]*$").test(e.target.value)
|
||||
if(!boolean) {
|
||||
this.$message.warning('请输入正整数')
|
||||
e.target.value = ' '
|
||||
}
|
||||
},
|
||||
handleAvatarSuccess(res, file) {
|
||||
this.loading = false;
|
||||
this.imageUrl = URL.createObjectURL(file.raw);
|
||||
this.$message({
|
||||
message: "上传成功",
|
||||
type: "success",
|
||||
});
|
||||
this.$emit("imgs", {
|
||||
type: "text",
|
||||
url: `${res.data}`,
|
||||
});
|
||||
},
|
||||
handleUpload() {
|
||||
this.$refs['excel-upload-input'][0].click()
|
||||
},
|
||||
handleClick(e){
|
||||
const files = e.target.files
|
||||
const rawFile = files[0] // only use files[0]
|
||||
if (!rawFile) return
|
||||
//this.upload(rawFile)
|
||||
this.$emit("uploadEX", rawFile);
|
||||
},
|
||||
upload(rawFile) {
|
||||
this.$refs['excel-upload-input'][0].value = null // fix can't select the same excel
|
||||
const before = this.beforeUpload(rawFile)
|
||||
if (before) {
|
||||
let formData = new FormData();
|
||||
formData.append('file',rawFile);
|
||||
this.$http.upload('/file/upload',formData).then(res=>{
|
||||
if(res.code == 200){
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: "上传成功",
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const isLt1M = file.size / 1024 / 1024 < 1
|
||||
if (isLt1M) {
|
||||
return true
|
||||
}
|
||||
this.$message({
|
||||
message: '小于1兆',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
},
|
||||
handleAvatarError() {
|
||||
this.loading = false;
|
||||
this.$message.error("上传失败");
|
||||
},
|
||||
beforeAvatarUpload(file) {
|
||||
const isJPG = file.type === "image/jpeg" || "image/png";
|
||||
const isLt5M = file.size / 1024 / 1024 < 5;
|
||||
if (!isJPG) {
|
||||
this.$message.error("上传格式只能是图片格式!");
|
||||
}
|
||||
if (!isLt5M) {
|
||||
this.$message.error("上传头像图片大小不能超过 5MB!");
|
||||
}
|
||||
return isJPG && isLt5M;
|
||||
},
|
||||
handleAvatarProgress(res, file) {
|
||||
this.loading = true;
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
let list = fileList.map((item) => {
|
||||
console.log(item)
|
||||
if(item.response){
|
||||
return item.response.data
|
||||
}else{
|
||||
if(item.url.indexOf('http')!=-1){
|
||||
return item.url.split(process.env.VUE_APP_IMG)[1]
|
||||
}else{
|
||||
return item.url
|
||||
}
|
||||
}
|
||||
});
|
||||
this.$emit("imgs", {
|
||||
type: "pictureCard",
|
||||
url: list,
|
||||
});
|
||||
},
|
||||
handleExceed() {
|
||||
this.$message({
|
||||
message: `最多上传${this.$refs.pictureCard[0].limit||9}张图片`,
|
||||
type: "warning",
|
||||
});
|
||||
},
|
||||
handlePictureCardPreview(file){
|
||||
this.dialogImageUrl = file.url;
|
||||
this.dialogVisible = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@keyframes circles{
|
||||
0%{transform:rotateZ(0deg);}
|
||||
100%{transform:rotateZ(360deg);}
|
||||
}
|
||||
.good{
|
||||
animation-name:circles;
|
||||
animation-duration:3s;
|
||||
animation-iteration-count:1;
|
||||
}
|
||||
.avatar-uploader,
|
||||
.el-upload {
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.avatar-uploader:hover,
|
||||
.el-upload:hover {
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
line-height: 150px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.excel-upload-input{
|
||||
display: none;
|
||||
z-index: -9999;
|
||||
}
|
||||
</style>
|
||||
|
||||
170
resources/frontend/src/components/global/FormTable/index.vue
Normal file
170
resources/frontend/src/components/global/FormTable/index.vue
Normal file
@ -0,0 +1,170 @@
|
||||
<!-- 搜索表单 -->
|
||||
<template>
|
||||
<div class="ces-form">
|
||||
<section class="header" v-if="Handle">
|
||||
<el-button type="primary" size="mini" @click="addTable">新增</el-button>
|
||||
<el-button type="danger" size="mini" @click="del">删除</el-button>
|
||||
</section>
|
||||
<el-form :rules="formTable.rules" :model="formTable" ref="ruleForm">
|
||||
<el-table
|
||||
:data="formTable.data"
|
||||
border
|
||||
@select="select"
|
||||
@select-all="selectAll"
|
||||
:header-cell-class-name="headRuleStyle"
|
||||
:header-cell-style="{backgroundColor: '#f5f7fa',fontWeight: 'bold',color: '#909399'}">
|
||||
<el-table-column v-if="isSelection" type="selection" align="center"></el-table-column>
|
||||
<el-table-column
|
||||
v-for="item in formTable.cols"
|
||||
:size="size"
|
||||
:key="item.id"
|
||||
:prop="item.prop"
|
||||
:label="item.label"
|
||||
:width="item.width"
|
||||
:align="item.align||'center'"
|
||||
:fixed="item.fixed"
|
||||
:show-overflow-tooltip="item.overflow">
|
||||
<template slot-scope="scope">
|
||||
<el-form-item :prop="`data.${scope.$index}.${[item.prop]}`" :rules="formTable.rules[item.prop]" >
|
||||
<!-- 默认 -->
|
||||
<span
|
||||
v-if="!item.type"
|
||||
:style="item.itemStyle && item.itemStyle(scope.row)"
|
||||
:class="item.itemClass && item.item.itemClass(scope.row)"
|
||||
>{{(item.formatter && item.formatter(scope.row)) || scope.row[item.prop] || '-'}}</span>
|
||||
<!-- 输入框 -->
|
||||
<el-input v-if="item.type==='input'" v-model="scope.row[item.prop]" :size="item.size || size"></el-input>
|
||||
<!-- 下拉框 -->
|
||||
<el-select
|
||||
v-if="item.type==='select'"
|
||||
v-model="scope.row[item.prop]"
|
||||
:size="item.size || size"
|
||||
filterable
|
||||
:multiple="item.multiple"
|
||||
:placeholder="item.placeholder || '请选择'"
|
||||
@change="item.change && item.change(scope.row[item.prop])"
|
||||
@focus="item.focus && item.focus(scope.row[item.prop])"
|
||||
:disabled="item.isDisabled && item.isDisabled(scope.row[item.prop])"
|
||||
@remove-tag="item.remove && item.remove(scope.row[item.prop])">
|
||||
<el-option v-for="op in item.options" :label="op.label" :value="op.value" :key="op.value"></el-option>
|
||||
</el-select>
|
||||
<!-- 级联省市区 -->
|
||||
<el-cascader
|
||||
v-if="item.type==='cascader'"
|
||||
:placeholder="item.placeholder || '请选择'"
|
||||
:options="item.options || []"
|
||||
v-model="scope.row[item.prop]"
|
||||
:size="item.size || size"
|
||||
@focus="item.focus && item.focus(scope.row[item.prop])"
|
||||
filterable
|
||||
clearable
|
||||
:show-all-levels="item.showAll && item.showAll(scope.row[item.prop])"
|
||||
:props="{ expandTrigger: 'hover',checkStrictly: item.checkStrictly && item.checkStrictly(scope.row[item.prop]),value:item.value?item.value:'vaule' }"
|
||||
@change="item.change && item.change(scope.row[item.prop])"
|
||||
ref="cascaderAddr">
|
||||
</el-cascader>
|
||||
<span v-if="item.type==='button'">
|
||||
<el-button
|
||||
v-for="(btn,idx) in item.btnList"
|
||||
:key="idx"
|
||||
:size="item.size || size"
|
||||
:disabled="btn.disabled && btn.disabled(scope.row)"
|
||||
:type="btn.type"
|
||||
:icon="btn.icon"
|
||||
@click="btn.handle(scope.row,scope.$index)"
|
||||
>{{btn.label}}</el-button>
|
||||
</span>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// 表格型号:mini,medium,small
|
||||
size: {
|
||||
type: String,
|
||||
default: "mini",
|
||||
},
|
||||
formTable: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
isSelection: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
Handle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
addTable:Function
|
||||
},
|
||||
name: 'FormTable',
|
||||
data() {
|
||||
return {
|
||||
checkBox:[]
|
||||
};
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
select(rows, row) {
|
||||
this.$emit("select", rows, row);
|
||||
this.checkBox = rows
|
||||
},
|
||||
// 全选
|
||||
selectAll(rows) {
|
||||
this.$emit("select", rows);
|
||||
this.checkBox = rows
|
||||
},
|
||||
del(){
|
||||
if(this.checkBox&&this.checkBox.length>0){
|
||||
let arr = this.formTable.data.filter(item => !this.checkBox.some(ele => ele === item))
|
||||
this.checkBox = []
|
||||
this.formTable.data = arr
|
||||
}else{
|
||||
this.$message({
|
||||
message: '请先选择好需要删除的表格',
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
},
|
||||
headRuleStyle(row, rowIndex){
|
||||
if(row.column.property){
|
||||
let idx = row.row.findIndex(item=>{
|
||||
return item.property == Object.keys(this.formTable.rules)[0]
|
||||
})
|
||||
// console.log(row.column.property)
|
||||
// console.log(Object.keys(this.formTable.rules)[row.columnIndex-idx])
|
||||
if(Object.keys(this.formTable.rules)[row.columnIndex-idx] == row.column.property && row.column.property && Object.keys(this.formTable.rules).length!=1){
|
||||
return 'rules';
|
||||
}else if(Object.keys(this.formTable.rules).toString() == row.column.property){
|
||||
return 'rules';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.header{
|
||||
background-color: #f5f7fa;
|
||||
font-weight:bold ;
|
||||
padding: 10px 10px;
|
||||
border: 1px solid #EBEEF5;
|
||||
border-bottom: none;
|
||||
}
|
||||
.el-form >>> .rules .cell:before{
|
||||
content: '*';
|
||||
color: #f00;
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
/* .el-form >>>.el-form-item {margin-bottom: 0;} */
|
||||
</style>
|
||||
538
resources/frontend/src/components/global/Search/index.vue
Normal file
538
resources/frontend/src/components/global/Search/index.vue
Normal file
@ -0,0 +1,538 @@
|
||||
<!-- 搜索表单 -->
|
||||
<template>
|
||||
<div class="ces-search">
|
||||
<el-form :size="size" :inline="inline" :label-position="labelPosition" :label-width="labelWidth" ref="ruleForm" :rules="searchRules" :model="searchData">
|
||||
<el-form-item v-for="item in searchForm" :label="item.label" :key="item.label" :prop="item.prop" :label-width="item.labelWidth||labelWidth">
|
||||
<!-- 输入框 -->
|
||||
<el-input
|
||||
v-if="item.type==='input'"
|
||||
:type="item.mold||'text'"
|
||||
v-model="searchData[item.prop]"
|
||||
:size="size || item.size"
|
||||
:style="getInputStyle(item.width)"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
:placeholder="`请输入${item.placeholder||item.label}`"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
@blur="item.mold==='number'?BlurText($event):''"
|
||||
>
|
||||
<template v-if="item.slot" :slot="item.slot.direction||'append'">{{item.slot.value}}</template>
|
||||
</el-input>
|
||||
<!-- 文本域 -->
|
||||
<el-input
|
||||
v-if="item.type==='textarea'"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
:size="size || item.size"
|
||||
:style="{width:item.width+'px'}"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
v-model="searchData[item.prop]"
|
||||
></el-input>
|
||||
<!-- 下拉框 -->
|
||||
<el-select
|
||||
v-if="item.type==='select'"
|
||||
v-model="searchData[item.prop]"
|
||||
filterable
|
||||
:size="size || item.size"
|
||||
:style="{width:item.width+'px'}"
|
||||
:multiple="item.multiple"
|
||||
:placeholder="`请选择${item.placeholder||''}`"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
@visible-change="item.focus && item.focus($event,searchData[item.prop])"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
>
|
||||
<el-option v-for="op in item.options" :label="op.label" :value="op.value" :key="op.value"></el-option>
|
||||
</el-select>
|
||||
<!-- 级联省市区 -->
|
||||
<el-cascader
|
||||
v-if="item.type==='cascader'"
|
||||
:style="{width:item.width+'px'}"
|
||||
:placeholder="item.placeholder || '请选择'"
|
||||
:options="item.options || []"
|
||||
v-model="searchData[item.prop]"
|
||||
@focus="item.focus && item.focus(searchData[item.prop])"
|
||||
filterable
|
||||
clearable
|
||||
:show-all-levels="item.showAll && item.showAll(searchData[item.prop])"
|
||||
:props="{ expandTrigger: 'hover',checkStrictly: item.checkStrictly && item.checkStrictly(searchData[item.prop]) }"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
></el-cascader>
|
||||
<!-- 单选 -->
|
||||
<el-radio-group
|
||||
v-if="item.type==='radio'"
|
||||
v-model="searchData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
>
|
||||
<el-radio v-for="ra in item.radios" :label="ra.value" :key="ra.value">{{ra.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
<!-- 单选按钮 -->
|
||||
<el-radio-group
|
||||
v-if="item.type==='radioButton'"
|
||||
v-model="searchData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
>
|
||||
<el-radio-button v-for="ra in item.radios" :label="ra.value" :key="ra.value">{{ra.label}}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<!-- 复选框 -->
|
||||
<el-checkbox-group
|
||||
v-if="item.type==='checkbox'"
|
||||
v-model="searchData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
>
|
||||
<el-checkbox v-for="ch in item.checkboxs" :label="ch.value" :key="ch.value">{{ch.label}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<!-- 日期 -->
|
||||
<el-date-picker
|
||||
v-if="item.type==='date'"
|
||||
v-model="searchData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
:placeholder="`请选择${item.placeholder||''}`"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
></el-date-picker>
|
||||
<!-- 开始-结束日期 -->
|
||||
<el-date-picker
|
||||
v-if="item.type==='daterange'"
|
||||
type="daterange"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
v-model="searchData[item.prop]"
|
||||
:style="{width:item.width+'px'}"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:picker-options="pickerOptions"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
></el-date-picker>
|
||||
<!-- 时间 -->
|
||||
<el-time-select
|
||||
v-if="item.type==='time'"
|
||||
v-model="searchData[item.prop]"
|
||||
format="HH:mm:ss"
|
||||
value-format="HH:mm:ss"
|
||||
:picker-options="item.options||{
|
||||
start: '00:00',
|
||||
step: '00:30',
|
||||
end: '23:30'
|
||||
}"
|
||||
:style="{width:item.width+'px'}"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:placeholder="`请选择${item.placeholder||''}`"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
></el-time-select>
|
||||
<!-- 日期时间 -->
|
||||
<el-date-picker
|
||||
v-if="item.type==='dateTime'"
|
||||
:type="item.timeType||'datetime'"
|
||||
:style="{width:item.width+'px'}"
|
||||
v-model="searchData[item.prop]"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
:size="size || item.size"
|
||||
:placeholder="`请选择${item.placeholder||''}`"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
></el-date-picker>
|
||||
<!-- 滑块 -->
|
||||
<!-- <el-slider v-if="item.type==='Slider'" v-model="searchData[item.prop]"></el-slider> -->
|
||||
<!-- 开关 -->
|
||||
<el-switch
|
||||
v-if="item.type==='switch'"
|
||||
v-model="searchData[item.prop]"
|
||||
:size="size || item.size"
|
||||
:active-value="item.values&&item.values[0]"
|
||||
:inactive-value="item.values&&item.values[1]"
|
||||
@change="item.change && item.change(searchData[item.prop])"
|
||||
:style="{width:item.width+'px'}"
|
||||
:disabled="item.isDisabled && item.isDisabled(searchData[item.prop])"
|
||||
></el-switch>
|
||||
<!-- 图片上传 -->
|
||||
<section v-if="item.type==='upload'" :style="{width:item.width+'px'}">
|
||||
<el-upload
|
||||
v-loading="loading"
|
||||
class="avatar-uploader"
|
||||
:action="upload_url+'/common/upload'"
|
||||
:show-file-list="false"
|
||||
:on-success="item.success"
|
||||
:on-error="handleAvatarError"
|
||||
:on-progress="handleAvatarProgress"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
name="file"
|
||||
>
|
||||
<img v-if="searchData[item.prop]" :src="searchData[item.prop]|formatImg" class="avatar" />
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</section>
|
||||
<!-- 多图片上传 -->
|
||||
<section v-if="item.type==='uploadList'" :style="{width:item.width+'px'}">
|
||||
<el-upload
|
||||
ref="pictureCard"
|
||||
v-loading="loading"
|
||||
:action="upload_url+'/common/upload'"
|
||||
list-type="picture-card"
|
||||
:multiple="true"
|
||||
:limit="item.limit||9"
|
||||
:fileList="fileList"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:on-error="handleAvatarError"
|
||||
:on-progress="handleAvatarProgress"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
:on-remove="handleRemove"
|
||||
:on-exceed="handleExceed"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:headers="{'Authorization':$cookie.get('token')}"
|
||||
name="file"
|
||||
>
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
<el-dialog :visible.sync="dialogVisible" title="预览" width="600px">
|
||||
<img width="100%" :src="dialogImageUrl" alt />
|
||||
</el-dialog>
|
||||
</section>
|
||||
<!-- 富文本 -->
|
||||
<r-tinymce
|
||||
v-if="item.type==='tinymce'"
|
||||
v-model="searchData[item.prop]"
|
||||
:height="300"
|
||||
:width="600"
|
||||
></r-tinymce>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item v-for="(item,i) in searchHandle" :key="'searchBtn'+i">
|
||||
<!-- <el-button type="primary" @click="onSubmit">{{item.label}}</el-button> -->
|
||||
<el-button
|
||||
v-if="(item.isShow===undefined && item.theme===undefined)?true:item.isShow&& item.isShow()"
|
||||
:disabled="item.isDisabled && item.isDisabled(item)"
|
||||
class="el-button el-button--medium"
|
||||
:class="getBtnClass(item)"
|
||||
:style="{width:item.width+'px'}"
|
||||
@click="getHandle(item.handle)"
|
||||
@mouseleave="mouseleave(item.icon)"
|
||||
@mouseenter="mouseenter(item.icon)"
|
||||
>
|
||||
<i :class="upCir(item.icon)"></i>
|
||||
{{item.label}}</el-button>
|
||||
<div v-if="item.theme==='upload'">
|
||||
<input ref="excel-upload-input" class="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick">
|
||||
<el-button :loading="item.loading" :size="item.size || size" type="success" icon="el-icon-upload2" @click="handleUpload">
|
||||
{{item.label}}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "Search",
|
||||
props: {
|
||||
labelPosition:{
|
||||
type: String,
|
||||
default: "none"
|
||||
},
|
||||
isState:{
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isHandle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
labelWidth: {
|
||||
type: String,
|
||||
default: "100px",
|
||||
},
|
||||
// 搜索框型号:mini,medium,small
|
||||
size: {
|
||||
type: String,
|
||||
default: "medium",
|
||||
},
|
||||
searchForm: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
searchHandle: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
searchData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
searchRules: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
fileList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
imageUrl: "",
|
||||
upload_url: process.env.NODE_ENV !== 'production'?'/proxy':process.env.VUE_APP_URL,
|
||||
imgurl: process.env.VUE_APP_IMG,
|
||||
dialogVisible: false,
|
||||
dialogImageUrl:'',
|
||||
isMouse:false,
|
||||
isLoading:false,
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '最近一周',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近三个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
getInputStyle(){
|
||||
return (width)=>{
|
||||
if (width) {
|
||||
return `${width}+px`;
|
||||
}
|
||||
return '180px'
|
||||
}
|
||||
},
|
||||
upCir(){
|
||||
return (icon)=>{
|
||||
if (this.loading&&icon==='el-icon-refresh') {
|
||||
if (this.loading) {
|
||||
return `el-icon-loading`
|
||||
}
|
||||
return `el-icon-refresh`;
|
||||
}
|
||||
else if (this.isMouse&&icon==='el-icon-refresh') {
|
||||
return `good el-icon-refresh-left`
|
||||
}
|
||||
else {
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getBtnClass(){
|
||||
return (row)=>{
|
||||
let str=``,bbs=row.icon=='el-icon-refresh'?true:false;
|
||||
str+=`el-button--`+row.type+` `
|
||||
// str+=row.size?`el-button--`+row.size+` `:``
|
||||
if (this.loading&&bbs) {
|
||||
str+=`is-disabled`
|
||||
}
|
||||
return str;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getHandle(func){
|
||||
func.call(func)
|
||||
|
||||
},
|
||||
mouseenter(icon){
|
||||
if (icon==='el-icon-refresh') {
|
||||
this.isMouse=true;
|
||||
}
|
||||
},
|
||||
mouseleave(icon){
|
||||
if (icon==='el-icon-refresh') {
|
||||
this.isMouse=false;
|
||||
}
|
||||
},
|
||||
|
||||
BlurText(e) {
|
||||
let boolean = new RegExp("^[1-9][0-9]*$").test(e.target.value)
|
||||
if(!boolean) {
|
||||
this.$message.warning('请输入正整数')
|
||||
e.target.value = ' '
|
||||
}
|
||||
},
|
||||
handleAvatarSuccess(res, file) {
|
||||
this.loading = false;
|
||||
this.imageUrl = URL.createObjectURL(file.raw);
|
||||
this.$message({
|
||||
message: "上传成功",
|
||||
type: "success",
|
||||
});
|
||||
this.$emit("imgs", {
|
||||
type: "text",
|
||||
url: `${res.data}`,
|
||||
});
|
||||
},
|
||||
handleUpload() {
|
||||
this.$refs['excel-upload-input'][0].click()
|
||||
},
|
||||
handleClick(e){
|
||||
const files = e.target.files
|
||||
const rawFile = files[0] // only use files[0]
|
||||
if (!rawFile) return
|
||||
//this.upload(rawFile)
|
||||
this.$emit("uploadEX", rawFile);
|
||||
},
|
||||
upload(rawFile) {
|
||||
this.$refs['excel-upload-input'][0].value = null // fix can't select the same excel
|
||||
const before = this.beforeUpload(rawFile)
|
||||
if (before) {
|
||||
let formData = new FormData();
|
||||
formData.append('file',rawFile);
|
||||
this.$http.upload('/file/upload',formData).then(res=>{
|
||||
if(res.code == 200){
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: "上传成功",
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const isLt1M = file.size / 1024 / 1024 < 1
|
||||
if (isLt1M) {
|
||||
return true
|
||||
}
|
||||
this.$message({
|
||||
message: '小于1兆',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
},
|
||||
handleAvatarError() {
|
||||
this.loading = false;
|
||||
this.$message.error("上传失败");
|
||||
},
|
||||
beforeAvatarUpload(file) {
|
||||
const isJPG = file.type === "image/jpeg" || "image/png";
|
||||
const isLt5M = file.size / 1024 / 1024 < 5;
|
||||
if (!isJPG) {
|
||||
this.$message.error("上传格式只能是图片格式!");
|
||||
}
|
||||
if (!isLt5M) {
|
||||
this.$message.error("上传头像图片大小不能超过 5MB!");
|
||||
}
|
||||
return isJPG && isLt5M;
|
||||
},
|
||||
handleAvatarProgress(res, file) {
|
||||
this.loading = true;
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
let list = fileList.map((item) => {
|
||||
console.log(item)
|
||||
if(item.response){
|
||||
return item.response.data
|
||||
}else{
|
||||
if(item.url.indexOf('http')!=-1){
|
||||
return item.url.split(process.env.VUE_APP_IMG)[1]
|
||||
}else{
|
||||
return item.url
|
||||
}
|
||||
}
|
||||
});
|
||||
this.$emit("imgs", {
|
||||
type: "pictureCard",
|
||||
url: list,
|
||||
});
|
||||
},
|
||||
handleExceed() {
|
||||
this.$message({
|
||||
message: `最多上传${this.$refs.pictureCard[0].limit||9}张图片`,
|
||||
type: "warning",
|
||||
});
|
||||
},
|
||||
handlePictureCardPreview(file){
|
||||
this.dialogImageUrl = file.url;
|
||||
this.dialogVisible = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.ces-search {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
flex-wrap: wrap;
|
||||
align-items:center;
|
||||
}
|
||||
@keyframes circles{
|
||||
0%{transform:rotateZ(0deg);}
|
||||
100%{transform:rotateZ(360deg);}
|
||||
}
|
||||
.good{
|
||||
animation-name:circles;
|
||||
animation-duration:3s;
|
||||
animation-iteration-count:1;
|
||||
}
|
||||
.avatar-uploader,
|
||||
.el-upload {
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.avatar-uploader:hover,
|
||||
.el-upload:hover {
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
line-height: 150px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.excel-upload-input{
|
||||
display: none;
|
||||
z-index: -9999;
|
||||
}
|
||||
</style>
|
||||
485
resources/frontend/src/components/global/Table/index.vue
Normal file
485
resources/frontend/src/components/global/Table/index.vue
Normal file
@ -0,0 +1,485 @@
|
||||
<!--表格组件 -->
|
||||
<template>
|
||||
<section class="ces-table-pagee flex_column flex1">
|
||||
<slot></slot>
|
||||
<!-- 表格操作按钮 -->
|
||||
<section class="ces-handle" v-if="isHandle" style="margin-bottom: 20px;">
|
||||
<!-- <section class="ces-handle" v-if="isHandle"> -->
|
||||
<el-button
|
||||
v-for="item in tableHandles"
|
||||
v-if="item.isShow ? item.isShow():true"
|
||||
:disabled="item.isDisabled && item.isDisabled()"
|
||||
:key="item.label"
|
||||
:size="size || item.size"
|
||||
:type="item.type"
|
||||
:icon="item.icon"
|
||||
@click="item.handle"
|
||||
>{{item.label}}</el-button>
|
||||
<slot name="tip"></slot>
|
||||
</section>
|
||||
<!-- 数据表格 -->
|
||||
<section class="ces-table flex1" ref="tableBody">
|
||||
<el-table
|
||||
:data="tableData"
|
||||
:size="size"
|
||||
:border="isBorder"
|
||||
@select="select"
|
||||
@select-all="selectAll"
|
||||
@current-change="CurrentChange"
|
||||
:highlightCurrentRow="highlightCurrentRow"
|
||||
:row-class-name="tableRowClassName"
|
||||
v-loading="loading"
|
||||
:defaultSelections="defaultSelections"
|
||||
ref="cesTable"
|
||||
:row-key="rowKey"
|
||||
:height="height"
|
||||
:header-cell-style="{backgroundColor: '#f5f7fa',fontWeight: 'bold',color: '#909399'}"
|
||||
:tree-props="treeProps"
|
||||
>
|
||||
<el-table-column v-if="isSelection" type="selection" align="center" sortable></el-table-column>
|
||||
<el-table-column v-if="isIndex" type="index" sortable :label="indexLabel" align="center" width="80" :index="indexMethod"></el-table-column>
|
||||
<!-- 数据栏 -->
|
||||
<el-table-column
|
||||
v-for="(item,idx) in tableCols"
|
||||
:key="idx"
|
||||
:prop="item.prop"
|
||||
:label="item.btnLabel||item.label"
|
||||
:width="item.width"
|
||||
:min-width="item.minWidth"
|
||||
:align="item.align || 'center'"
|
||||
:fixed="item.fixed"
|
||||
:render-header="item.require?renderHeader:null"
|
||||
:show-overflow-tooltip="isOverflow"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<!-- html -->
|
||||
<span v-if="item.type==='html'" v-html="item.html(scope.row)"></span>
|
||||
<!-- tag -->
|
||||
<el-tag
|
||||
v-if="item.type==='tag'"
|
||||
:type="item.theme && item.theme(scope.row)"
|
||||
>{{(item.formatter && item.formatter(scope.row)) || scope.row[item.prop]}}</el-tag>
|
||||
<!-- 按钮 -->
|
||||
<span v-if="item.type==='button'">
|
||||
<el-button
|
||||
v-for="(btn,idx) in item.btnList"
|
||||
:key="idx"
|
||||
:disabled="btn.isDisabled&& btn.isDisabled(scope.row)"
|
||||
v-if="btn.isShow?btn.isShow(scope.row):true"
|
||||
:type="btn.type"
|
||||
:size="btn.size || size"
|
||||
:icon="btn.icon"
|
||||
:circle="btn.circle||false"
|
||||
@click="btn.handle(scope.row,scope.$index)"
|
||||
>{{btn.label}}</el-button>
|
||||
<el-dropdown v-if="item.dropList" @command="item.handleCommand" trigger="click">
|
||||
<el-button icon="el-icon-setting" :size="item.dropSize || size" type="info" />
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item
|
||||
v-for="(drop,idx) in item.dropList"
|
||||
:key="idx"
|
||||
:command="{btn:drop.label,row:scope.row}"
|
||||
:disabled="drop.isDisabled && drop.isDisabled(scope.row)"
|
||||
>{{drop.label}}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
<!-- 输入框 -->
|
||||
<el-input
|
||||
v-if="item.type==='input'"
|
||||
v-model="scope.row[item.prop]"
|
||||
:size="size || btn.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(scope.row)"
|
||||
:placeholder="item.placeholder || '请输入'"
|
||||
@focus="item.focus && item.focus(scope.row)"
|
||||
@input="item.input && item.input(scope.row,scope.$index)"
|
||||
@change="item.change && item.change(scope.row,scope.$index)"
|
||||
></el-input>
|
||||
<!-- 下拉框 -->
|
||||
<el-select
|
||||
v-if="item.type==='select'"
|
||||
v-model="scope.row[item.prop]"
|
||||
:size="size || btn.size"
|
||||
:disabled="item.isDisabled && item.isDisabled(scope.row)"
|
||||
@change="item.change && item.change(scope.row)"
|
||||
>
|
||||
<el-option
|
||||
v-for="(op,idx) in item.options"
|
||||
:label="op.label"
|
||||
:value="op.value"
|
||||
:key="idx"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<!-- 级联省市区 -->
|
||||
<el-cascader
|
||||
v-if="item.type==='cascader'"
|
||||
:style="{width:item.width+'px'}"
|
||||
:placeholder="item.placeholder || '请选择'"
|
||||
:options="item.options || []"
|
||||
v-model="scope.row[item.prop]"
|
||||
@focus="item.focus && item.focus(scope.row)"
|
||||
filterable
|
||||
clearable
|
||||
:props="{ expandTrigger: 'hover',checkStrictly: true }"
|
||||
@change="item.change && item.change(scope.row)"
|
||||
></el-cascader>
|
||||
<!-- 单选 -->
|
||||
<el-radio-group
|
||||
v-if="item.type==='radio'"
|
||||
v-model="scope.row[item.prop]"
|
||||
:disabled="item.isDisabled && item.isDisabled(scope.row)"
|
||||
:size="size || btn.size"
|
||||
@change="item.change && item.change(scope.row)"
|
||||
>
|
||||
<el-radio v-for="(ra,idx) in item.radios" :label="ra.value" :key="idx">{{ra.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
<!-- 复选框 -->
|
||||
<el-checkbox-group
|
||||
v-if="item.type==='checkbox'"
|
||||
v-model="scope.row[item.prop]"
|
||||
:disabled="item.isDisabled && item.isDisabled(scope.row)"
|
||||
:size="size || btn.size"
|
||||
@change="item.change && item.change(scope.row)"
|
||||
>
|
||||
<el-checkbox
|
||||
v-for="(ra,idx) in item.checkboxs"
|
||||
:label="ra.value"
|
||||
:key="idx"
|
||||
>{{ra.label}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<!-- 评价 -->
|
||||
<el-rate
|
||||
v-if="item.type==='rate'"
|
||||
:value ="scope.row[item.prop]*1"
|
||||
:allow-half="true"
|
||||
:disabled="item.isDisabled && item.isDisabled(scope.row)"
|
||||
:size="size || btn.size"
|
||||
@change="item.change && item.change(scope.row)"
|
||||
></el-rate>
|
||||
<!-- 开关 -->
|
||||
<el-switch
|
||||
v-if="item.type==='switch'"
|
||||
v-model="scope.row[item.prop]"
|
||||
:size="size || btn.size"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
:active-value="item.values&&item.values[0]"
|
||||
:inactive-value="item.values&&item.values[1]"
|
||||
:disabled="item.isDisabled && item.isDisabled(scope.row)"
|
||||
@change="item.change && item.change(scope.row)"
|
||||
></el-switch>
|
||||
<!-- 二维码 -->
|
||||
<el-popover
|
||||
v-if="item.type==='qrCode'"
|
||||
:placement="item.placement || 'left'"
|
||||
trigger="click"
|
||||
id="qrcode"
|
||||
>
|
||||
<div>
|
||||
<vue-qr
|
||||
:logo-src="item.logoSrc"
|
||||
:size="300"
|
||||
:margin="10"
|
||||
:auto-color="true"
|
||||
:dot-scale="1"
|
||||
:text="(item.formatter && item.formatter(scope.row)) || (scope.row[item.prop]===0?0:scope.row[item.prop]?scope.row[item.prop]:'-')" />
|
||||
</div>
|
||||
<vue-qr
|
||||
slot="reference"
|
||||
:logo-src="item.logoSrc"
|
||||
:size="100"
|
||||
:margin="10"
|
||||
:auto-color="true"
|
||||
:dot-scale="1"
|
||||
:text="(item.formatter && item.formatter(scope.row)) || (scope.row[item.prop]===0?0:scope.row[item.prop]?scope.row[item.prop]:'-')" />
|
||||
</el-popover>
|
||||
<!-- 单图像 -->
|
||||
<!-- <img v-if="item.type==='image'" :src="scope.row[item.prop]" @click="item.handle && item.handle(scope.row)"/> -->
|
||||
<el-popover
|
||||
v-if="item.type==='image'"
|
||||
:placement="item.placement || 'left'"
|
||||
trigger="click"
|
||||
>
|
||||
<div>
|
||||
<el-image
|
||||
style="width: 300px;height: auto;"
|
||||
:src="scope.row[item.prop]|formatImg"
|
||||
fit="fill"
|
||||
></el-image>
|
||||
</div>
|
||||
<el-image
|
||||
:style="item.style || 'width: 80px;height: 80px;'"
|
||||
:src="scope.row[item.prop]|formatImg"
|
||||
fit="contain"
|
||||
slot="reference"
|
||||
></el-image>
|
||||
</el-popover>
|
||||
<!-- 多图像 -->
|
||||
<el-popover
|
||||
v-if="item.type==='images'"
|
||||
:placement="item.placement || 'left'"
|
||||
trigger="click"
|
||||
>
|
||||
<div>
|
||||
<el-carousel
|
||||
trigger="click"
|
||||
style="width: 300px;height: auto;"
|
||||
arrow="always"
|
||||
indicator-position="none"
|
||||
:autoplay="false"
|
||||
>
|
||||
<el-carousel-item v-for="(url,idx) in imgList(scope.row[item.prop])" :key="idx">
|
||||
<img :src="url|formatImg" alt style="width: 300px;height: auto;" />
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
</div>
|
||||
<el-button type="text" slot="reference">查看</el-button>
|
||||
</el-popover>
|
||||
<!-- 滑块 -->
|
||||
<el-slider
|
||||
v-if="item.type==='slider'"
|
||||
v-model="scope.row[item.prop]"
|
||||
:disabled="item.isDisabled && item.isDisabled(scope.row)"
|
||||
:size="size || btn.size"
|
||||
@change="item.change && item.change(scope.row)"
|
||||
></el-slider>
|
||||
<!-- 默认 -->
|
||||
<span
|
||||
v-if="!item.type"
|
||||
@click="item.handle && item.handle(scope.row)"
|
||||
:style="item.itemStyle && item.itemStyle(scope.row)"
|
||||
:class="item.itemClass && item.item.itemClass(scope.row)"
|
||||
>{{(item.formatter && item.formatter(scope.row)) || (scope.row[item.prop]===0?0:scope.row[item.prop]?scope.row[item.prop]:'-')}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<div slot="empty">
|
||||
<p>
|
||||
<img src="~@/assets/img/original.png" width="163" height="100" />
|
||||
</p>
|
||||
<p>
|
||||
<span>当前暂无数据,请添加数据</span>
|
||||
</p>
|
||||
</div>
|
||||
</el-table>
|
||||
</section>
|
||||
<!-- 分页 -->
|
||||
<section class="ces-pagination" v-if="isPagination">
|
||||
<el-pagination
|
||||
style="display: flex;justify-content: star;align-items: center;"
|
||||
@current-change="handleCurrentChange"
|
||||
@size-change="handleSizeChange"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total,sizes ,prev, pager, next,jumper"
|
||||
:page-size="tablePage[pagination[0]] || tablePage.size"
|
||||
:current-page="tablePage[pagination[1]] || tablePage.offset"
|
||||
:total="tablePage[pagination[2]] || tablePage.total"
|
||||
></el-pagination>
|
||||
</section>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import VueQr from 'vue-qr';
|
||||
export default {
|
||||
name: "Table",
|
||||
// components: {VueQr},
|
||||
props: {
|
||||
// 表格型号:mini,medium,small
|
||||
size: {
|
||||
type: String,
|
||||
default: "medium",
|
||||
},
|
||||
rowKey:{
|
||||
type: String,
|
||||
default: "id",
|
||||
},
|
||||
isOverflow: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isBorder: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 表格操作
|
||||
isHandle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
tableHandles: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 表格数据
|
||||
tableData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 表格列配置
|
||||
tableCols: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 是否显示表格复选框
|
||||
isSelection: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
defaultSelections: {
|
||||
type: [Array, Object],
|
||||
default: () => null,
|
||||
},
|
||||
// 是否显示表格索引
|
||||
isIndex: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
indexLabel: {
|
||||
type: String,
|
||||
default: "序号",
|
||||
},
|
||||
// 是否显示分页
|
||||
isPagination: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 分页数据
|
||||
tablePage: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
size: 10,
|
||||
page: 1,
|
||||
total: 0,
|
||||
}),
|
||||
},
|
||||
highlightCurrentRow: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
treeProps:{
|
||||
type: Object,
|
||||
default: () => ({children: 'children', hasChildren: 'hasChildren'}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
height: 0,
|
||||
imgurl: process.env.VUE_APP_IMG,
|
||||
pagination:[]
|
||||
//imgurl:'http://s302t98620.zicp.vip:44353/car/img/'
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
defaultSelections(val) {
|
||||
this.$nextTick(function () {
|
||||
if (Array.isArray(val)) {
|
||||
val.forEach((row) => {
|
||||
this.$refs.cesTable.toggleRowSelection(row);
|
||||
});
|
||||
} else {
|
||||
this.$refs.cesTable.toggleRowSelection(val);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if(this.pagination && this.pagination.length==0){
|
||||
Object.keys(this.tablePage).forEach(key=>{
|
||||
this.pagination.push(key)
|
||||
})
|
||||
}
|
||||
this.$nextTick((_) => {
|
||||
this.$parent.$el.className = "flex_column";
|
||||
this.$parent.$el.style.height = "100%";
|
||||
this.height = this.$refs.tableBody.clientHeight;
|
||||
console.log('mounted:this.height'+this.height);
|
||||
// this.height = 500;
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
getSort(){
|
||||
return (index)=>{
|
||||
return !Boolean(index)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
indexMethod(index){
|
||||
return (this.tablePage[this.pagination[1]]-1)*this.tablePage[this.pagination[0]]+index+1
|
||||
},
|
||||
// 表格勾选
|
||||
select(rows, row) {
|
||||
this.$emit("select", rows, row);
|
||||
},
|
||||
// 全选
|
||||
selectAll(rows) {
|
||||
this.$emit("select", rows);
|
||||
},
|
||||
//
|
||||
handleCurrentChange(val) {
|
||||
this.tablePage[this.pagination[1]] = val;
|
||||
this.$emit("refresh", {
|
||||
[this.pagination[0]]: this.tablePage[this.pagination[0]],
|
||||
[this.pagination[1]]: this.tablePage[this.pagination[1]],
|
||||
});
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.tablePage[this.pagination[0]] = val;
|
||||
this.$emit("refresh", {
|
||||
[this.pagination[0]]: this.tablePage[this.pagination[0]],
|
||||
[this.pagination[1]]: this.tablePage[this.pagination[1]],
|
||||
});
|
||||
},
|
||||
CurrentChange(val) {
|
||||
this.$emit("radio", val);
|
||||
},
|
||||
imgList(img) {
|
||||
if (img) {
|
||||
let arr = img.split(",").map(item=>{
|
||||
return item.startsWith('http') ? item : process.env.VUE_APP_IMG + item;
|
||||
})
|
||||
return arr;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
tableRowClassName({ row, rowIndex }) {
|
||||
//获取当前点击行下标
|
||||
row.index = rowIndex;
|
||||
},
|
||||
renderHeader(h, obj) {
|
||||
return h(
|
||||
"span",
|
||||
{
|
||||
class: "ces-table-require",
|
||||
},
|
||||
obj.column.label
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.ces-table-require::before {
|
||||
content: "*";
|
||||
color: red;
|
||||
}
|
||||
|
||||
.el-button + .el-dropdown {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.ces-handle{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
/* .ces-table-page{
|
||||
margin-top: 20px;
|
||||
padding: 0 30px;
|
||||
} */
|
||||
</style>
|
||||
|
||||
9
resources/frontend/src/components/global/index.js
vendored
Normal file
9
resources/frontend/src/components/global/index.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
const componentsContext = require.context('./', true, /index\.vue$/);
|
||||
|
||||
componentsContext.keys().forEach(component => {
|
||||
const componentConfig = componentsContext(component);
|
||||
const ctrl = componentConfig.default || componentConfig;
|
||||
Vue.component(`r-${ctrl.name.substr(0,1).toLocaleLowerCase()+ctrl.name.substr(1)}`, ctrl)
|
||||
});
|
||||
9
resources/frontend/src/main.js
vendored
9
resources/frontend/src/main.js
vendored
@ -3,13 +3,20 @@ import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
import ElementUI from "element-ui";
|
||||
import httpRequest from '@/util/https'
|
||||
import msg from '@/util/msg'
|
||||
import "element-ui/lib/theme-chalk/index.css";
|
||||
import "@/css/style.css";
|
||||
import '@/assets/scss/index.scss'
|
||||
import "./router/main";
|
||||
import '@/components/global'
|
||||
import echarts from '@/util/echartUi.js'
|
||||
|
||||
Vue.use(ElementUI);
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
Vue.prototype.$http = httpRequest
|
||||
Vue.prototype.$msg = msg
|
||||
Vue.prototype.$chart = echarts
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
|
||||
47
resources/frontend/src/router/list.js
vendored
47
resources/frontend/src/router/list.js
vendored
@ -115,6 +115,53 @@ const list = [
|
||||
name: "供应商列表",
|
||||
component: () => import("../views/supplier/supplierList.vue"),
|
||||
},
|
||||
{
|
||||
path: "putWarehouse",
|
||||
name: "商品入库",
|
||||
component: () => import("../views/stock/putWarehouse.vue"),
|
||||
},
|
||||
{
|
||||
path: "stockNotice",
|
||||
name: "库存预警",
|
||||
component: () => import("../views/stock/stockNotice.vue"),
|
||||
},
|
||||
|
||||
{
|
||||
path: "stockTacks",
|
||||
name: "盘点报损",
|
||||
component: () => import("../views/stock/stockTacks.vue"),
|
||||
},
|
||||
{
|
||||
path: "message",
|
||||
name: "消息列表",
|
||||
component: () => import("../views/message/message.vue"),
|
||||
},
|
||||
|
||||
{
|
||||
path: "salesChart",
|
||||
name: "销售图表",
|
||||
component: () => import("../views/dataCenter/salesChart.vue"),
|
||||
},
|
||||
{
|
||||
path: "goodChart",
|
||||
name: "商品图表",
|
||||
component: () => import("../views/dataCenter/goodChart.vue"),
|
||||
},
|
||||
{
|
||||
path: "flagChart",
|
||||
name: "交易趋势图表",
|
||||
component: () => import("../views/dataCenter/flagChart.vue"),
|
||||
},
|
||||
{
|
||||
path: "damageChart",
|
||||
name: "报损图表",
|
||||
component: () => import("../views/dataCenter/damageChart.vue"),
|
||||
},
|
||||
{
|
||||
path: "costChart",
|
||||
name: "交易趋势图表",
|
||||
component: () => import("../views/dataCenter/costChart.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
1
resources/frontend/src/util/area2.js
vendored
Normal file
1
resources/frontend/src/util/area2.js
vendored
Normal file
File diff suppressed because one or more lines are too long
36
resources/frontend/src/util/echartUi.js
vendored
Normal file
36
resources/frontend/src/util/echartUi.js
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
|
||||
import * as echarts from 'echarts';
|
||||
// 引入柱状图图表,图表后缀都为 Chart
|
||||
import { BarChart,LineChart,PieChart } from 'echarts/charts';
|
||||
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
|
||||
import {
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
DatasetComponent,
|
||||
TransformComponent,
|
||||
LegendComponent,
|
||||
ToolboxComponent,
|
||||
} from 'echarts/components';
|
||||
// 标签自动布局,全局过渡动画等特性
|
||||
import { LabelLayout, UniversalTransition } from 'echarts/features';
|
||||
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
|
||||
// 注册必须的组件
|
||||
echarts.use([
|
||||
ToolboxComponent,
|
||||
LegendComponent,
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
DatasetComponent,
|
||||
TransformComponent,
|
||||
BarChart,
|
||||
LabelLayout,
|
||||
UniversalTransition,
|
||||
CanvasRenderer,
|
||||
LineChart,
|
||||
PieChart
|
||||
]);
|
||||
export default echarts
|
||||
44
resources/frontend/src/util/http.js
vendored
44
resources/frontend/src/util/http.js
vendored
@ -2,9 +2,15 @@ import axios from "axios";
|
||||
import { getToken } from "@/util/auth";
|
||||
import NProgress from "nprogress";
|
||||
import "nprogress/nprogress.css";
|
||||
import qs from 'qs'
|
||||
import merge from 'lodash/merge'
|
||||
import { Message } from "element-ui";
|
||||
var instance = axios.create({
|
||||
timeout: 360000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
}
|
||||
});
|
||||
|
||||
instance.interceptors.request.use(
|
||||
@ -54,5 +60,43 @@ instance.interceptors.response.use(
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
instance.adornParams = (params = {}, openDefultParams = false) => {
|
||||
var defaults = {
|
||||
't': new Date().getTime()
|
||||
}
|
||||
return openDefultParams ? merge(defaults, params) : params
|
||||
}
|
||||
|
||||
instance.adornData = (data = {}, openDefultdata = false, contentType = 'json') => {
|
||||
var defaults = {
|
||||
't': new Date().getTime()
|
||||
}
|
||||
data = openDefultdata ? merge(defaults, data) : data
|
||||
return contentType === 'json' ? JSON.stringify(data) : qs.stringify(data)
|
||||
}
|
||||
instance.adornUrl = (actionName) => {
|
||||
//return (process.env.NODE_ENV !== 'production' && process.env.OPEN_PROXY ? 'proxyApi/' : process.env.VUE_APP_URL) + actionName
|
||||
if (process.env.VUE_APP_API_NODE !== 'production' && process.env.VUE_APP_API_PROXY_PREFIX) {
|
||||
console.log(111111111);
|
||||
return `${actionName}`
|
||||
} else {
|
||||
console.log(111111111);
|
||||
env.VUE_APP_BASE_URL + actionName
|
||||
}
|
||||
}
|
||||
instance.get = (url, query) => {
|
||||
return instance({
|
||||
url: instance.adornUrl(url),
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
instance.post = (url, data = {}) => {
|
||||
return instance({
|
||||
url: instance.adornUrl(url),
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
export default instance;
|
||||
|
||||
106
resources/frontend/src/util/https.js
vendored
Normal file
106
resources/frontend/src/util/https.js
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
import axios from "axios";
|
||||
import { getToken } from "@/util/auth";
|
||||
import NProgress from "nprogress";
|
||||
import "nprogress/nprogress.css";
|
||||
import qs from 'qs'
|
||||
import merge from 'lodash/merge'
|
||||
import { Message } from "element-ui";
|
||||
|
||||
const http = axios.create({
|
||||
timeout: 1000 * 50,
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
})
|
||||
|
||||
axios.defaults.withCredentials = true;
|
||||
axios.defaults.changeOrigin = true;
|
||||
|
||||
|
||||
http.interceptors.request.use(
|
||||
(config) => {
|
||||
// config.headers['content-type'] = 'application/json'
|
||||
|
||||
// config.headers['Shop-Id'] = localStorage.getItem('shopId') || 1
|
||||
|
||||
// 在发送请求之前做些什么
|
||||
// config.headers['content-type'] = 'application/json'
|
||||
config.headers.Authorization = "Bearer " + getToken(); // 请求头
|
||||
NProgress.start();
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 对请求错误做些什么
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 添加响应拦截器
|
||||
http.interceptors.response.use(
|
||||
(response) => {
|
||||
NProgress.done();
|
||||
console.log('添加响应拦截器'+response);
|
||||
const res = response.status;
|
||||
// 对响应数据做点什么
|
||||
if (res === 200 || res === 201) {
|
||||
return response.data
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log(error.response);
|
||||
NProgress.done();
|
||||
// 对响应错误做点什么
|
||||
if (error.response.status === 400) {
|
||||
Message({
|
||||
message: error.response.data.errorMessage,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
|
||||
if (error.response.status === 500) {
|
||||
Message({
|
||||
message: error.response.data.message,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
http.adornParams = (params = {}, openDefultParams = false) => {
|
||||
var defaults = {
|
||||
't': new Date().getTime()
|
||||
}
|
||||
return openDefultParams ? merge(defaults, params) : params
|
||||
}
|
||||
|
||||
http.adornData = (data = {}, openDefultdata = false, contentType = 'json') => {
|
||||
var defaults = {
|
||||
't': new Date().getTime()
|
||||
}
|
||||
data = openDefultdata ? merge(defaults, data) : data
|
||||
return contentType === 'json' ? JSON.stringify(data) : qs.stringify(data)
|
||||
}
|
||||
http.adornUrl = (actionName) => {
|
||||
if (process.env.VUE_APP_API_NODE !== 'production' && process.env.VUE_APP_API_PROXY_PREFIX) {
|
||||
return process.env.VUE_APP_API_PROXY_PREFIX+`${actionName}`
|
||||
} else {
|
||||
process.env.VUE_APP_BASE_URL + actionName
|
||||
}
|
||||
}
|
||||
http.get = (url, query) => {
|
||||
return http({
|
||||
url: http.adornUrl(url),
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
http.post = (url, data = {}) => {
|
||||
return http({
|
||||
url: http.adornUrl(url),
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
export default http;
|
||||
58
resources/frontend/src/util/msg.js
vendored
Normal file
58
resources/frontend/src/util/msg.js
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
import {MessageBox, Message} from 'element-ui'
|
||||
|
||||
const message = (msg, type) => {
|
||||
Message({
|
||||
showClose: true,
|
||||
message: msg,
|
||||
type: type
|
||||
});
|
||||
}
|
||||
//成功
|
||||
const success = (msg) => {
|
||||
message(msg, 'success');
|
||||
}
|
||||
//消息
|
||||
const info = (msg) => {
|
||||
message(msg, 'info');
|
||||
}
|
||||
//错误
|
||||
const error = (msg) => {
|
||||
message(msg, 'error');
|
||||
}
|
||||
//警告
|
||||
const warning = (msg) => {
|
||||
message(msg, 'warning');
|
||||
}
|
||||
|
||||
//ElMessageBox
|
||||
const alert = ({title, msg, okBtnText, func}) => {
|
||||
if (!title) {
|
||||
title = '提示';
|
||||
}
|
||||
if (!msg) {
|
||||
msg = '错误';
|
||||
}
|
||||
if (!okBtnText) {
|
||||
okBtnText = '确定';
|
||||
}
|
||||
MessageBox.alert(msg, title, {
|
||||
confirmButtonText: okBtnText,
|
||||
}).then(func ? func : () => {})
|
||||
}
|
||||
|
||||
const confirm = ({title, msg, func, cFunc}) => {
|
||||
MessageBox.confirm(msg, title ? title:'提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
}).then(func ? func : () => {}).catch(cFunc ? cFunc : () => {});
|
||||
}
|
||||
|
||||
export default {
|
||||
success,
|
||||
info,
|
||||
error,
|
||||
warning,
|
||||
alert,
|
||||
confirm,
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ export default {
|
||||
type: "error",
|
||||
});
|
||||
} else {
|
||||
console.log(11111111);
|
||||
axios.post("/api/auth/login", this.form).then((res) => {
|
||||
let data = res.data;
|
||||
if (data.error) {
|
||||
|
||||
202
resources/frontend/src/views/dataCenter/costChart.vue
Normal file
202
resources/frontend/src/views/dataCenter/costChart.vue
Normal file
@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="boxcard">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="padding-right: 5px;">时间维度</span>
|
||||
<el-radio-group @input="change" v-model="param.time">
|
||||
<el-radio-button v-for="time in list.times" :label="time.value">{{time.label}}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-date-picker
|
||||
@change="change"
|
||||
v-model="param.date"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="daterange"
|
||||
align="right"
|
||||
unlink-panels
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:picker-options="pickerOptions">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div id="canvas" style="height: 300px;width:100%;"></div>
|
||||
</el-card>
|
||||
<!-- 内容 -->
|
||||
<div :style="{height:`${this.contentHeight}px`}">
|
||||
<r-table class="page" :isIndex="false" :tableData="tableData" :tableCols="tableCols" @refresh="init()" >
|
||||
</r-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
param:{keyWord:'week',time:'week'},
|
||||
contentHeight:500,
|
||||
myChart:{},
|
||||
list:{times:[{label:'今日',value:'day'},{label:'昨日',value:'yesterday'},{label:'本周',value:'week'},{label:'本月',value:'month'},{label:'本季',value:'quarter'},{label:'本年',value:'year'}],},
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '最近一周',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近三个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
tableData: [],
|
||||
tableCols:[
|
||||
{ label: "商品类型", prop: "type_name",width:150},
|
||||
{ label: "品牌", prop: "brand_name",width:150},
|
||||
{ label: "商品名称", prop: "good_name",width:150},
|
||||
{ label: "商品sku", prop: "title",width:200},
|
||||
{ label: "SKU销量", prop: "goods_number",width:200},
|
||||
{ label: "实际⼊库", prop: "stock",width:200},
|
||||
{ label: "总量库存", prop: "num",width:200},
|
||||
{ label: "可售库存", prop: "shopStock",width:200},
|
||||
{ label: "采购人员", prop: "buyer_user",width:150},
|
||||
{ label: "操作人员", prop: "operator_user",width:150},
|
||||
{ label: "创建时间", prop: "created_by",width:200},
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let element = document.querySelector('.box-card');
|
||||
let topEl = document.querySelector('.boxcard');
|
||||
this.contentHeight=element.offsetHeight-topEl.offsetHeight-70
|
||||
this.$nextTick(()=>{
|
||||
setTimeout(() => {
|
||||
this.init(this.param)
|
||||
}, 1500);
|
||||
})
|
||||
},
|
||||
methods:{
|
||||
change(e){
|
||||
this.param.keyWord=e
|
||||
this.init(this.param)
|
||||
},
|
||||
init(param={}){
|
||||
this.$http.post('/costChart',Object.assign(param)).then(res=>{
|
||||
if (res.code==200) {
|
||||
this.getCanvas(res.data.field,res.data.data,res.data.sumDate)
|
||||
this.tableData=res.data.list
|
||||
} else {
|
||||
this.$msg.error('获取数据失败,请重新获取~')
|
||||
}
|
||||
})
|
||||
},
|
||||
getCanvas(field=[],data=[],sumCount=[]) {
|
||||
console.log(data);
|
||||
let series=[]
|
||||
this.myChart = this.$chart.init(document.getElementById("canvas"));
|
||||
const option = {
|
||||
color: [
|
||||
'#CCFFFF','#FFCCCC','#99CCCC','#FFCC99','#FF9999','#996699','#CC9999','#FFFFCC','#CCCC99','#FFFF99','#CCCCFF','#0099CC','#CCCCCC','#FF6666','#FF9966','#FFCCCC','#CC9966','#666666','#FF6666','#FFFF66','#99CC66','#CC3333','#CCCCCC','#003366','#663366','#CCCC99','#666666','#FF6666','#FFFF00','#0066CC','#333333','#336633','#990033','#66CC00','#CC99CC','#339933','#993399','#006633',
|
||||
'#CC9966','#003300','#FF0033','#333399','#CCCC00','#003399','#99CC00','#CC0033','#999933','#993333','#333300','#CCFF99','#99CCFF','#99CC99','#336699','#CC9933','#FFCC33','#336666','#99CC33','#FFCC00','#CC6699','#FFFF00','#3366CC','#FF6600','#009966','#990033','#CCFF66','#FF9900','#FF9966','#996600','#CC6600','#999999','#CCCC33','#000000','#999966','#663300','#FF9933','#6666CC'
|
||||
],
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'slider',
|
||||
realtime: true,
|
||||
start: 0,
|
||||
end: 5,
|
||||
height: 5,
|
||||
left: 5,
|
||||
right: 5,
|
||||
bottom: 10,
|
||||
show: true,
|
||||
fillerColor: "rgba(17, 100, 210, 0.42)",
|
||||
borderColor: "rgba(17, 100, 210, 0.12)",
|
||||
handleSize: 0,
|
||||
showDetail: false,
|
||||
zoomLock: true,
|
||||
moveOnMouseMove: false,
|
||||
|
||||
startValue: 0,
|
||||
endValue: 6,
|
||||
minValueSpan: 6,
|
||||
maxValueSpan: 6,
|
||||
},
|
||||
{
|
||||
type: "inside",
|
||||
start: 0,
|
||||
end: 5,
|
||||
zoomOnMouseWheel: false,
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true
|
||||
}
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
width: 500,
|
||||
type: 'scroll',
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: field
|
||||
}
|
||||
],
|
||||
toolbox: {
|
||||
show: true,
|
||||
orient: 'vertical',
|
||||
left: 'right',
|
||||
top: 'center',
|
||||
feature: {
|
||||
mark: { show: true },
|
||||
dataView: { show: true, sreadOnly: false },
|
||||
magicType: { show: true, type: ['stack'] },
|
||||
restore: { show: true },
|
||||
saveAsImage: { show: true }
|
||||
}
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value'
|
||||
}
|
||||
],
|
||||
series: []
|
||||
};
|
||||
Object.keys(data).forEach(key => {
|
||||
console.log(data[key]);
|
||||
series.push({name: key,type: 'bar',stack: 'Ad',emphasis: {focus: 'series'},data:data[key]})
|
||||
});
|
||||
series.push({name: '合计',type: 'bar',data: sumCount,emphasis: {focus: 'series'},markLine: {lineStyle: {type: 'dashed'},data: [[{ type: 'min' }, { type: 'max' }]]}})
|
||||
option.series=series
|
||||
this.myChart.setOption(option);
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
202
resources/frontend/src/views/dataCenter/damageChart.vue
Normal file
202
resources/frontend/src/views/dataCenter/damageChart.vue
Normal file
@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="boxcard">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="padding-right: 5px;">时间维度</span>
|
||||
<el-radio-group @input="change" v-model="param.time">
|
||||
<el-radio-button v-for="time in list.times" :label="time.value">{{time.label}}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-date-picker
|
||||
@change="change"
|
||||
v-model="param.date"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="daterange"
|
||||
align="right"
|
||||
unlink-panels
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:picker-options="pickerOptions">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div id="canvas" style="height: 300px;width:100%;"></div>
|
||||
</el-card>
|
||||
<!-- 内容 -->
|
||||
<div :style="{height:`${this.contentHeight}px`}">
|
||||
<r-table class="page" :isIndex="false" :tableData="tableData" :tableCols="tableCols" @refresh="init()" >
|
||||
</r-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
param:{keyWord:'week',time:'week'},
|
||||
contentHeight:500,
|
||||
myChart:{},
|
||||
list:{times:[{label:'今日',value:'day'},{label:'昨日',value:'yesterday'},{label:'本周',value:'week'},{label:'本月',value:'month'},{label:'本季',value:'quarter'},{label:'本年',value:'year'}],},
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '最近一周',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近三个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
tableData: [],
|
||||
tableCols:[
|
||||
{ label: "商品类型", prop: "type_name",width:150},
|
||||
{ label: "品牌", prop: "brand_name",width:150},
|
||||
{ label: "商品名称", prop: "good_name",width:150},
|
||||
{ label: "商品sku", prop: "title",width:200},
|
||||
{ label: "报损库存", prop: "stock",width:200},
|
||||
{ label: "总量库存", prop: "num",width:200},
|
||||
{ label: "可售库存", prop: "shopStock",width:200},
|
||||
{ label: "采购人员", prop: "buyer_user",width:150},
|
||||
{ label: "操作人员", prop: "operator_user",width:150},
|
||||
{ label: "创建时间", prop: "created_by",width:200},
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let element = document.querySelector('.box-card');
|
||||
let topEl = document.querySelector('.boxcard');
|
||||
this.contentHeight=element.offsetHeight-topEl.offsetHeight-70
|
||||
this.$nextTick(()=>{
|
||||
setTimeout(() => {
|
||||
this.init(this.param)
|
||||
}, 1500);
|
||||
})
|
||||
},
|
||||
methods:{
|
||||
change(e){
|
||||
this.param.keyWord=e
|
||||
this.init(this.param)
|
||||
},
|
||||
init(param={}){
|
||||
this.$http.post('/damageChart',Object.assign(param)).then(res=>{
|
||||
if (res.code==200) {
|
||||
this.getCanvas(res.data.field,res.data.data,res.data.sumDate)
|
||||
this.tableData=res.data.list
|
||||
} else {
|
||||
this.$msg.error('获取数据失败,请重新获取~')
|
||||
}
|
||||
})
|
||||
},
|
||||
getCanvas(field=[],data=[],sumCount=[]) {
|
||||
console.log(data);
|
||||
let series=[]
|
||||
this.myChart = this.$chart.init(document.getElementById("canvas"));
|
||||
console.log(this.myChart);
|
||||
const option = {
|
||||
color: [
|
||||
'#CCFFFF','#FFCCCC','#99CCCC','#FFCC99','#FF9999','#996699','#CC9999','#FFFFCC','#CCCC99','#FFFF99','#CCCCFF','#0099CC','#CCCCCC','#FF6666','#FF9966','#FFCCCC','#CC9966','#666666','#FF6666','#FFFF66','#99CC66','#CC3333','#CCCCCC','#003366','#663366','#CCCC99','#666666','#FF6666','#FFFF00','#0066CC','#333333','#336633','#990033','#66CC00','#CC99CC','#339933','#993399','#006633',
|
||||
'#CC9966','#003300','#FF0033','#333399','#CCCC00','#003399','#99CC00','#CC0033','#999933','#993333','#333300','#CCFF99','#99CCFF','#99CC99','#336699','#CC9933','#FFCC33','#336666','#99CC33','#FFCC00','#CC6699','#FFFF00','#3366CC','#FF6600','#009966','#990033','#CCFF66','#FF9900','#FF9966','#996600','#CC6600','#999999','#CCCC33','#000000','#999966','#663300','#FF9933','#6666CC'
|
||||
],
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'slider',
|
||||
realtime: true,
|
||||
start: 0,
|
||||
end: 5,
|
||||
height: 5,
|
||||
left: 5,
|
||||
right: 5,
|
||||
bottom: 10,
|
||||
show: true,
|
||||
fillerColor: "rgba(17, 100, 210, 0.42)",
|
||||
borderColor: "rgba(17, 100, 210, 0.12)",
|
||||
handleSize: 0,
|
||||
showDetail: false,
|
||||
zoomLock: true,
|
||||
moveOnMouseMove: false,
|
||||
|
||||
startValue: 0,
|
||||
endValue: 6,
|
||||
minValueSpan: 6,
|
||||
maxValueSpan: 6,
|
||||
},
|
||||
{
|
||||
type: "inside",
|
||||
start: 0,
|
||||
end: 5,
|
||||
zoomOnMouseWheel: false,
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true
|
||||
}
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
width: 500,
|
||||
type: 'scroll',
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: field
|
||||
}
|
||||
],
|
||||
toolbox: {
|
||||
show: true,
|
||||
orient: 'vertical',
|
||||
left: 'right',
|
||||
top: 'center',
|
||||
feature: {
|
||||
mark: { show: true },
|
||||
dataView: { show: true, sreadOnly: false },
|
||||
magicType: { show: true, type: ['stack'] },
|
||||
restore: { show: true },
|
||||
saveAsImage: { show: true }
|
||||
}
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value'
|
||||
}
|
||||
],
|
||||
series: []
|
||||
};
|
||||
Object.keys(data).forEach(key => {
|
||||
console.log(data[key]);
|
||||
series.push({name: key,type: 'bar',stack: 'Ad',emphasis: {focus: 'series'},data:data[key]})
|
||||
});
|
||||
series.push({name: '合计',type: 'bar',data: sumCount,emphasis: {focus: 'series'},markLine: {lineStyle: {type: 'dashed'},data: [[{ type: 'min' }, { type: 'max' }]]}})
|
||||
option.series=series
|
||||
this.myChart.setOption(option);
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
146
resources/frontend/src/views/dataCenter/flagChart.vue
Normal file
146
resources/frontend/src/views/dataCenter/flagChart.vue
Normal file
@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="boxcard" style="height: 100%;">
|
||||
<div slot="header" class="clearfix" >
|
||||
<span style="padding-right: 5px;">时间维度</span>
|
||||
<el-radio-group @input="change" v-model="param.time">
|
||||
<el-radio-button v-for="time in list.times" :label="time.value">{{time.label}}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-date-picker
|
||||
@change="change"
|
||||
v-model="param.date"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="daterange"
|
||||
align="right"
|
||||
unlink-panels
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:picker-options="pickerOptions">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div id="canvas" style="min-height: 400px;width:100%;"></div>
|
||||
</el-card>
|
||||
<!-- <div :style="{height:`${this.contentHeight}px`}">
|
||||
<r-table class="page" :isIndex="false" :tableData="tableData" :tableCols="tableCols" @refresh="init()" >
|
||||
</r-table>
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
param:{keyWord:'month',time:'month'},
|
||||
contentHeight:500,
|
||||
myChart:{},
|
||||
list:{times:[{label:'今日',value:'day'},{label:'昨日',value:'yesterday'},{label:'本周',value:'week'},{label:'本月',value:'month'},{label:'本季',value:'quarter'},{label:'本年',value:'year'}],},
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '最近一周',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近三个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
tableData: [],
|
||||
tableCols:[
|
||||
{ label: "商品类型", prop: "type_name",width:150},
|
||||
{ label: "品牌", prop: "brand_name",width:150},
|
||||
{ label: "商品名称", prop: "good_name",width:150},
|
||||
{ label: "商品sku", prop: "title",width:200},
|
||||
{ label: "报损库存", prop: "stock",width:200},
|
||||
{ label: "总量库存", prop: "num",width:200},
|
||||
{ label: "可售库存", prop: "shopStock",width:200},
|
||||
{ label: "采购人员", prop: "buyer_user",width:150},
|
||||
{ label: "操作人员", prop: "operator_user",width:150},
|
||||
{ label: "创建时间", prop: "created_by",width:200},
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let element = document.querySelector('.box-card');
|
||||
let topEl = document.querySelector('.boxcard');
|
||||
this.contentHeight=element.offsetHeight-topEl.offsetHeight-70
|
||||
this.$nextTick(()=>{
|
||||
setTimeout(() => {
|
||||
this.init(this.param)
|
||||
}, 1500);
|
||||
})
|
||||
},
|
||||
methods:{
|
||||
change(e){
|
||||
this.param.keyWord=e
|
||||
this.init(this.param)
|
||||
},
|
||||
init(param={}){
|
||||
this.$http.post('/flagChart',Object.assign(param)).then(res=>{
|
||||
this.getCanvas(res.data.field,res.data.data)
|
||||
})
|
||||
},
|
||||
getCanvas(field=[],data=[]) {
|
||||
console.log(data);
|
||||
let series=[]
|
||||
this.myChart = this.$chart.init(document.getElementById("canvas"));
|
||||
let option = {
|
||||
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: ['订单金额', '退款金额']
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {}
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: field
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: []
|
||||
};
|
||||
Object.keys(data).forEach(key => {
|
||||
console.log(key);
|
||||
|
||||
});
|
||||
series.push({name: '订单金额',type: 'line',stack: 'Total',data:data['goods_cost_price']})
|
||||
series.push({name: '退款金额',type: 'line',stack: 'Total',data:data['refund_amount']})
|
||||
option.series=series
|
||||
this.myChart.setOption(option);
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
90
resources/frontend/src/views/dataCenter/goodChart.vue
Normal file
90
resources/frontend/src/views/dataCenter/goodChart.vue
Normal file
@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div>
|
||||
<r-board :boardData="tops" class="boxcard" />
|
||||
<div :style="{height:`${this.contentHeight}px`}" style="background-color: #ffff;margin-top: 10px;padding-top: 20px;">
|
||||
<r-table class="page" :isIndex="false" :tableData="tableData" :tableCols="tableCols" :tablePage="pagination" @refresh="init()" >
|
||||
<div class="flex-col-center" style="width:100%;">
|
||||
<r-search ref="searchalt" :searchData="searchData" :searchForm="searchForm" :searchHandle="searchHandle" style="" />
|
||||
</div>
|
||||
</r-table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pagination: { size: 10, page: 1, total: 0 },
|
||||
searchData: {
|
||||
keyWord:"",
|
||||
status:'-1'
|
||||
},
|
||||
searchForm: [
|
||||
// { type: "radioButton",label: "时间", prop: "keyWord",radios:[{label:'今日',value:'day'},{label:'昨日',value:'yesterday'},{label:'本周',value:'week'},{label:'本月',value:'month'},{label:'本季',value:'quarter'},{label:'本年',value:'year'}]},
|
||||
{ type: "input",label: "关键词", prop: "keyWord",placeholder:'商品名、规格'},
|
||||
{ type: "select",label: "SKU状态", prop: "status",options:[{label:'全部',value:'-1'},{label:'在售',value:'1'},{label:'下架',value:'0'},{label:'预警',value:'2'}]},
|
||||
],
|
||||
searchHandle: [
|
||||
{type: "info",icon: "el-icon-refresh", handle: e => this.init(true) },
|
||||
{label: "搜索",type: "primary",icon: "el-icon-search",handle: e => this.seach()},
|
||||
],
|
||||
contentHeight:500,
|
||||
tableData: [],
|
||||
tableCols:[
|
||||
|
||||
{ label: "商品类型", prop: "type_name",width:150},
|
||||
{ label: "品牌", prop: "brand_name",width:150},
|
||||
{ label: "商品名称", prop: "good_name",width:150},
|
||||
{ label: "商品sku", prop: "title",width:200},
|
||||
{ label: "总量库存", prop: "num",width:200},
|
||||
{ label: "可售库存", prop: "stock",width:200},
|
||||
{ label: "采购成本", prop: "buyer_price",width:150},
|
||||
{ label: "参考售价", prop: "reference_price",width:150},
|
||||
{ label: "成本", prop: "cost",width:200},
|
||||
{ label: "SKU状态", prop: "status",width:200},
|
||||
{ label: "更新时间", prop: "updated_at",width:200},
|
||||
],
|
||||
tops:[{label:'商品总数',value:0},{label:'实际库存量',value:0},{label:'可售库存量',value:0},{label:'在售SKU',value:0},{label:'下架SKU',value:0},{label:'预警SKU',value:0}],
|
||||
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
|
||||
},
|
||||
mounted() {
|
||||
let element = document.querySelector('.box-card');
|
||||
let topEl = document.querySelector('.boxcard');
|
||||
console.log(element.offsetHeight,topEl.offsetHeight);
|
||||
this.contentHeight=element.offsetHeight-50-10-10
|
||||
this.init()
|
||||
},
|
||||
methods:{
|
||||
init(param={}){
|
||||
this.$http.post('/goodChart',Object.assign(this.pagination,param)).then(res=>{
|
||||
this.tableData=res.data.list
|
||||
let skan=res.data.skan
|
||||
this.tops.forEach((lst,index)=>{
|
||||
lst.value=skan[index]
|
||||
})
|
||||
})
|
||||
},
|
||||
seach(){
|
||||
this.init(this.searchData)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.divi{
|
||||
display: inline-block;
|
||||
width: 1px;
|
||||
margin: 0 8px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
background-color:#DCDFE6;
|
||||
}
|
||||
</style>
|
||||
201
resources/frontend/src/views/dataCenter/salesChart.vue
Normal file
201
resources/frontend/src/views/dataCenter/salesChart.vue
Normal file
@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="boxcard">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="padding-right: 5px;">时间维度</span>
|
||||
<el-radio-group @input="change" v-model="param.time">
|
||||
<el-radio-button v-for="time in list.times" :label="time.value">{{time.label}}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-date-picker
|
||||
@change="change"
|
||||
v-model="param.date"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="daterange"
|
||||
align="right"
|
||||
unlink-panels
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:picker-options="pickerOptions">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div id="salescanvas" style="height: 400px;width:100%;"></div>
|
||||
</el-card>
|
||||
<!-- 内容 -->
|
||||
<div :style="{height:`${this.contentHeight}px`}">
|
||||
<r-table class="page" :isIndex="false" :tableData="tableData" :tableCols="tableCols" @refresh="init()" >
|
||||
</r-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
param:{keyWord:'week',time:'week'},
|
||||
contentHeight:500,
|
||||
myChart:{},
|
||||
list:{times:[{label:'今日',value:'day'},{label:'昨日',value:'yesterday'},{label:'本周',value:'week'},{label:'本月',value:'month'},{label:'本季',value:'quarter'},{label:'本年',value:'year'}],},
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '最近一周',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近三个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
tableData: [],
|
||||
tableCols:[
|
||||
{ label: "商品类型", prop: "type_name",width:150},
|
||||
{ label: "品牌", prop: "brand_name",width:150},
|
||||
{ label: "商品名称", prop: "good_name",width:150},
|
||||
{ label: "商品sku", prop: "title",width:200},
|
||||
{ label: "销量", prop: "goods_number",width:200},
|
||||
{ label: "实际库存", prop: "num",width:200},
|
||||
{ label: "可售库存", prop: "stock",width:200},
|
||||
{ label: "缺货量", prop: "lastNum",width:150},
|
||||
{ label: "状态", prop: "status",width:150},
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let element = document.querySelector('.box-card');
|
||||
let topEl = document.querySelector('.boxcard');
|
||||
this.contentHeight=element.offsetHeight-topEl.offsetHeight-70
|
||||
this.$nextTick(()=>{
|
||||
setTimeout(() => {
|
||||
|
||||
this.init(this.param)
|
||||
}, 1500);
|
||||
})
|
||||
},
|
||||
methods:{
|
||||
change(e){
|
||||
this.param.keyWord=e
|
||||
this.init(this.param)
|
||||
},
|
||||
init(param={}){
|
||||
this.$http.post('/salesChart',Object.assign(param)).then(res=>{
|
||||
if (res.code==200) {
|
||||
this.getCanvas(res.data.field,res.data.data,res.data.sumDate)
|
||||
this.tableData=res.data.list
|
||||
} else {
|
||||
this.$msg.error('获取数据失败,请重新获取~')
|
||||
}
|
||||
})
|
||||
},
|
||||
getCanvas(field=[],data=[],sumCount=[]) {
|
||||
console.log('-------getCanvas data------2023-09-25--');
|
||||
var series=[]
|
||||
this.myChart=this.$chart.init(document.getElementById("salescanvas"));
|
||||
|
||||
const option = {
|
||||
color: [
|
||||
'#CCFFFF','#FFCCCC','#99CCCC','#FFCC99','#FF9999','#996699','#CC9999','#FFFFCC','#CCCC99','#FFFF99','#CCCCFF','#0099CC','#CCCCCC','#FF6666','#FF9966','#FFCCCC','#CC9966','#666666','#FF6666','#FFFF66','#99CC66','#CC3333','#CCCCCC','#003366','#663366','#CCCC99','#666666','#FF6666','#FFFF00','#0066CC','#333333','#336633','#990033','#66CC00','#CC99CC','#339933','#993399','#006633',
|
||||
'#CC9966','#003300','#FF0033','#333399','#CCCC00','#003399','#99CC00','#CC0033','#999933','#993333','#333300','#CCFF99','#99CCFF','#99CC99','#336699','#CC9933','#FFCC33','#336666','#99CC33','#FFCC00','#CC6699','#FFFF00','#3366CC','#FF6600','#009966','#990033','#CCFF66','#FF9900','#FF9966','#996600','#CC6600','#999999','#CCCC33','#000000','#999966','#663300','#FF9933','#6666CC'
|
||||
],
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'slider',
|
||||
realtime: true,
|
||||
start: 0,
|
||||
end: 5,
|
||||
height: 5,
|
||||
left: 5,
|
||||
right: 5,
|
||||
bottom: 10,
|
||||
show: true,
|
||||
fillerColor: "rgba(17, 100, 210, 0.42)",
|
||||
borderColor: "rgba(17, 100, 210, 0.12)",
|
||||
handleSize: 0,
|
||||
showDetail: false,
|
||||
zoomLock: true,
|
||||
moveOnMouseMove: false,
|
||||
|
||||
startValue: 0,
|
||||
endValue: 6,
|
||||
minValueSpan: 6,
|
||||
maxValueSpan: 6,
|
||||
},
|
||||
{
|
||||
type: "inside",
|
||||
start: 0,
|
||||
end: 5,
|
||||
zoomOnMouseWheel: false,
|
||||
moveOnMouseWheel: true,
|
||||
moveOnMouseMove: true
|
||||
}
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
width: 500,
|
||||
type: 'scroll',
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: field
|
||||
}
|
||||
],
|
||||
toolbox: {
|
||||
show: true,
|
||||
orient: 'vertical',
|
||||
left: 'right',
|
||||
top: 'center',
|
||||
feature: {
|
||||
mark: { show: true },
|
||||
dataView: { show: true, sreadOnly: false },
|
||||
magicType: { show: true, type: ['stack'] },
|
||||
restore: { show: true },
|
||||
saveAsImage: { show: true }
|
||||
}
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value'
|
||||
}
|
||||
],
|
||||
series: []
|
||||
};
|
||||
Object.keys(data).forEach(key => {
|
||||
series.push({name:key,type: 'bar',stack: 'Ad',emphasis: {focus: 'series'},data:data[key]})
|
||||
});
|
||||
series.push({name: '合计',type: 'bar',data: sumCount,emphasis: {focus: 'series'},markLine: {lineStyle: {type: 'dashed'},data: [[{ type: 'min' }, { type: 'max' }]]}})
|
||||
option.series=series
|
||||
this.myChart.setOption(option);
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
1175
resources/frontend/src/views/dataCenter/test.vue
Normal file
1175
resources/frontend/src/views/dataCenter/test.vue
Normal file
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="box-card">
|
||||
<div class="box-card" ref="boxCard">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</el-main>
|
||||
|
||||
76
resources/frontend/src/views/message/message.vue
Normal file
76
resources/frontend/src/views/message/message.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card>
|
||||
<!-- <el-button @click="init()">测试</el-button> -->
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane v-for="(data,index) in list" :key="index" :label="getState(index)" :name="index">
|
||||
<el-alert
|
||||
style="margin: 10px;height:50px;"
|
||||
v-for="(item,itemi) in data" :key="itemi"
|
||||
:title="item.content"
|
||||
type="info"
|
||||
close-text="知道了"
|
||||
@close="close(item)">
|
||||
</el-alert>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list:[],
|
||||
activeName: '1'
|
||||
};
|
||||
},
|
||||
mounted(){
|
||||
this.init()
|
||||
},
|
||||
computed:{
|
||||
getState(){
|
||||
return function(state){
|
||||
var str=''
|
||||
console.log(state);
|
||||
switch (parseInt(state)) {
|
||||
case 1:
|
||||
str='补货预警'
|
||||
break;
|
||||
case 2:
|
||||
str='价格预警'
|
||||
break;
|
||||
default:
|
||||
str='保质期预警'
|
||||
break;
|
||||
}
|
||||
return str
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(tab, event) {
|
||||
console.log(tab, event);
|
||||
},
|
||||
init(){
|
||||
this.$http.post('/getNoticeList').then(res=>{
|
||||
if (res.code == 200) {
|
||||
console.log(res.data);
|
||||
this.list=res.data
|
||||
}else{
|
||||
this.$msg.error('失败!')
|
||||
}
|
||||
})
|
||||
},
|
||||
close(e) {
|
||||
this.$http.post('/getSaveRead',e).then(res=>{
|
||||
if (res.code == 200) {
|
||||
this.$msg.success('变更成功!')
|
||||
}else{
|
||||
this.$msg.error('变更失败!')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
238
resources/frontend/src/views/stock/putWarehouse.vue
Normal file
238
resources/frontend/src/views/stock/putWarehouse.vue
Normal file
@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<div class="goods">
|
||||
<el-card class="boxcard" shadow="never">
|
||||
<r-search ref="searchalt" :searchData="searchData" :searchForm="searchForm" :searchHandle="searchHandle" />
|
||||
</el-card>
|
||||
|
||||
<div :style="{height:`${this.contentHeight}px`}" style="padding-top:30px;">
|
||||
<r-table class="page" :isIndex="false" isHandle :tableData="tableData" :tableCols="tableCols" :tableHandles="tableHandles" :isPagination="true" :tablePage="pagination" @refresh="init()">
|
||||
<el-upload slot="tip" ref="newset" action="/api/uploadPutWarehouse" :multiple="false" name="file"
|
||||
:show-file-list="false" :on-success="inventorySuccess" :before-upload="beforeInventory"
|
||||
:on-error="inventoryError" style="display:inline-block;margin: 0 10px 0 10px;" :headers="headers">
|
||||
<el-button type="primary" plain>入库导入</el-button>
|
||||
</el-upload>
|
||||
</r-table>
|
||||
|
||||
</div>
|
||||
<r-form
|
||||
:isHandle="true"
|
||||
:formRules="formRules"
|
||||
:formCols="formCols"
|
||||
:formHandle="formHandle"
|
||||
:formData="formData"
|
||||
labelWidth="100px"
|
||||
dialogWidth="550px"
|
||||
:inline="false"
|
||||
ref="elForm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
load:false,
|
||||
flag:false,
|
||||
title:'',
|
||||
param:{},
|
||||
supplierType:[],
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + localStorage.getItem("token")
|
||||
},
|
||||
pagination: { size: 10, page: 1, total: 0 },
|
||||
searchData: {
|
||||
keyWord:"",
|
||||
// status:'',
|
||||
},
|
||||
searchForm: [
|
||||
{ type: "input",label: "关键词", prop: "keyWord",placeholder:'商品、SKU、批次',width:400},
|
||||
],
|
||||
searchHandle: [
|
||||
{type: "info",icon: "el-icon-refresh", handle: e => this.init(true) },
|
||||
{label: "搜索",type: "primary",icon: "el-icon-search",handle: e => this.seach()},
|
||||
],
|
||||
|
||||
tableData: [],
|
||||
tableCols:[
|
||||
{ label: "供应商名称", prop: "supplier_name",width:200},
|
||||
{ label: "商品名称", prop: "good_name",width:150},
|
||||
{ label: "商品sku", prop: "sku_name",width:200},
|
||||
{ label: "采购批次", prop: "batch",width:150},
|
||||
{ label: "采购数量", prop: "stock",width:200},
|
||||
{ label: "采购单价", prop: "buyer_price",width:150},
|
||||
{ label: "销售价格", prop: "price",width:150},
|
||||
{ label: "保质期/天", prop: "shelf_life",width:150},
|
||||
{ label: "采购日期", prop: "buyer_at",width:150},
|
||||
{ label: "采购员", prop: "username",width:200},
|
||||
{ label: "备注", prop: "remark",width:250},
|
||||
{ label: "创建时间", prop: "created_at",width:200},
|
||||
{ label: "操作",type: "button",width: 300,
|
||||
btnList: [
|
||||
// {label: "修改",type: "primary",size: "mini",handle: (row) => this.elFormChange(row)},
|
||||
{label: "删除",type: "danger",size: "mini",handle: (row) => this.elFormDelete(row)},
|
||||
]
|
||||
},
|
||||
],
|
||||
|
||||
tableHandles: [
|
||||
{
|
||||
label: "新增入库",
|
||||
type: "primary",
|
||||
handle: e => {this.elFormVisible(e)} ,
|
||||
}
|
||||
],
|
||||
formData: {
|
||||
supplier_id: "",
|
||||
good_type:[],
|
||||
stock:'',
|
||||
buyer_price:'',
|
||||
price:'',
|
||||
shelf_life:"",
|
||||
buyer_at:"",
|
||||
buyer_by:"",
|
||||
remark:"",
|
||||
},
|
||||
formCols: [
|
||||
{ label: "供应商名称", prop: "supplier_id",width:350,type:'select',options:[]},
|
||||
{ label: "商品/规格", prop: "good_type",width:350,type:'cascader',options:[]},
|
||||
{ label: "入库数量", prop: "stock",width:350,type:'number'},
|
||||
{ label: "采购单价", prop: "buyer_price",width:350,type:'number'},
|
||||
{ label: "销售价格", prop: "price",width:350,type:'number'},
|
||||
{ label: "保质期/天", prop: "shelf_life",width:350,type:'number'},
|
||||
{ label: "入库日期", prop: "buyer_at",width:350,type:'dateTime'},
|
||||
{ label: "采购员", prop: "buyer_by",width:350,type:'select',options:[]},
|
||||
{ label: "备注", prop: "remark",width:350,type: "textarea"},
|
||||
],
|
||||
formRules: {
|
||||
supplier_id: [{ required: true, message: "请选择供应商名称", trigger: "blur" }],
|
||||
good_type: [{ required: true, message: "请选择商品/规格", trigger: "blur" }],
|
||||
buyer_by: [{ required: true, message: "请选择采购员", trigger: "blur" }],
|
||||
},
|
||||
formHandle: [
|
||||
{
|
||||
label: "确认",
|
||||
type: "primary",
|
||||
icon: "el-icon-circle-plus-outline",
|
||||
handle: e => this.elFormSubmit(),
|
||||
},
|
||||
{
|
||||
label: "取消",
|
||||
icon: "el-icon-circle-close",
|
||||
handle: e => this.elFormVisible(),
|
||||
},
|
||||
],
|
||||
width:500,
|
||||
height:500,
|
||||
contentHeight:500,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let element = document.querySelector('.box-card');
|
||||
this.width=element.offsetWidth
|
||||
this.height=element.offsetHeight
|
||||
let topEl = document.querySelector('.boxcard');
|
||||
this.contentHeight=element.offsetHeight-topEl.offsetHeight
|
||||
|
||||
this.$http.post('/getProSku').then(res=>{
|
||||
this.formCols[0].options=res.data.supplier;
|
||||
this.formCols[1].options=res.data.product;
|
||||
this.formCols[7].options=res.data.user;
|
||||
})
|
||||
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
beforeInventory() {
|
||||
this.loadingModule = this.$loading({
|
||||
lock: true,
|
||||
text: '导入中...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
},
|
||||
inventorySuccess(response) {
|
||||
this.$message({
|
||||
message: '导入成功!',
|
||||
type: "success",
|
||||
});
|
||||
this.loadingModule.close();
|
||||
},
|
||||
inventoryError(err) {
|
||||
this.$message({
|
||||
message: err.errorMessage,
|
||||
type: "error",
|
||||
});
|
||||
this.loadingModule.close();
|
||||
},
|
||||
init(param={}) {
|
||||
let data=Object.assign(this.pagination,param)
|
||||
this.$http.get('/listPutWarehouse',data).then(res=>{
|
||||
this.pagination.page=res.data.page
|
||||
this.pagination.size=res.data.size
|
||||
this.pagination.total=res.data.total
|
||||
this.tableData=res.data.list;
|
||||
console.log(this.tableData);
|
||||
})
|
||||
},
|
||||
seach(){
|
||||
this.init(this.searchData)
|
||||
},
|
||||
elFormUpload(e){
|
||||
console.log('导入',e);
|
||||
},
|
||||
elFormVisible(title){
|
||||
if (title==undefined) {
|
||||
this.title='新增'
|
||||
this.formData = { ...{} };
|
||||
}
|
||||
this.$refs.elForm.dialogFormTitle=this.title
|
||||
this.$refs.elForm.dialogFormVisible =!this.$refs.elForm.dialogFormVisible
|
||||
},
|
||||
elFormChange(e){
|
||||
this.title='修改'
|
||||
this.formData={...e}
|
||||
console.log(this.formData);
|
||||
this.elFormVisible("修改");
|
||||
|
||||
},
|
||||
elFormDelete(e){
|
||||
this.$confirm('您确定要删除吗?','提示').then(()=>{
|
||||
this.$http.post('/delPutWarehouse',{id:e.id}).then(res=>{
|
||||
if (res.code == 200) {
|
||||
this.$msg.success('删除成功!')
|
||||
this.tableData=this.tableData.filter((obj)=>{
|
||||
return obj.id!=e.id
|
||||
})
|
||||
}
|
||||
})
|
||||
}).catch(()=>{})
|
||||
},
|
||||
elFormSubmit(e) {
|
||||
this.$refs.elForm.$refs.ruleForm.validate((valid) => {
|
||||
if (valid) {
|
||||
// console.log(this.formData);return;
|
||||
this.$http.post('/savePutWarehouse', this.formData).then((res) => {
|
||||
console.log(res);
|
||||
if (res.code==200) {
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: `${this.title}成功!`,
|
||||
duration: 1300,
|
||||
onClose: (res) => {
|
||||
this.elFormVisible();
|
||||
this.init();
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
// this.treeUpload()
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
129
resources/frontend/src/views/stock/stockNotice.vue
Normal file
129
resources/frontend/src/views/stock/stockNotice.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div class="goods">
|
||||
<div >
|
||||
|
||||
<el-card class="boxcard" shadow="never" >
|
||||
<div slot="header" class="clearfix">
|
||||
<span>{{list[0].cn_name}}</span>
|
||||
</div>
|
||||
<r-formItem ref="itemData0" btnRight :itemData="list[0]" :btnList="btnList0" :formRule="formRule" :formItem="formItem0"></r-formItem>
|
||||
</el-card>
|
||||
<el-card class="boxcard" shadow="never" >
|
||||
<div slot="header" class="clearfix">
|
||||
<span>{{list[1].cn_name}}</span>
|
||||
</div>
|
||||
<r-formItem ref="itemData1" btnRight :itemData="list[1]" :btnList="btnList1" :formRule="formRule" :formItem="formItem1"></r-formItem>
|
||||
</el-card>
|
||||
<el-card class="boxcard" shadow="never" >
|
||||
<div slot="header" class="clearfix">
|
||||
<span>{{list[2].cn_name}}</span>
|
||||
</div>
|
||||
<r-formItem ref="itemData2" btnRight :itemData="list[2]" :btnList="btnList2" :formRule="formRule" :formItem="formItem2"></r-formItem>
|
||||
</el-card>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import index from '../../components/global/FormItem/index.vue';
|
||||
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
itemData0: {
|
||||
day_num: 3,
|
||||
active_time:'13:10',
|
||||
active_piece: 10,
|
||||
active_price: 0,
|
||||
user_id:1,
|
||||
},
|
||||
itemData1: {
|
||||
day_num: 3,
|
||||
active_time:'13:10',
|
||||
active_piece: 10,
|
||||
active_price: 0,
|
||||
user_id:1,
|
||||
},
|
||||
itemData2: {
|
||||
day_num: 3,
|
||||
active_time:'13:10',
|
||||
active_piece: 10,
|
||||
active_price: 0,
|
||||
user_id:1,
|
||||
},
|
||||
formItem0: [
|
||||
{labelWidth:'120',type: "time", label: "激活检查时间", prop: "active_time"},
|
||||
{labelWidth:'120',type: "select", label: "管理员推送", prop: "user_id",options:[]},
|
||||
],
|
||||
formItem1: [
|
||||
{labelWidth:'120',type: "time", label: "激活检查时间", prop: "active_time"},
|
||||
{labelWidth:'120',type: "select", label: "管理员推送", prop: "user_id",options:[]},
|
||||
],
|
||||
formItem2: [
|
||||
{labelWidth:'120',type: "time", label: "激活检查时间", prop: "active_time"},
|
||||
{labelWidth:'120',type: "select", label: "管理员推送", prop: "user_id",options:[]},
|
||||
],
|
||||
formRule: {
|
||||
minutes: [{ required: true, message: "请输入时间区间/分钟", trigger: "blur" }],
|
||||
active_time: [{ required: true, message: "请选择激活检查时间", trigger: "blur" }],
|
||||
user_id: [{ required: true, message: "请选择管理员推送", trigger: "blur" }],
|
||||
},
|
||||
btnList0: [{label: "确定",type: "primary",icon: "el-icon-setting",handle: e => this.elFormSubmit0()}],
|
||||
btnList1: [{label: "确定",type: "primary",icon: "el-icon-setting",handle: e => this.elFormSubmit1()}],
|
||||
btnList2: [{label: "确定",type: "primary",icon: "el-icon-setting",handle: e => this.elFormSubmit2()}],
|
||||
width:500,
|
||||
height:500,
|
||||
contentHeight:500,
|
||||
list:[],
|
||||
data:[],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$http.post('/stockNoticeList').then(res=>{
|
||||
this.list=res.data.list
|
||||
// this.data=res.data.user
|
||||
this.formItem0[1].options=res.data.user
|
||||
this.formItem1[1].options=res.data.user
|
||||
this.formItem2[1].options=res.data.user
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getSavestockNotice(index=0){
|
||||
this.$http.post('/saveStockNotice',this.list[index]).then(res=>{
|
||||
if (res.code == 200) {
|
||||
this.$msg.success('修改成功!')
|
||||
}else{
|
||||
this.$msg.error('修改失败!')
|
||||
}
|
||||
})
|
||||
},
|
||||
elFormSubmit0(e) {
|
||||
console.log(e);
|
||||
this.$refs.itemData0.$refs.ruleForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.getSavestockNotice(0)
|
||||
}
|
||||
});
|
||||
},
|
||||
elFormSubmit1(e) {
|
||||
this.$refs.itemData1.$refs.ruleForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.getSavestockNotice(1)
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
elFormSubmit2(e) {
|
||||
this.$refs.itemData2.$refs.ruleForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.getSavestockNotice(2)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
232
resources/frontend/src/views/stock/stockTacks.vue
Normal file
232
resources/frontend/src/views/stock/stockTacks.vue
Normal file
@ -0,0 +1,232 @@
|
||||
<template>
|
||||
<div class="goods">
|
||||
<el-card class="boxcard" shadow="never">
|
||||
<r-search ref="searchalt" :searchData="searchData" :searchForm="searchForm" :searchHandle="searchHandle" />
|
||||
</el-card>
|
||||
|
||||
<div :style="{height:`${this.contentHeight}px`}" style="padding-top:30px;">
|
||||
<r-table class="page" :isIndex="false" isHandle :tableData="tableData" :tableCols="tableCols" :tableHandles="tableHandles" :isPagination="true" :tablePage="pagination" @refresh="init()">
|
||||
<el-upload slot="tip" ref="newset" action="/api/uploadStockTacks" :multiple="false" name="file"
|
||||
:show-file-list="false" :on-success="inventorySuccess" :before-upload="beforeInventory"
|
||||
:on-error="inventoryError" style="display:inline-block;margin: 0 10px 0 10px;"
|
||||
:headers="headers">
|
||||
<el-button type="primary" plain>报损导入</el-button>
|
||||
</el-upload>
|
||||
</r-table>
|
||||
|
||||
</div>
|
||||
<r-form
|
||||
:isHandle="true"
|
||||
:formRules="formRules"
|
||||
:formCols="formCols"
|
||||
:formHandle="formHandle"
|
||||
:formData="formData"
|
||||
labelWidth="100px"
|
||||
dialogWidth="550px"
|
||||
:inline="false"
|
||||
ref="elForm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
load:false,
|
||||
flag:false,
|
||||
title:'',
|
||||
param:{},
|
||||
supplierType:[],
|
||||
pagination: { size: 10, page: 1, total: 0 },
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + localStorage.getItem("token")
|
||||
},
|
||||
searchData: {
|
||||
keyWord:"",
|
||||
},
|
||||
searchForm: [
|
||||
{ type: "input",label: "关键词", prop: "keyWord",placeholder:'商品名、规格、品牌',width:500},
|
||||
],
|
||||
searchHandle: [
|
||||
{type: "info",icon: "el-icon-refresh", handle: e => this.init(true) },
|
||||
{label: "搜索",type: "primary",icon: "el-icon-search",handle: e => this.seach()},
|
||||
],
|
||||
|
||||
tableData: [],
|
||||
formCols: [
|
||||
{ label: "商品/规格", prop: "good_type",width:350,type:'cascader',options:[]},
|
||||
{ label: "报损数量", prop: "stock",width:350,type:'number'},
|
||||
{ label: "采购成本", prop: "buyer_price",width:350,type:'number'},
|
||||
{ label: "入库成本", prop: "price",width:350,type:'number'},
|
||||
{ label: "报损日期", prop: "tack_date",width:350,type:'date'},
|
||||
{ label: "采购员", prop: "buyer_by",width:350,type:'select',options:[]},
|
||||
{ label: "备注", prop: "remark",width:350,type: "textarea"},
|
||||
],
|
||||
tableCols:[
|
||||
{ label: "报损日期", prop: "tack_date",width:150},
|
||||
{ label: "商品类型", prop: "type_name",width:150},
|
||||
{ label: "品牌", prop: "brand_name",width:150},
|
||||
{ label: "商品名称", prop: "good_name",width:150},
|
||||
{ label: "商品sku", prop: "sku_name",width:200},
|
||||
{ label: "采购数量", prop: "stock",width:200},
|
||||
{ label: "采购成本", prop: "buyer_price",width:150},
|
||||
{ label: "入库成本", prop: "price",width:150},
|
||||
{ label: "采购员", prop: "username",width:200},
|
||||
{ label: "备注", prop: "remark",width:250},
|
||||
{ label: "创建时间", prop: "created_at",width:200},
|
||||
{ label: "操作",type: "button",width: 300,
|
||||
btnList: [
|
||||
// {label: "修改",type: "primary",size: "mini",handle: (row) => this.elFormChange(row)},
|
||||
{label: "删除",type: "danger",size: "mini",handle: (row) => this.elFormDelete(row)},
|
||||
]
|
||||
},
|
||||
],
|
||||
|
||||
tableHandles: [
|
||||
{
|
||||
label: "新增报损",
|
||||
type: "primary",
|
||||
handle: e => {this.elFormVisible(e)} ,
|
||||
},
|
||||
],
|
||||
formData: {
|
||||
good_type:[],
|
||||
stock:'',
|
||||
buyer_price:'',
|
||||
price:'',
|
||||
tack_date:"",
|
||||
buyer_by:"",
|
||||
remark:"",
|
||||
},
|
||||
|
||||
formRules: {
|
||||
},
|
||||
formHandle: [
|
||||
{
|
||||
label: "确认",
|
||||
type: "primary",
|
||||
icon: "el-icon-circle-plus-outline",
|
||||
handle: e => this.elFormSubmit(),
|
||||
},
|
||||
{
|
||||
label: "取消",
|
||||
icon: "el-icon-circle-close",
|
||||
handle: e => this.elFormVisible(),
|
||||
},
|
||||
],
|
||||
width:500,
|
||||
height:500,
|
||||
contentHeight:500,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let element = document.querySelector('.box-card');
|
||||
this.width=element.offsetWidth
|
||||
this.height=element.offsetHeight
|
||||
let topEl = document.querySelector('.boxcard');
|
||||
this.contentHeight=element.offsetHeight-topEl.offsetHeight
|
||||
|
||||
this.$http.post('/getProSku').then(res=>{
|
||||
this.formCols[0].options=res.data.product;
|
||||
this.formCols[5].options=res.data.user;
|
||||
})
|
||||
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init(param={}) {
|
||||
// console.log(localStorage.getItem("token"));return;
|
||||
// console.log(this.$store.state.token);return;
|
||||
let data=Object.assign(this.pagination,param)
|
||||
this.$http.get('/listStockTacks',data).then(res=>{
|
||||
this.pagination.page=res.data.page
|
||||
this.pagination.size=res.data.size
|
||||
this.pagination.total=res.data.total
|
||||
this.tableData=res.data.list;
|
||||
console.log(this.tableData);
|
||||
})
|
||||
},
|
||||
beforeInventory() {
|
||||
this.loadingModule = this.$loading({
|
||||
lock: true,
|
||||
text: '导入中...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
},
|
||||
inventorySuccess(response) {
|
||||
this.$message({
|
||||
message: '导入成功!',
|
||||
type: "success",
|
||||
});
|
||||
this.loadingModule.close();
|
||||
},
|
||||
inventoryError(err) {
|
||||
this.$message({
|
||||
message: err.errorMessage,
|
||||
type: "error",
|
||||
});
|
||||
this.loadingModule.close();
|
||||
},
|
||||
seach(){
|
||||
this.init(this.searchData)
|
||||
},
|
||||
elFormUpload(e){
|
||||
console.log('导入',e);
|
||||
},
|
||||
elFormVisible(title){
|
||||
if (title==undefined) {
|
||||
this.title='新增'
|
||||
this.formData = { ...{} };
|
||||
}
|
||||
this.$refs.elForm.dialogFormTitle=this.title
|
||||
this.$refs.elForm.dialogFormVisible =!this.$refs.elForm.dialogFormVisible
|
||||
},
|
||||
elFormChange(e){
|
||||
this.title='修改'
|
||||
this.formData={...e}
|
||||
console.log(this.formData);
|
||||
this.elFormVisible("修改");
|
||||
|
||||
},
|
||||
elFormDelete(e){
|
||||
this.$confirm('您确定要删除吗?','提示').then(()=>{
|
||||
this.$http.post('/delStockTacks',{id:e.id}).then(res=>{
|
||||
if (res.code == 200) {
|
||||
this.$msg.success('删除成功!')
|
||||
this.tableData=this.tableData.filter((obj)=>{
|
||||
return obj.id!=e.id
|
||||
})
|
||||
}
|
||||
})
|
||||
}).catch(()=>{})
|
||||
},
|
||||
elFormSubmit(e) {
|
||||
this.$refs.elForm.$refs.ruleForm.validate((valid) => {
|
||||
if (valid) {
|
||||
// console.log(this.formData);return;
|
||||
this.$http.post('/saveStockTacks', this.formData).then((res) => {
|
||||
console.log(res);
|
||||
if (res.code==200) {
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: `${this.title}报损成功!`,
|
||||
duration: 1300,
|
||||
onClose: (res) => {
|
||||
this.elFormVisible();
|
||||
this.init();
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
// this.treeUpload()
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
123
resources/frontend/src/views/supplier/good.vue
Normal file
123
resources/frontend/src/views/supplier/good.vue
Normal file
@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div>
|
||||
<r-search ref="searchalt" :searchData="searchData" :searchForm="searchForm" :searchHandle="searchHandle" />
|
||||
<r-table :isIndex="true" :tableData="tableData" :tableCols="tableCols" v-loading="load" :isPagination="true" :tablePage="pagination" @refresh="init()" />
|
||||
<r-form dialogWidth="500px" labelWidth="120px" :isHandle="true" :formCols="formCols" :formHandle="formHandle" :formRules="formRules" :formData="formData" ref="elForm" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
list:[],
|
||||
load:false,
|
||||
pagination: { size: 10, page: 1, total: 0 },
|
||||
searchData: {
|
||||
keyWord:"",
|
||||
batteryStatus:'-1',
|
||||
batteryLockStatus:'-1',
|
||||
batteryModelId:'',
|
||||
},
|
||||
searchForm: [
|
||||
{ type: "input",label: "关键词", prop: "keyWord",placeholder:'客户名称、电池编号、使用人'},
|
||||
{ type: "select",label: "电池状态", prop: "batteryStatus",options:[{label:'正常',value:'0'},{label:'故障',value:'1'},{label:'全部',value:'-1'}]},
|
||||
{ type: "select",label: "电池锁定状态", prop: "batteryLockStatus",options:[{label:'正常',value:'0'},{label:'锁定',value:'1'},{label:'全部',value:'-1'}]},
|
||||
],
|
||||
searchHandle: [
|
||||
{type: "info",icon: "el-icon-refresh", handle: e => this.init(true) },
|
||||
{label: "搜索",type: "primary",icon: "el-icon-search",handle: e => this.seach()},
|
||||
],
|
||||
tableData: [],
|
||||
tableCols: [
|
||||
{ label: "电池编号", prop: "batteryNo",width:200},
|
||||
{ label: "电池型号", prop: "batteryModelName",width:150},
|
||||
{ label: "是否备件库", prop: "isSpares",formatter:e=>e.isSpares?'是':'否',width:120},
|
||||
{ label: "所属订单", prop: "byOrderCode",width:150},
|
||||
{ label: "所属出库单号", prop: "byStockCode",width:150},
|
||||
{ label: "客户类型", prop: "customerType",width:150,formatter:e=>e.customerType==0?'经销商':'代理商',},
|
||||
{ label: "所属客户", prop: "customerName",width: 200},
|
||||
{ label: "所属代理", prop: "parentCustomerName",width:200},
|
||||
{ label: "使用人", prop: "usePersionName",width:120},
|
||||
{ label: "电池状态", prop: "batteryStatus",formatter:e=>e.batteryStatus==0?'正常':'故障'},
|
||||
{ label: "电池锁定状态", prop: "batteryLockStatus",formatter:e=>e.batteryLockStatus==0?'正常':'已锁定',width:120,isDisabled:e=>e.batteryLockStatus?true:false},
|
||||
{ label: "操作",type: "button",width: 300,
|
||||
btnList: [
|
||||
{label: "手动解锁",type: "primary",size: "mini",isShow:e=>e.batteryLockStatus==1?true:false,handle: (row) => this.getLock(row)},
|
||||
{label: "查看备件更换记录",type: "danger",size: "mini",handle: (row) => this.getChange(row)},
|
||||
]
|
||||
},
|
||||
],
|
||||
formCols: [
|
||||
],
|
||||
formRules:{
|
||||
},
|
||||
formData: {
|
||||
},
|
||||
formHandle: [
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
},
|
||||
created() {
|
||||
this.$http.post('/battery/model/list').then(res=>{
|
||||
let lst=res.data;
|
||||
let arr=[]
|
||||
lst.forEach((obj)=>{
|
||||
let list={label:obj.batteryModel,value:obj.id}
|
||||
arr.push(list)
|
||||
});
|
||||
this.searchForm.push({type:'select', label: "电池型号", prop: "batteryModelId",options:arr})
|
||||
})
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init(isref=false,param={}) {
|
||||
// this.load=true;
|
||||
let data=Object.assign(this.pagination,param)
|
||||
this.$http.get('/battery/getBatteryListByCustomer',data).then(res=>{
|
||||
console.log(res.data);
|
||||
// this.pagination.pageSize=res.data.pageSize
|
||||
// this.pagination.page=res.data.currPage
|
||||
// this.pagination.total=res.data.totalCount
|
||||
// this.tableData=res.data.list;
|
||||
})
|
||||
},
|
||||
seach(){
|
||||
this.init(false,this.searchData)
|
||||
},
|
||||
|
||||
getLock(e){
|
||||
console.log(e);
|
||||
this.$confirm('您确定要解锁吗?','提示').then(()=>{
|
||||
this.$http.post('/battery/settinglock',{id:String(e.id)}).then(res=>{
|
||||
if (res.data==1) {
|
||||
this.$msg.success('解锁成功!')
|
||||
this.init()
|
||||
}else{
|
||||
this.$msg.error(res.msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
getChange(e){
|
||||
this.$router.push({
|
||||
name: 'battery-replace',
|
||||
query:{
|
||||
row:JSON.stringify({batteryNo:String(e.batteryNo)}),
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
@ -1,7 +1,247 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row type="flex" justify="end">
|
||||
<el-col :offset="24"><el-button type="success">新增</el-button></el-col>
|
||||
</el-row>
|
||||
<div class="goods">
|
||||
<el-card class="boxcard" shadow="never">
|
||||
<r-search ref="searchalt" :searchData="searchData" :searchForm="searchForm" :searchHandle="searchHandle" />
|
||||
</el-card>
|
||||
|
||||
<div :style="{height:`${this.contentHeight}px`}" style="padding-top:30px;">
|
||||
<r-table class="page" :isIndex="false" isHandle :tableData="tableData" :tableCols="tableCols" :tableHandles="tableHandles" :isPagination="true" :tablePage="pagination" @refresh="init()" />
|
||||
|
||||
</div>
|
||||
<r-form
|
||||
:isHandle="true"
|
||||
:formRules="formRules"
|
||||
:formCols="formCols"
|
||||
:formHandle="formHandle"
|
||||
:formData="formData"
|
||||
labelWidth="100px"
|
||||
dialogWidth="550px"
|
||||
:inline="false"
|
||||
ref="elForm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
load:false,
|
||||
flag:false,
|
||||
title:'',
|
||||
param:{},
|
||||
supplierType:[],
|
||||
pagination: { size: 10, page: 1, total: 0 },
|
||||
searchData: {
|
||||
keyWord:"",
|
||||
status:'-1'
|
||||
},
|
||||
searchForm: [
|
||||
{ type: "input",label: "关键词", prop: "keyWord",placeholder:'供应商名称'},
|
||||
{ type: "select",label: "状态", prop: "status",options:[{label:'禁用',value:'0'},{label:'正常',value:'1'},{label:'全部',value:'-1'}]}
|
||||
],
|
||||
searchHandle: [
|
||||
{type: "info",icon: "el-icon-refresh", handle: e => this.init(true) },
|
||||
{label: "搜索",type: "primary",icon: "el-icon-search",handle: e => this.seach()},
|
||||
],
|
||||
|
||||
tableData: [],
|
||||
tableCols:[
|
||||
{ label: "供应商名称", prop: "supplier_name",width:200},
|
||||
{ label: "所在类别", prop: "supplier_type",width:150},
|
||||
{ label: "拥有品类", prop: "type_name",width:200},
|
||||
{ label: "对公银行", prop: "bank",width:150},
|
||||
{ label: "对公账号", prop: "bank_num",width:200},
|
||||
{ label: "联系人", prop: "username",width:150},
|
||||
{ label: "手机号码", prop: "phone",width:150},
|
||||
{ label: "公司座机", prop: "tel",width:150},
|
||||
{ label: "微信号码", prop: "wx",width:150},
|
||||
{ label: "公司地址", prop: "address",width:200},
|
||||
{ label: "地址邮编", prop: "code",width:150},
|
||||
{ label: "状态", prop: "status",formatter:e=>e.status==1?'正常':'禁用'},
|
||||
{ label: "备注", prop: "remark",width:250},
|
||||
{ label: "创建时间", prop: "created_at",width:200},
|
||||
{ label: "操作",type: "button",width: 300,
|
||||
btnList: [
|
||||
{label: "修改",type: "primary",size: "mini",handle: (row) => this.elFormChange(row)},
|
||||
{label: "删除",type: "danger",size: "mini",handle: (row) => this.elFormDelete(row)},
|
||||
]
|
||||
},
|
||||
],
|
||||
|
||||
tableHandles: [
|
||||
{
|
||||
label: "新增供应商",
|
||||
type: "primary",
|
||||
handle: e => {this.elFormVisible(e)} ,
|
||||
},
|
||||
],
|
||||
// pagination: { limit: 10, offset: 1, total: 1 },
|
||||
formData: {
|
||||
supplier_name: "",
|
||||
type_id:'',
|
||||
good_type_id:'',
|
||||
bank:"",
|
||||
bank_num:"",
|
||||
username:"",
|
||||
phone:"",
|
||||
tel:"",
|
||||
wx:"",
|
||||
address:"",
|
||||
code:"",
|
||||
status:1,
|
||||
remark:''
|
||||
},
|
||||
formCols: [
|
||||
{type: "input", label: "供应商名称", prop: "supplier_name",width:350},
|
||||
{type: "select", label: "所在类别", prop: "type_id",width:350,options:[]},
|
||||
{type: "select", label: "品类", prop: "good_type_id",width:350,options:[]},
|
||||
{type: "input", label: "对公银行", prop: "bank",width:350},
|
||||
{type: "input", label: "对公账号", prop: "bank_num",width:350},
|
||||
{type: "input", label: "联系人", prop: "username",width:350},
|
||||
{type: "input", label: "手机号码", prop: "phone",width:350},
|
||||
{type: "input", label: "公司座机", prop: "tel",width:350},
|
||||
{type: "input", label: "微信号码", prop: "wx",width:350},
|
||||
{type: "input", label: "公司地址", prop: "address",width:350},
|
||||
{type: "input", label: "公司邮编", prop: "code",width:350},
|
||||
{type: "select", label: "状态", prop: "status",width:350,options:[{label:'正常',value:1},{label:'禁用',value:0}]},
|
||||
{type: "textarea", label: "备注", prop: "remark",width:350},
|
||||
],
|
||||
formRules: {
|
||||
supplier_name: [{ required: true, message: "请输入供应商名称", trigger: "blur" }],
|
||||
type_id: [{ required: true, message: "请选择所在类别", trigger: "blur" }],
|
||||
good_type_id: [{ required: true, message: "请选择品类", trigger: "blur" }],
|
||||
},
|
||||
formHandle: [
|
||||
{
|
||||
label: "确认",
|
||||
type: "primary",
|
||||
icon: "el-icon-circle-plus-outline",
|
||||
handle: e => this.elFormSubmit(),
|
||||
},
|
||||
{
|
||||
label: "取消",
|
||||
icon: "el-icon-circle-close",
|
||||
handle: e => this.elFormVisible(),
|
||||
},
|
||||
],
|
||||
width:500,
|
||||
height:500,
|
||||
contentHeight:500,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let element = document.querySelector('.box-card');
|
||||
this.width=element.offsetWidth
|
||||
this.height=element.offsetHeight
|
||||
let topEl = document.querySelector('.boxcard');
|
||||
|
||||
this.contentHeight=element.offsetHeight-topEl.offsetHeight
|
||||
|
||||
// },
|
||||
// console.log(el);
|
||||
// window.addEventListener('resize', this.handleResize);
|
||||
// const element = this.$refs['box-card'];
|
||||
// console.log(element);
|
||||
// element.addEventListener('resize', () => {
|
||||
// this.handleResize();
|
||||
// });
|
||||
this.$http.post('/getSupplierType').then(res=>{
|
||||
this.supplierType=res.data
|
||||
let index=this.formCols.findIndex((res,index)=>{
|
||||
return res.prop=='type_id'
|
||||
})
|
||||
this.formCols[index].options=res.data.type
|
||||
let index2=this.formCols.findIndex((res,index)=>{
|
||||
return res.prop=='good_type_id'
|
||||
})
|
||||
this.formCols[index2].options=res.data.good
|
||||
})
|
||||
this.init()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleResize() {
|
||||
// 这里可以访问 this.$el 来获取元素的类
|
||||
const elementClass = this.$el.boxcard;
|
||||
console.log('页面大小变化,当前类名:', elementClass);
|
||||
// 根据需要执行其他逻辑
|
||||
},
|
||||
init(param={}) {
|
||||
// this.load=true;listSupplier
|
||||
let data=Object.assign(this.pagination,param)
|
||||
this.$http.get('/listSupplier',data).then(res=>{
|
||||
this.pagination.page=res.data.page
|
||||
this.pagination.size=res.data.size
|
||||
this.pagination.total=res.data.total
|
||||
this.tableData=res.data.list;
|
||||
console.log(this.tableData);
|
||||
})
|
||||
},
|
||||
seach(){
|
||||
this.init(this.searchData)
|
||||
},
|
||||
elFormVisible(title){
|
||||
if (title==undefined) {
|
||||
this.title='新增'
|
||||
this.formData = { ...{status:1} };
|
||||
}
|
||||
this.$refs.elForm.dialogFormTitle=this.title
|
||||
this.$refs.elForm.dialogFormVisible =!this.$refs.elForm.dialogFormVisible
|
||||
},
|
||||
elFormChange(e){
|
||||
this.title='修改'
|
||||
this.formData={...e}
|
||||
this.elFormVisible("修改");
|
||||
|
||||
},
|
||||
elFormDelete(e){
|
||||
this.$confirm('您确定要删除吗?','提示').then(()=>{
|
||||
this.$http.post('/delSupplier',{id:e.id}).then(res=>{
|
||||
if (res.code == 200) {
|
||||
this.$msg.success('删除成功!')
|
||||
this.tableData=this.tableData.filter((obj)=>{
|
||||
return obj.id!=e.id
|
||||
})
|
||||
}
|
||||
})
|
||||
}).catch(()=>{})
|
||||
// this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
|
||||
// confirmButtonText: '确定',
|
||||
// cancelButtonText: '取消',
|
||||
// type: 'warning'
|
||||
// }).then(() => {
|
||||
// this.$message.success('删除成功!');
|
||||
// // 执行删除操作的代码
|
||||
// }).catch(() => {
|
||||
// this.$message.info('已取消删除');
|
||||
// });
|
||||
},
|
||||
elFormSubmit(e) {
|
||||
this.$refs.elForm.$refs.ruleForm.validate((valid) => {
|
||||
if (valid) {
|
||||
console.log(this.formData);
|
||||
this.$http.post('/saveSupplier', this.formData).then((res) => {
|
||||
console.log(res);
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: `${this.title}成功!`,
|
||||
duration: 1300,
|
||||
onClose: (res) => {
|
||||
this.elFormVisible();
|
||||
this.init();
|
||||
},
|
||||
});
|
||||
});
|
||||
// this.treeUpload()
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
4
resources/frontend/vue.config.js
vendored
4
resources/frontend/vue.config.js
vendored
@ -7,8 +7,8 @@ module.exports = {
|
||||
proxy: {
|
||||
// 配置代理
|
||||
"/api": {
|
||||
// target: "http://erp.local",
|
||||
target: "http://erp.chutang66.com",
|
||||
target: "https://erp.lookthere.cn",
|
||||
// target: "http://erp.chutang66.com",
|
||||
changeOrigin: true, // 开启代理
|
||||
pathRewrite: {
|
||||
// 重命名
|
||||
|
||||
@ -477,4 +477,67 @@ return [
|
||||
'name' => '销售数据列表',
|
||||
'parent_id' => 180,
|
||||
],
|
||||
// 供应商管理
|
||||
'supplier' => [
|
||||
'id' => 181,
|
||||
'name' => '供应商管理',
|
||||
'parent_id' => 0,
|
||||
'show' => 1,
|
||||
],
|
||||
// 供应商管理--
|
||||
'supplierList' => [
|
||||
'id' => 182,
|
||||
'name' => '供应商列表',
|
||||
'parent_id' => 181,
|
||||
'show' => 1,
|
||||
],
|
||||
// 库存管理
|
||||
'stock' => [
|
||||
'id' => 183,
|
||||
'name' => '库存管理',
|
||||
'parent_id' => 0,
|
||||
'show' => 1,
|
||||
],
|
||||
'putWarehouse' => [
|
||||
'id' => 184,
|
||||
'name' => '商品入库',
|
||||
'parent_id' => 183,
|
||||
'show' => 1,
|
||||
],
|
||||
'stockNotice' => [
|
||||
'id' => 185,
|
||||
'name' => '库存预警',
|
||||
'parent_id' => 183,
|
||||
'show' => 1,
|
||||
],
|
||||
'stockTacks' => [
|
||||
'id' => 186,
|
||||
'name' => '盘点报损',
|
||||
'parent_id' => 183,
|
||||
'show' => 1,
|
||||
],
|
||||
'message' => [
|
||||
'id' => 187,
|
||||
'name' => '消息列表',
|
||||
'parent_id' => 0,
|
||||
'show' => 1,
|
||||
],
|
||||
'dataChart' => [
|
||||
'id' => 188,
|
||||
'name' => '数据报表',
|
||||
'parent_id' => 0,
|
||||
'show' => 1,
|
||||
],
|
||||
'salesData' => [
|
||||
'id' => 189,
|
||||
'name' => '销售数据',
|
||||
'parent_id' => 188,
|
||||
'show' => 1,
|
||||
],
|
||||
'afterSales' => [
|
||||
'id' => 190,
|
||||
'name' => '售后数据',
|
||||
'parent_id' => 188,
|
||||
'show' => 1,
|
||||
],
|
||||
];
|
||||
|
||||
@ -12,7 +12,10 @@ use App\Http\Controllers\Group\GroupsController;
|
||||
use App\Http\Controllers\Business\BusinessOrderController;
|
||||
use App\Http\Controllers\Goods\GoodsSkuLocationController;
|
||||
use App\Http\Controllers\Goods\GoodsCombinationController;
|
||||
|
||||
use App\Http\Controllers\Supplier\SupplierController;
|
||||
use App\Http\Controllers\Warehouse\WarehouseController;
|
||||
use App\Http\Controllers\Warehouse\StockNoticeControllers;
|
||||
use App\Http\Controllers\DataCenter\DataChartControllers;
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Routes
|
||||
@ -23,7 +26,11 @@ use App\Http\Controllers\Goods\GoodsCombinationController;
|
||||
| is assigned the "api" middleware group. Enjoy building your API!
|
||||
|
|
||||
*/
|
||||
Route::get('test', [ShopsController::class, 'test']);
|
||||
|
||||
Route::middleware(['auth:api', 'check.permissions'])->group(function () {
|
||||
|
||||
// $api->post('index', 'IndexController@IndexHomeQueue');
|
||||
// 用户
|
||||
Route::resource('users', 'User\UsersController', ['only' => ['index', 'store', 'show', 'update', 'destroy']]);
|
||||
// 商品种类
|
||||
@ -73,6 +80,7 @@ Route::middleware(['auth:api', 'check.permissions'])->group(function () {
|
||||
// 数据中心
|
||||
Route::get('data_center/sales_report', [DataCenterController::class, 'salesReport'])->name('sales_report.index');
|
||||
});
|
||||
|
||||
Route::get('stock/goods_skus', [GoodsSkusController::class, 'stockNum'])->middleware('auth:api');
|
||||
Route::get('goods/filter/{title}', [GoodsCombinationController::class, 'goodsSkus'])->middleware('auth:api');
|
||||
// 登录
|
||||
@ -99,6 +107,11 @@ Route::post('business', [ShopsController::class, 'business'])->name('shop.put.bu
|
||||
Route::post('inventory/goods_skus', [GoodsSkusController::class, 'inventoryImport'])->name('goods_sku.inventory');
|
||||
// 上新导入
|
||||
Route::post('new/set/goods_skus', [GoodsSkusController::class, 'newSetImport'])->name('goods_sku.new_set');
|
||||
// 报损导入
|
||||
Route::post('uploadStockTacks', [WarehouseController::class, 'uploadStockTacks'])->middleware('auth:api');
|
||||
// 入库导入
|
||||
Route::post('uploadPutWarehouse', [WarehouseController::class, 'uploadPutWarehouse'])->middleware('auth:api');
|
||||
|
||||
// 商品货架导入
|
||||
Route::post('goods_sku_location', [GoodsSkuLocationController::class, 'import'])->name('goods_sku_location.import');
|
||||
// 组合商品导入
|
||||
@ -107,5 +120,42 @@ Route::post('combination/goods', [GoodsCombinationController::class, 'import'])-
|
||||
Route::post('today/price', [BusinessGoodsSkusController::class, 'todayPriceImport'])->name('plat.today_price.import');
|
||||
// 文件上传
|
||||
Route::post('upload', [UploadController::class, 'store'])->name('upload.file');
|
||||
|
||||
// 商品列表
|
||||
Route::get('goodsSkusList', [GoodsSkusController::class, 'goodsSkusList'])->name('goods_sku.list_for_goods_sku');
|
||||
|
||||
/*
|
||||
* 供应商管理
|
||||
*
|
||||
* */
|
||||
Route::get('listSupplier', [SupplierController::class, 'index'])->middleware('auth:api');
|
||||
Route::post('saveSupplier', [SupplierController::class, 'save'])->middleware('auth:api');
|
||||
Route::post('delSupplier', [SupplierController::class, 'delete'])->middleware('auth:api');
|
||||
Route::post('getSupplierType', [SupplierController::class, 'getSupplierType'])->middleware('auth:api');
|
||||
/*
|
||||
* 库存管理
|
||||
*
|
||||
* */
|
||||
Route::post('getProSku', [WarehouseController::class, 'getProSku'])->middleware('auth:api');
|
||||
Route::post('savePutWarehouse', [WarehouseController::class, 'savePutWarehouse'])->middleware('auth:api');
|
||||
Route::get('listPutWarehouse', [WarehouseController::class, 'listPutWarehouse'])->middleware('auth:api');
|
||||
Route::post('delPutWarehouse', [WarehouseController::class, 'delPutWarehouse'])->middleware('auth:api');
|
||||
Route::post('stockNoticeList', [StockNoticeControllers::class, 'stockNoticeList'])->middleware('auth:api');
|
||||
Route::post('saveStockNotice', [StockNoticeControllers::class, 'saveStockNotice'])->middleware('auth:api');
|
||||
|
||||
Route::post('getNoticeList', [StockNoticeControllers::class, 'getNoticeList'])->middleware('auth:api');
|
||||
Route::post('getSaveRead', [StockNoticeControllers::class, 'getSaveRead'])->middleware('auth:api');
|
||||
//报损
|
||||
Route::post('saveStockTacks', [WarehouseController::class, 'saveStockTacks'])->middleware('auth:api');
|
||||
Route::post('delStockTacks', [WarehouseController::class, 'delStockTacks'])->middleware('auth:api');
|
||||
Route::get('listStockTacks', [WarehouseController::class, 'listStockTacks'])->middleware('auth:api');
|
||||
|
||||
Route::post('goodChart', [DataChartControllers::class, 'goodChart'])->middleware('auth:api');
|
||||
Route::post('damageChart', [DataChartControllers::class, 'damageChart'])->middleware('auth:api');
|
||||
//销售图表
|
||||
Route::post('salesChart', [DataChartControllers::class, 'salesChart'])->middleware('auth:api');
|
||||
//交易趋势
|
||||
Route::post('flagChart', [DataChartControllers::class, 'flagChart'])->middleware('auth:api');
|
||||
//成本数据
|
||||
Route::post('costChart', [DataChartControllers::class, 'costChart'])->middleware('auth:api');
|
||||
Route::post('getOrderServerData', [DataChartControllers::class, 'getOrderServerData'])->middleware('auth:api');
|
||||
|
||||
@ -18,7 +18,8 @@ use App\Http\Controllers\Business\BusinessGoodsSkusController;
|
||||
*/
|
||||
|
||||
Route::get('/', function () {
|
||||
header('Location: ' . url()->current() . "/dist");
|
||||
// header('Location: ' . url()->current() . "/dist");
|
||||
return "hello";
|
||||
});
|
||||
|
||||
Route::get('goods_skus/export', [GoodsSkusController::class, 'export'])->name('goods_skus.export');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user