!147 配货功能

Merge pull request !147 from 赵世界/develop
This commit is contained in:
赵世界 2023-04-04 07:47:40 +00:00 committed by Gitee
commit b87a9d0def
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
67 changed files with 1163 additions and 46 deletions

View File

@ -0,0 +1,86 @@
<?php
namespace App\Exports;
use App\Models\Goods;
use App\Utils\ArrayUtils;
use Maatwebsite\Excel\Concerns\FromCollection;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class OrderBlankExport implements FromCollection, WithStyles
{
private $data;
private $shopName;
private $no;
private $count;
public function __construct($shopName, $no, $excelDate)
{
$this->shopName = $shopName;
$this->no = $no;
$this->count = count($excelDate);
$this->data = $this->createData($excelDate);
}
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return new Collection($this->data);
}
private function createData($excelDate)
{
$noStr = implode(',', $this->no);
$data = [
['店铺名称', $this->shopName],
['跟团号', $noStr],
['种类', '品牌', '商品规格', '商品名称', '数量', '所在货架编号', '配货'],
];
$goodsCodes = array_column($excelDate, 'goods_code');
$goods = Goods::query()
->with([
'brand:id,name',
'type:id,name',
])
->whereIn('goods_code', $goodsCodes)
->get(['goods_code', 'type_id', 'brand_id'])
->toArray();
$goods = ArrayUtils::index($goods, 'goods_code');
foreach ($excelDate as $key => $item) {
$goodsInfo = $goods[$item['goods_code']];
$arr[0] = $goodsInfo['type']['name'];
$arr[1] = $goodsInfo['brand']['name'];
$arr[2] = $key;
$arr[3] = $item['goods_name'];
$arr[4] = $item['num'];
$arr[5] = $item['local'];
$arr[6] = implode(' ', $item['p']);
$data[] = $arr;
}
return $data;
}
public function styles(Worksheet $sheet)
{
$count = $this->count + 2;
$sheet->mergeCells('B2:G2');
$sheet->getStyle('B2')->getAlignment()
->setVertical('center')
->setWrapText(true);
$sheet->getStyle('G3:G' . $count)->getAlignment()
->setVertical('center')
->setWrapText(true);
$sheet->getColumnDimension('A')->setWidth(10);
$sheet->getColumnDimension('B')->setWidth(10);
$sheet->getColumnDimension('C')->setWidth(10);
$sheet->getColumnDimension('D')->setWidth(60);
$sheet->getColumnDimension('E')->setWidth(5);
$sheet->getColumnDimension('F')->setWidth(11);
$sheet->getColumnDimension('G')->setWidth(14);
}
}

View File

@ -14,7 +14,7 @@ class BusinessGoodsSkuFilter extends Filters
return $this->builder->where('goods_name', '=', trim($value));
}
protected function shipId($value)
protected function shopId($value)
{
return $this->builder->where('shop_id', '=', trim($value));
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Filters;
class BusinessOrderFilter extends Filters
{
protected function participateNo($value)
{
return $this->builder->where('participate_no', '=', trim($value));
}
protected function shopId($value)
{
return $this->builder->where('shop_id', '=', $value);
}
protected function activityNo($value)
{
return $this->builder->where('activity_no', '=', $value);
}
protected function shippingStatus($value)
{
return $this->builder->where('shipping_status', '=', $value);
}
protected function isSupplier($value)
{
return $this->builder->where('is_supplier', '=', $value);
}
protected function cancelStatus($value)
{
return $this->builder->where('cancel_status', '=', $value);
}
protected function afterSalesStatus($value)
{
return $this->builder->where('after_sales_status', '=', $value);
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\Filters;
use App\Models\Goods;
use App\Models\GoodsSku;
class GoodsSkuLocationFilter extends Filters
{
public function date($value)
{
return $this->builder->where('date', '=', $value);
}
public function goodsTitle($value)
{
$goodsId = Goods::query()->where('title', $value)->value('id');
return $this->builder->where('goods_id', '=', $goodsId);
}
public function goodsCode($value)
{
$goodsId = Goods::query()->where('goods_code', $value)->value('id');
return $this->builder->where('goods_id', '=', $goodsId);
}
public function externalSkuId($value)
{
[$goodsCode, $skuCode] = explode('_', $value);
$goodsId = Goods::query()->where('goods_code', $goodsCode)->value('id');
$skuId = GoodsSku::query()->where('sku_code', $skuCode)->value('id');
return $this->builder->where('goods_sku_id', '=', $skuId)->where('goods_id', '=', $goodsId);
}
public function location($value)
{
return $this->builder->where('location', '=', $value);
}
public function status($value)
{
return $this->builder->where('status', '=', $value);
}
}

View File

@ -0,0 +1,97 @@
<?php
namespace App\Http\Controllers\Business;
use App\Exports\OrderBlankExport;
use App\Http\Controllers\Controller;
use App\Models\BusinessOrder;
use App\Models\Shop;
use App\Utils\DateTimeUtils;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Http\Resources\BusinessOrderResource;
use Maatwebsite\Excel\Facades\Excel;
class BusinessOrderController extends Controller
{
public function index(Request $request)
{
$businessOrders = BusinessOrder::query()
->where('shop_id', '<>', 8)
->with([
'shop:id,name',
'items:id,business_order_id,goods_name,goods_number,external_sku_id'
])
->orderByDesc('confirm_at')
->filter()
->paginate($request->get('per_page'));
return BusinessOrderResource::collection($businessOrders);
}
public function exportOrderBlank(Request $request)
{
$shopId = $request->get('shop_id');
$startNo = $request->get('start_no');
$endNo = $request->get('end_no');
$startTime = BusinessOrder::query()->where('shop_id', $shopId)->where('participate_no', $startNo)->value('confirm_at');
$endTime = BusinessOrder::query()->where('shop_id', $shopId)->where('participate_no', $endNo)->value('confirm_at');
$orders = BusinessOrder::query()
->with([
'items:id,business_order_id,external_sku_id,goods_number,goods_name',
'items.goodsSkuLocation:id,external_sku_id,location,goods_name'
])
->where('shop_id', $shopId)
->where('confirm_at', '>=', DateTimeUtils::getMicroTime($startTime))
->where('confirm_at', '<=', DateTimeUtils::getMicroTime($endTime))
->where('after_sales_status', 0)
->where('cancel_status', 0)
->where('is_supplier', 1)
->orderByDesc('confirm_at')
->get(['id', 'participate_no']);
$distribution = [];
$no = [];
foreach ($orders as $key => $order) {
$no[] = $order->participate_no;
foreach ($order->items as $item) {
$item = $item->toArray();
if (empty($item['external_sku_id'])) {
continue;
}
$local = $item['goods_sku_location'] ? $item['goods_sku_location']['location'] : '货架未找到';
$index = $key + 1;
$index = 'P' . $index . "({$order->participate_no}) * " . $item['goods_number'];
[$goodsCode, $skuCode] = explode('_', $item['external_sku_id']);
if (isset($distribution[$item['external_sku_id']])) {
$distribution[$item['external_sku_id']]['p'][] = $index;
$distribution[$item['external_sku_id']]['num'] += $item['goods_number'];
} else {
$distribution[$item['external_sku_id']] = [
'p' => [$index],
'local' => $local,
'num' => $item['goods_number'],
'goods_name' => $item['goods_name'],
'goods_code' => $goodsCode,
];
}
}
}
$shopName = Shop::query()->where('id', $shopId)->value('name');
ob_end_clean();
return Excel::download(new OrderBlankExport($shopName, $no, $distribution), $shopName . date('Y-m-d H:i:s') . '.xlsx');
}
public function groupActivity(Request $request, $shopId)
{
$todayTime = Carbon::today()->timestamp;
$todayTime = DateTimeUtils::getMicroTime($todayTime);
return BusinessOrder::query()
->where('shop_id', $shopId)
->where('confirm_at', '>=', $todayTime)
->groupBy(['activity_no', 'activity_title'])
->get(['activity_title', 'activity_no'])
->toArray();
}
}

View File

@ -13,7 +13,6 @@ use Illuminate\Support\Facades\Validator;
use App\Models\Goods;
use App\Http\Requests\GoodsRequest;
use App\Models\DailyStockRecord;
use Illuminate\Support\Facades\Storage;
class GoodsController extends Controller
{

View File

@ -0,0 +1,76 @@
<?php
namespace App\Http\Controllers\Goods;
use App\Http\Controllers\Controller;
use App\Http\Resources\GoodsSkuLocationResource;
use App\Imports\GoodsSkuLocationImport;
use App\Models\GoodsSkuLocation;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Facades\Excel;
class GoodsSkuLocationController extends Controller
{
public function index(Request $request)
{
$goodsSkuLocation = GoodsSkuLocation::query()
->with([
'goods:id,title,goods_code,brand_id,type_id',
'goods.brand:id,name',
'goods.type:id,name',
'goodsSku:id,title,sku_code,stock',
])
->filter()
->paginate($request->get('per_page'));
return GoodsSkuLocationResource::collection($goodsSkuLocation);
}
public function update(Request $request, $id)
{
$goodsSkuLocation = GoodsSkuLocation::query()->findOrFail($id);
if ($location = $request->get('location')) {
$goodsSkuLocation->location = $location;
}
if ($todayInitNum = $request->get('today_init_num')) {
$goodsSkuLocation->today_init_num = $todayInitNum;
}
if ($status = $request->get('status')) {
$goodsSkuLocation->status = $status;
}
if ($note = $request->get('note')) {
$goodsSkuLocation->note = $note;
}
$goodsSkuLocation->save();
return response()->json($this->res);
}
public function delete(Request $request, $id)
{
GoodsSkuLocation::query()->delete($id);
return response()->json($this->res);
}
public function import(Request $request)
{
if (!$request->hasFile('goodsSkuLocation')) {
$this->res = [
'httpCode' => 404,
'errorCode' => 404404,
'errorMessage' => 'not found file',
];
}
try {
$import = new GoodsSkuLocationImport();
$path = $request->file('goodsSkuLocation');
Excel::import($import, $path);
} catch (ValidationException $exception) {
$this->setValidatorFailResponse($exception->validator->getMessageBag()->getMessages());
}
return response($this->res, $this->res['httpCode']);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class BusinessOrderResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class GoodsSkuLocationResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace App\Imports;
use App\Models\Goods;
use App\Models\GoodsSkuLocation;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToArray;
use Maatwebsite\Excel\Concerns\WithStartRow;
class GoodsSkuLocationImport implements ToArray, SkipsEmptyRows, WithStartRow
{
public function startRow(): int
{
return 2;
}
public function array(array $array)
{
$goodsCode = $deleteLocation = [];
foreach ($array as &$row) {
$row = array_map(function ($value) {
return trim($value);
}, $row);
$goodsCode[] = $row[2];
$deleteLocation[] = $row[5];
}
GoodsSkuLocation::query()->whereIn('location', $deleteLocation)->delete();
unset($row);
$goods = Goods::query()
->whereIn('goods_code', $goodsCode)
->get(['id', 'goods_code', 'title']);
$goodsSkus = [];
foreach ($goods as $goodsItem) {
foreach ($goodsItem->skus as $sku){
$goodsSkus[$goodsItem['goods_code']][$sku->sku_code] = [
'goods_id' => $goodsItem->id,
'goods_sku_id' => $sku->id,
'external_sku_id' => $goodsItem['goods_code'] . '_' . $sku->sku_code,
'goods_name' => $goodsItem['title'] . '_' . $sku->title,
];
}
}
$data = [];
foreach ($array as $row) {
if (isset($goodsSkus[$row[2]][$row[4]])) {
$data[] = array_merge($goodsSkus[$row[2]][$row[4]], [
'date' => date('Y-m-d'),
'today_init_num' => $row[1],
'location' => $row[5],
]);
}
}
$model = new GoodsSkuLocation();
$model->batchInsert($data);
}
}

View File

@ -64,6 +64,6 @@ class BusinessGoodsSku extends Model
public function shop()
{
return $this->hasOne(Shop::class, 'id', 'shop_id');
return $this->belongsTo(Shop::class, 'shop_id', 'id');
}
}

View File

@ -2,8 +2,22 @@
namespace App\Models;
use App\Models\traits\Filter;
class BusinessOrder extends Model
{
use Filter;
public $fieldSearchable = [
'participate_no',
'shop_id',
'activity_no',
'shipping_status',
'is_supplier',
'cancel_status',
'after_sales_status',
];
protected $fillable = [
'shop_id',
'receiver_address_detail',
@ -41,8 +55,44 @@ class BusinessOrder extends Model
'order_sn',
];
public function getConfirmAtAttribute($value)
{
return date('Y-m-d H:i:s', $value / 1000);
}
public function getShippingStatusAttribute($value)
{
$map = ['未发货', '已发货', '部分发货'];
return $map[$value];
}
public function getIsSupplierAttribute($value)
{
$map = ['帮忙团订单', '自卖团订单'];
return $map[$value];
}
public function getCancelStatusAttribute($value)
{
$map = ['未取消', '已取消'];
return $map[$value];
}
public function getAfterSalesStatusAttribute($value)
{
return empty($value) ? '未售后' : '有售后';
}
public function items()
{
return $this->hasMany(BusinessOrderItem::class, 'business_order_id');
}
public function shop()
{
return $this->belongsTo(Shop::class, 'shop_id', 'id');
}
}

View File

@ -32,11 +32,16 @@ class BusinessOrderItem extends Model
public function order()
{
return $this->hasOne(BusinessOrder::class, 'id', 'business_order_id');
return $this->belongsTo(BusinessOrder::class, 'business_order_id', 'id');
}
public function shop()
{
return $this->hasOne(Shop::class, 'id', 'shop_id');
return $this->belongsTo(Shop::class, 'shop_id', 'id');
}
public function goodsSkuLocation()
{
return $this->hasOne(GoodsSkuLocation::class, 'external_sku_id', 'external_sku_id');
}
}

View File

@ -42,11 +42,11 @@ class Goods extends Model
public function brand()
{
return $this->hasOne(GoodsBrand::class, 'id', 'brand_id');
return $this->belongsTo(GoodsBrand::class, 'brand_id', 'id');
}
public function type()
{
return $this->hasOne(GoodsType::class, 'id', 'type_id');
return $this->belongsTo(GoodsType::class, 'type_id', 'id');
}
}

View File

@ -64,7 +64,7 @@ class GoodsSku extends Model
*/
public function goods()
{
return $this->hasOne(Goods::class, 'id', 'goods_id');
return $this->belongsTo(Goods::class, 'goods_id', 'id');
}
/**
@ -74,9 +74,4 @@ class GoodsSku extends Model
{
return $this->hasOne(DailyStockRecord::class, 'sku_id', 'id');
}
public function order()
{
return $this->hasOne(BusinessOrderItem::class, 'external_sku_id', 'id');
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Models;
use App\Models\traits\Filter;
class GoodsSkuLocation extends Model
{
use Filter;
public $fieldSearchable = [
'date',
'goods_title',
'goods_code',
'external_sku_id',
'location',
'status',
];
public function goods()
{
return $this->belongsTo(Goods::class, 'goods_id', 'id');
}
public function goodsSku()
{
return $this->belongsTo(GoodsSku::class, 'goods_sku_id', 'id');
}
public function getStatusAttribute($value)
{
$map = ['未使用', '正常', '过期'];
return $map[$value];
}
}

View File

@ -63,6 +63,6 @@ class Groups extends Model
public function shop()
{
return $this->hasOne(Shop::class, 'id', 'shop_id');
return $this->belongsTo(Shop::class, 'shop_id', 'id');
}
}

View File

@ -122,6 +122,6 @@ class Log extends Model
public function user()
{
return $this->hasOne(User::class, 'id', 'user_id');
return $this->belongsTo(User::class, 'user_id', 'id');
}
}

View File

@ -12,7 +12,7 @@ class Model extends EloquentModel
return $query->orderBy('id', 'desc');
}
public function scopeOlder($query)
public function scopeOrder($query)
{
return $query->orderBy('id', 'asc');
}

View File

@ -40,6 +40,6 @@ class DateTimeUtils
}
$time *= 1000;
return ceil($time);
return (int)ceil($time);
}
}

View File

@ -57,6 +57,8 @@ class CreateBusinessOrdersTable extends Migration
$table->timestamps();
// 索引
$table->unique(['shop_id', 'order_sn']);
$table->index(['shop_id', 'participate_no']);
$table->index(['shop_id', 'confirm_at', 'after_sales_status', 'cancel_status', 'is_supplier']);
});
}

View File

@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateGoodsSkuLocationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::defaultStringLength(191);
Schema::create('goods_sku_locations', function (Blueprint $table) {
$table->bigIncrements('id');
$table->date('date');
$table->unsignedBigInteger('goods_id');
$table->unsignedBigInteger('goods_sku_id');
$table->string('location');
$table->integer('today_init_num');
$table->string('external_sku_id');
$table->string('goods_name')->nullable();
$table->tinyInteger('status')->default(1);
$table->string('note')->nullable();
$table->timestamps();
$table->unique('external_sku_id', 'location');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('goods_sku_locations');
}
}

View File

@ -18,6 +18,7 @@ class MenusTableSeeder extends Seeder
['parent_id' => $id, 'code' => 'GOODS_LIST', 'name' => '商品列表', 'seq' => 0],
['parent_id' => $id, 'code' => 'GOODS_TYPE', 'name' => '商品种类', 'seq' => 1],
['parent_id' => $id, 'code' => 'GOODS_BRAND', 'name' => '商品品牌', 'seq' => 2],
['parent_id' => $id, 'code' => 'GOODS_SKU_LOCATION', 'name' => '商品货架', 'seq' => 3],
]);
// 店铺管理
DB::table('menus')->insertGetId(['parent_id' => 0, 'code' => 'SHOP_MANAGE', 'name' => '店铺管理', 'seq' => 10]);
@ -34,6 +35,7 @@ class MenusTableSeeder extends Seeder
$id = DB::table('menus')->insertGetId(['parent_id' => 0, 'code' => 'PLAT', 'name' => '平台', 'seq' => 40]);
DB::table('menus')->insert([
['parent_id' => $id, 'code' => 'PLAT_GOODS_LIST', 'name' => '货品列表', 'seq' => 0],
['parent_id' => $id, 'code' => 'PLAT_ORDER_LIST', 'name' => '订单列表', 'seq' => 1],
]);
// 团购
DB::table('menus')->insertGetId(['parent_id' => 0, 'code' => 'GROUP_MANAGEMENT', 'name' => '团购管理', 'seq' => 1]);

View File

@ -0,0 +1 @@
.block[data-v-8ac9ae68]{margin-top:20px}

View File

@ -0,0 +1 @@
.block[data-v-40c048a6]{margin-top:20px}

View File

@ -1 +1 @@
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>erp</title><link href="css/chunk-088acbde.902ebb66.css" rel="prefetch"><link href="css/chunk-0cbcaa56.e05858e7.css" rel="prefetch"><link href="css/chunk-0f6f9608.b3153d73.css" rel="prefetch"><link href="css/chunk-26daa808.62429343.css" rel="prefetch"><link href="css/chunk-35db73ce.1f9c10ff.css" rel="prefetch"><link href="css/chunk-43a9ad8f.ebe80e03.css" rel="prefetch"><link href="css/chunk-4caed774.ad94328f.css" rel="prefetch"><link href="css/chunk-52fcdd7c.51e3ffbd.css" rel="prefetch"><link href="css/chunk-6ae0a0d3.84a02b23.css" rel="prefetch"><link href="css/chunk-743f0316.fb5066fb.css" rel="prefetch"><link href="css/chunk-75426f71.902ebb66.css" rel="prefetch"><link href="css/chunk-904e5abc.902ebb66.css" rel="prefetch"><link href="css/chunk-a3ddd952.902ebb66.css" rel="prefetch"><link href="css/chunk-ab4d3e40.d941d6ef.css" rel="prefetch"><link href="css/chunk-e35186f0.902ebb66.css" rel="prefetch"><link href="css/chunk-f0b6f0d4.a3b83cc4.css" rel="prefetch"><link href="css/chunk-f35dfe36.ea52b615.css" rel="prefetch"><link href="js/chunk-088acbde.08d60870.js" rel="prefetch"><link href="js/chunk-0cbcaa56.46e3dd42.js" rel="prefetch"><link href="js/chunk-0f6f9608.cdc3788a.js" rel="prefetch"><link href="js/chunk-26daa808.9e326ce2.js" rel="prefetch"><link href="js/chunk-35db73ce.ae2590c3.js" rel="prefetch"><link href="js/chunk-43a9ad8f.22ca8cda.js" rel="prefetch"><link href="js/chunk-4caed774.d65d1796.js" rel="prefetch"><link href="js/chunk-52fcdd7c.0070e388.js" rel="prefetch"><link href="js/chunk-63c1eac8.59f3df74.js" rel="prefetch"><link href="js/chunk-6ae0a0d3.ee4aa3e0.js" rel="prefetch"><link href="js/chunk-743f0316.503949a4.js" rel="prefetch"><link href="js/chunk-75426f71.128f599c.js" rel="prefetch"><link href="js/chunk-904e5abc.e6a5edbe.js" rel="prefetch"><link href="js/chunk-a3ddd952.0482ce75.js" rel="prefetch"><link href="js/chunk-ab4d3e40.078de018.js" rel="prefetch"><link href="js/chunk-e35186f0.055dd015.js" rel="prefetch"><link href="js/chunk-f0b6f0d4.e264ca96.js" rel="prefetch"><link href="js/chunk-f35dfe36.e7038b09.js" rel="prefetch"><link href="css/app.6c30acd7.css" rel="preload" as="style"><link href="css/chunk-vendors.9181e156.css" rel="preload" as="style"><link href="js/app.99e885d1.js" rel="preload" as="script"><link href="js/chunk-vendors.524d6b36.js" rel="preload" as="script"><link href="css/chunk-vendors.9181e156.css" rel="stylesheet"><link href="css/app.6c30acd7.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but erp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.524d6b36.js"></script><script src="js/app.99e885d1.js"></script></body></html>
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>erp</title><link href="css/chunk-088acbde.902ebb66.css" rel="prefetch"><link href="css/chunk-0b2fb3a8.ebe80e03.css" rel="prefetch"><link href="css/chunk-0cbcaa56.e05858e7.css" rel="prefetch"><link href="css/chunk-26daa808.62429343.css" rel="prefetch"><link href="css/chunk-281ed902.b3153d73.css" rel="prefetch"><link href="css/chunk-35db73ce.1f9c10ff.css" rel="prefetch"><link href="css/chunk-4caed774.ad94328f.css" rel="prefetch"><link href="css/chunk-52fcdd7c.51e3ffbd.css" rel="prefetch"><link href="css/chunk-6ae0a0d3.84a02b23.css" rel="prefetch"><link href="css/chunk-743f0316.fb5066fb.css" rel="prefetch"><link href="css/chunk-75426f71.902ebb66.css" rel="prefetch"><link href="css/chunk-7e09c5c4.749f9966.css" rel="prefetch"><link href="css/chunk-904e5abc.902ebb66.css" rel="prefetch"><link href="css/chunk-a3ddd952.902ebb66.css" rel="prefetch"><link href="css/chunk-ab4d3e40.d941d6ef.css" rel="prefetch"><link href="css/chunk-dae6d032.c998c48a.css" rel="prefetch"><link href="css/chunk-e35186f0.902ebb66.css" rel="prefetch"><link href="css/chunk-f0b6f0d4.a3b83cc4.css" rel="prefetch"><link href="css/chunk-f35dfe36.ea52b615.css" rel="prefetch"><link href="js/chunk-088acbde.e3b91ba7.js" rel="prefetch"><link href="js/chunk-0b2fb3a8.c7277f66.js" rel="prefetch"><link href="js/chunk-0cbcaa56.46e3dd42.js" rel="prefetch"><link href="js/chunk-26daa808.9e326ce2.js" rel="prefetch"><link href="js/chunk-281ed902.01d8bc0c.js" rel="prefetch"><link href="js/chunk-35db73ce.ae2590c3.js" rel="prefetch"><link href="js/chunk-4caed774.d65d1796.js" rel="prefetch"><link href="js/chunk-52fcdd7c.0070e388.js" rel="prefetch"><link href="js/chunk-63c1eac8.59f3df74.js" rel="prefetch"><link href="js/chunk-6ae0a0d3.ee4aa3e0.js" rel="prefetch"><link href="js/chunk-743f0316.cc5e2a5b.js" rel="prefetch"><link href="js/chunk-75426f71.128f599c.js" rel="prefetch"><link href="js/chunk-7e09c5c4.5e89acae.js" rel="prefetch"><link href="js/chunk-904e5abc.e6a5edbe.js" rel="prefetch"><link href="js/chunk-a3ddd952.0482ce75.js" rel="prefetch"><link href="js/chunk-ab4d3e40.c28d58b3.js" rel="prefetch"><link href="js/chunk-dae6d032.7fa60b44.js" rel="prefetch"><link href="js/chunk-e35186f0.f1d6b68d.js" rel="prefetch"><link href="js/chunk-f0b6f0d4.b774c023.js" rel="prefetch"><link href="js/chunk-f35dfe36.e7038b09.js" rel="prefetch"><link href="css/app.6c30acd7.css" rel="preload" as="style"><link href="css/chunk-vendors.9181e156.css" rel="preload" as="style"><link href="js/app.7aa7bce6.js" rel="preload" as="script"><link href="js/chunk-vendors.524d6b36.js" rel="preload" as="script"><link href="css/chunk-vendors.9181e156.css" rel="stylesheet"><link href="css/app.6c30acd7.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but erp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.524d6b36.js"></script><script src="js/app.7aa7bce6.js"></script></body></html>

2
public/dist/js/app.7aa7bce6.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/app.7aa7bce6.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -94,3 +94,36 @@ export function getGoodsList(params) {
params,
});
}
// 商品货架
export function goodsSkuLocation(params) {
return http({
url: "/api/goods_sku_location",
method: "get",
params,
});
}
export function importGoodsSkuLocation(params) {
return http({
url: "/api/goods_sku_location",
method: "post",
params,
});
}
export function updateGoodsSkuLocation(params) {
return http({
url: "/api/goods_sku_location",
method: "put",
params,
});
}
export function deleteGoodsSkuLocation(params) {
return http({
url: "/api/goods_sku_location",
method: "delete",
params,
});
}

View File

@ -30,3 +30,27 @@ export function syncStock(id) {
method: "post",
});
}
export function activityList(shopId) {
return http({
url: "/api/plat_group_activity/" + shopId,
method: "get",
});
}
// 平台订单列表
export function platOrderList(params) {
return http({
url: "/api/plat_orders",
method: "get",
params
});
}
export function platOrderExport(params) {
return http({
url: "/plat_orders/export",
method: "get",
params,
});
}

View File

@ -26,6 +26,11 @@ const list = [
name: "商品品牌",
component: () => import("../views/brand/brand.vue"),
},
{
path: "GOODS_SKU_LOCATION",
name: "商品货架",
component: () => import("../views/goods/location.vue"),
},
{
path: "SHOP_MANAGE",
name: "店铺管理",
@ -70,6 +75,11 @@ const list = [
name: "货品列表",
component: () => import("../views/plat/goodsList.vue"),
},
{
path: "PLAT_ORDER_LIST",
name: "订单列表",
component: () => import("../views/plat/orderList.vue"),
},
{
path: "GROUP_MANAGEMENT",
name: "团购管理",

View File

@ -0,0 +1,171 @@
<template>
<div class="conent">
<el-card :body-style="{ padding: '20px 20px 0 20px' }">
<el-form ref="form" :inline="true" :model="form">
<el-form-item label="日期:">
<el-date-picker v-model="form.date" type="date" placeholder="日期"></el-date-picker>
</el-form-item>
<el-form-item label="商品名称:">
<el-input v-model="form.goods_title" placeholder="商品名称"></el-input>
</el-form-item>
<el-form-item label="商品编码:">
<el-input v-model="form.goods_code" placeholder="商品编码"></el-input>
</el-form-item>
<el-form-item label="完整编码:">
<el-input v-model="form.external_sku_id" placeholder="完整编码"></el-input>
</el-form-item>
<el-form-item label="货架号:">
<el-input v-model="form.location" placeholder="货架号"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleChoose">筛选</el-button>
<el-button plain @click="handleReChoose">重置筛选</el-button>
<el-upload ref="myUpload" action="/api/goods_sku_location" :multiple="false" name="goodsSkuLocation"
:show-file-list="false" :on-success="uploadSuccess" :before-upload="beforeUpload"
:on-error="uploadError" style="display:inline-block;margin: 0 10px 0 10px;">
<el-button type="primary" plain>商品货架导入</el-button>
</el-upload>
</el-form-item>
</el-form>
</el-card>
<el-card style="margin-top: 10px">
<el-table v-loading="loading" ref="multipleTable" :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期"></el-table-column>
<el-table-column label="种类">
<template slot-scope="scope">
{{ scope.row.goods.type.name }}
</template>
</el-table-column>
<el-table-column label="品牌">
<template slot-scope="scope">
{{ scope.row.goods.brand.name }}
</template>
</el-table-column>
<el-table-column label="商品名称" prop="goods_name"></el-table-column>
<el-table-column label="完整编码" prop="external_sku_id"></el-table-column>
<el-table-column label="库存">
<template slot-scope="scope">
{{ scope.row.goods_sku.stock }}
</template>
</el-table-column>
<el-table-column prop="location" label="货架号"></el-table-column>
<el-table-column prop="today_init_num" label="导入时数量"></el-table-column>
<!-- <el-table-column prop="status" label="状态"></el-table-column>
<el-table-column prop="note" label="备注"></el-table-column> -->
</el-table>
<!-- 分页功能 -->
<div class="block">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
:current-page="current_page" :page-sizes="[15, 50, 100]" :page-size="per_page"
layout="total, sizes, prev, pager, next, jumper" :total="Paginationdata.total">
</el-pagination>
</div>
</el-card>
</div>
</template>
<script>
import { goodsSkuLocation } from "../../api/goods";
export default {
data() {
return {
form: {
date: "",
goods_title: "",
goods_code: "",
external_sku_id: "",
location: "",
},
dialogVisible: false,
loading: true,
tableData: [],
Paginationdata: {}, //
current_page: 1, //
per_page: 10, //
};
},
mounted() {
this.goodsSkuLocation();
},
methods: {
//
goodsSkuLocation(params = {}) {
params.page = this.current_page;
params.per_page = this.per_page;
goodsSkuLocation(params).then((res) => {
this.tableData = res.data.data;
this.Paginationdata = res.data.meta;
});
this.loading = false;
},
//
handleSizeChange(val) {
//
this.current_page = 1;
this.per_page = val;
this.goodsSkuLocation();
},
handleCurrentChange(val) {
//
this.current_page = val;
this.goodsSkuLocation();
},
//
handleChoose() {
this.form = {
...this.form,
page: 1,
per_page: this.per_page,
};
this.goodsSkuLocation(this.form);
},
//
handleReChoose() {
this.form = {
shipping_status: "",
is_supplier: "",
cancel_status: "",
after_sales_status: "",
};
this.goodsSkuLocation();
},
beforeUpload() {
this.loadingModule = this.$loading({
lock: true,
text: '盘点导入中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
},
uploadSuccess(response) {
this.$message({
message: response.message,
type: "success",
});
this.loadingModule.close();
},
uploadError(err) {
this.$message({
message: err.errorMessage,
type: "error",
});
this.loadingModule.close();
}
},
};
</script>
<style lang="scss" scoped>
.block {
margin-top: 20px;
}
</style>

View File

@ -0,0 +1,242 @@
<template>
<div class="conent">
<el-card :body-style="{ padding: '20px 20px 0 20px' }">
<el-form ref="form" :inline="true" :model="form">
<el-form-item label="店铺:">
<el-select v-model="form.shop_id" placeholder="店铺" @change="setActivity">
<el-option v-for="item in shops" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="活动名称:">
<el-select v-model="form.activity_no" placeholder="活动名称">
<el-option v-for="item in groupActivity" :key="item.activity_no" :label="item.activity_title"
:value="item.activity_no">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="发货状态:">
<el-select v-model="form.shipping_status" placeholder="发货状态">
<el-option value="" label="全部"></el-option>
<el-option value="0" label="未发货"></el-option>
<el-option value="2" label="部分发货"></el-option>
<el-option value="1" label="已发货"></el-option>
</el-select>
</el-form-item>
<el-form-item label="订单类型:">
<el-select v-model="form.is_supplier" placeholder="订单类型">
<el-option value="" label="全部订单"></el-option>
<el-option value="1" label="自卖团订单"></el-option>
<el-option value="0" label="帮忙团订单"></el-option>
</el-select>
</el-form-item>
<el-form-item label="订单状态:">
<el-select v-model="form.cancel_status" placeholder="订单状态">
<el-option value="" label="全部"></el-option>
<el-option value="0" label="未取消"></el-option>
<el-option value="1" label="已取消"></el-option>
</el-select>
</el-form-item>
<el-form-item label="售后状态:">
<el-select v-model="form.after_sales_status" placeholder="售后状态">
<el-option value="" label="全部"></el-option>
<el-option value="0" label="未售后"></el-option>
<el-option value="1" label="有售后"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleChoose">筛选</el-button>
<el-button plain @click="handleReChoose">重置筛选</el-button>
</el-form-item>
<el-button type="primary" @click="dialogVisible = true">配货单导出</el-button>
</el-form>
</el-card>
<el-card style="margin-top: 10px">
<el-table v-loading="loading" ref="multipleTable" :data="tableData" style="width: 100%">
<el-table-column label="店铺名称">
<template slot-scope="scope">
{{ scope.row.shop.name }}
</template>
</el-table-column>
<el-table-column prop="activity_title" label="活动名称"></el-table-column>
<el-table-column prop="shipping_status" label="发货状态"></el-table-column>
<el-table-column prop="is_supplier" label="订单类型"></el-table-column>
<el-table-column prop="cancel_status" label="订单状态"></el-table-column>
<el-table-column prop="after_sales_status" label="售后状态"></el-table-column>
<el-table-column prop="participate_no" label="跟团号"></el-table-column>
<el-table-column label="商品信息">
<template slot-scope="scope">
<div v-for="item in scope.row.items" :key="item.id">
<!-- {{ item.goods_name }}*{{ item.goods_number }} -->
{{ item.external_sku_id }}
</div>
</template>
</el-table-column>
<el-table-column prop="confirm_at" label="下单时间"></el-table-column>
</el-table>
<!-- 分页功能 -->
<div class="block">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
:current-page="current_page" :page-sizes="[15, 50, 100]" :page-size="per_page"
layout="total, sizes, prev, pager, next, jumper" :total="Paginationdata.total">
</el-pagination>
</div>
</el-card>
<!-- 配货单导出 -->
<el-dialog title="配货单导出" :visible.sync="dialogVisible" :close-on-click-modal="false">
<el-form ref="exportForm" :model="exportForm" label-width="100px" :rules="exportFormRules">
<el-form-item label="店铺:" prop="shop_id">
<el-select v-model="exportForm.shop_id" placeholder="店铺" @change="setActivity">
<el-option v-for="item in shops" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="开始跟团号" prop="start_no">
<el-input v-model="exportForm.start_no"></el-input>
</el-form-item>
<el-form-item label="结束跟团号" prop="end_no">
<el-input v-model="exportForm.end_no"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="derivation('exportForm')">导出</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script>
import { platOrderList, activityList, platOrderExport } from "../../api/plat";
import { storeList } from "../../api/shop";
export default {
data() {
return {
form: {
shop_id: "",
activity_no: "",
shipping_status: "",
is_supplier: "",
cancel_status: "",
after_sales_status: "",
},
dialogVisible: false,
loading: true,
tableData: [],
Paginationdata: {}, //
current_page: 1, //
per_page: 10, //
shops: [],
groupActivity: [],
exportForm: {
shop_id: "",
start_no: "",
end_no: ""
},
exportFormRules: {
shop_id: [
{ required: true, trigger: 'blur' }
],
start_no: [
{ required: true, trigger: 'blur' }
],
end_no: [
{ required: true, trigger: 'blur' }
],
}
};
},
mounted() {
//
this.getPlatOrderList();
this.getShopsList();
},
methods: {
//
getPlatOrderList(params = {}) {
params.page = this.current_page;
params.per_page = this.per_page;
platOrderList(params).then((res) => {
this.tableData = res.data.data;
this.Paginationdata = res.data.meta;
});
},
getShopsList() {
let page = {
page: 0,
per_page: 99,
};
storeList(page).then((res) => {
this.shops = res.data.data;
});
this.loading = false;
},
//
handleSizeChange(val) {
//
this.current_page = 1;
this.per_page = val;
this.getPlatOrderList();
},
handleCurrentChange(val) {
//
this.current_page = val;
this.getPlatOrderList();
},
//
handleChoose() {
this.form = {
...this.form,
page: 1,
per_page: this.per_page,
};
this.getPlatOrderList(this.form);
},
//
handleReChoose() {
this.form = {
shop_id: "",
activity_no: "",
shipping_status: "",
is_supplier: "",
cancel_status: "",
after_sales_status: "",
};
this.getPlatOrderList();
},
setActivity(shopId) {
activityList(shopId).then((res) => {
this.groupActivity = res.data;
})
},
derivation(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
window.open("/plat_orders/export?shop_id=" + this.exportForm.shop_id + '&start_no=' + this.exportForm.start_no + '&end_no=' + this.exportForm.end_no);
} else {
return false;
}
});
}
},
};
</script>
<style lang="scss" scoped>
.block {
margin-top: 20px;
}
</style>

View File

@ -11,7 +11,7 @@ module.exports = {
proxy: {
// 配置代理
"/api": {
// target: "http://172.23.134.136:81",
// target: "http://192.168.247.186:81",
target: "http://erp.chutang66.com",
changeOrigin: true, // 开启代理
pathRewrite: {

View File

@ -122,6 +122,31 @@ return [
'name' => '删除',
'parent_id' => 4,
],
'GOODS_SKU_LOCATION' => [
'id' => 15,
'name' => '商品货架',
'parent_id' => 1,
],
'goods_sku_location.index' => [
'id' => 150,
'name' => '列表',
'parent_id' => 15,
],
'goods_sku_location.import' => [
'id' => 151,
'name' => '导入',
'parent_id' => 15,
],
'goods_sku_location.update' => [
'id' => 152,
'name' => '更新',
'parent_id' => 15,
],
'goods_sku_location.destroy' => [
'id' => 153,
'name' => '删除',
'parent_id' => 15,
],
// 店铺管理
'SHOP_MANAGE' => [
'id' => 5,
@ -282,6 +307,26 @@ return [
'name' => '同步库存',
'parent_id' => 120,
],
'plat.activity.list' => [
'id' => 1204,
'name' => '团购活动列表',
'parent_id' => 120,
],
'PLAT_ORDER_LIST' => [
'id' => 14,
'name' => '订单列表',
'parent_id' => 12,
],
'plat.orders.index' => [
'id' => 140,
'name' => '订单列表',
'parent_id' => 14,
],
'plat.orders.export' => [
'id' => 1400,
'name' => '配货单导出',
'parent_id' => 140,
],
// 团购管理
'GROUP_MANAGEMENT' => [
'id' => 13,

View File

@ -7,6 +7,8 @@ use App\Http\Controllers\Shop\ShopsController;
use App\Http\Controllers\Goods\GoodsSkusController;
use App\Http\Controllers\Business\BusinessGoodsSkusController;
use App\Http\Controllers\Group\GroupsController;
use App\Http\Controllers\Business\BusinessOrderController;
use App\Http\Controllers\Goods\GoodsSkuLocationController;
/*
|--------------------------------------------------------------------------
@ -46,9 +48,15 @@ Route::middleware(['auth:api', 'check.permissions'])->group(function () {
]]);
// 平台
Route::resource('plat_goods', 'Business\BusinessGoodsSkusController', ['only' => ['index', 'update', 'destroy']]);
Route::get('plat_orders', [BusinessOrderController::class, 'index'])->name('plat.orders.index');
Route::get('plat_group_activity/{shopId}', [BusinessOrderController::class, 'groupActivity'])->name('plat.activity.list');
Route::post('plat/sync/{id}/stock', [BusinessGoodsSkusController::class, 'syncStock'])->name('plat.sync.stock');
// 团购
Route::resource('group', 'Group\GroupsController', ['only' => ['index', 'store', 'show', 'update', 'destroy']]);
// 商品货架
Route::get('goods_sku_location', [GoodsSkuLocationController::class, 'index'])->name('goods_sku_location.index');
Route::put('goods_sku_location', [GoodsSkuLocationController::class, 'update'])->name('goods_sku_location.update');
Route::delete('goods_sku_location', [GoodsSkuLocationController::class, 'delete'])->name('goods_sku_location.delete');
});
// 登录
Route::post('/auth/login', [LoginController::class, 'login'])->name('auth.login');
@ -72,6 +80,7 @@ Route::post('business', [ShopsController::class, 'business'])->name('shop.put.bu
// 盘点导入
Route::post('inventory/goods_skus', [GoodsSkusController::class, 'inventoryImport'])->name('goods_sku.inventory');
// 商品货架导入
Route::post('goods_sku_location', [GoodsSkuLocationController::class, 'import'])->name('goods_sku_location.import');
Route::post('upload', [UploadController::class, 'store'])->name('upload.file');

View File

@ -3,6 +3,7 @@
use App\Http\Controllers\Goods\GoodsSkusController;
use App\Http\Controllers\Goods\GoodsController;
use App\Http\Controllers\Shop\ShopsController;
use App\Http\Controllers\Business\BusinessOrderController;
/*
|--------------------------------------------------------------------------
@ -20,6 +21,7 @@ Route::get('/', function () {
});
Route::get('goods_skus/export', [GoodsSkusController::class, 'export'])->name('goods_skus.export');
Route::get('plat_orders/export', [BusinessOrderController::class, 'exportOrderBlank'])->name('plat.orders.export');
Route::get('goods/import/template', [GoodsController::class, 'download'])->name('download.goods_import.template');