feat: #10000 页面优化,功能优化

This commit is contained in:
赵世界 2022-09-08 01:02:07 +08:00
parent 1da2e43dd4
commit 8fc2ad6972
25 changed files with 869 additions and 366 deletions

View File

@ -0,0 +1,68 @@
<?php
namespace App\Console\Commands;
use App\Models\DailyStockRecord;
use App\Models\Goods;
use App\Models\GoodsSku;
use App\Models\Log;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class DeleteGoodsSku extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'delete:goods_sku {code : 完整的商品编码}';
/**
* 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()
{
$code = $this->argument('code');
if (empty($code)) {
reutrn;
}
[$goodsCode, $skuCode] = explode('_', $code);
DB::beginTransaction();
try {
$goods = Goods::query()->where('goods_code', $goodsCode)->first();
$countSkus = GoodsSku::query()->where('goods_id', $goods->id)->count();
$sku = GoodsSku::query()->where('goods_id', $goods->id)->where('sku_code', $skuCode)->first();
DailyStockRecord::where('sku_id', $sku->id)->delete();
Log::where('module', 'goods')->where('target_type', 'goods_sku')->where('target_id', $sku->id)->delete();
$sku->delete();
if (1 === $countSkus) {
$goods->delete();
}
DB::commit();
$this->info('删除成功');
} catch (\Exception $exception) {
DB::rollBack();
$this->info('删除失败' . $exception->getMessage());
}
}
}

View File

@ -7,6 +7,7 @@ use App\Models\Shop;
use App\Services\Business\BusinessFactory;
use App\Utils\DateTimeUtils;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class Test extends Command
{

View File

@ -2,15 +2,29 @@
namespace App\Http\Controllers\Business;
use App\Events\StockUpdateEvent;
use App\Http\Controllers\Controller;
use App\Http\Resources\BusinessGoodsSkuResource;
use App\Models\BusinessGoodsSku;
use App\Models\BusinessOrderItem;
use App\Models\GoodsSku;
use App\Models\Log as LogModel;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
class BusinessGoodsSkusController extends Controller
{
public function __construct(Request $request)
{
$this->log = new LogModel([
'module' => 'plat',
'action' => $request->getMethod(),
'target_type' => 'goods',
]);
}
public function index(Request $request)
{
$businessGoodsSkus = BusinessGoodsSku::query()
@ -32,9 +46,50 @@ class BusinessGoodsSkusController extends Controller
return response($this->res, $this->res['httpCode']);
}
$sku = BusinessGoodsSku::find($id);
$this->setBeforeUpdate($sku->is_sync);
$sku->is_sync = $request->input('is_sync');
$sku->save();
$this->setAfterUpdate($sku->is_sync);
$this->addLog($id, 'status');
return response($this->res, $this->res['httpCode']);
}
public function destroy(Request $request, $id)
{
DB::beginTransaction();
try {
$sku = BusinessGoodsSku::find($id);
$this->setBeforeUpdate($sku->toArray());
BusinessOrderItem::where('goods_id', $sku->goods_id)->where('sku_id', $sku->sku_id)->delete();
$sku->delete();
$this->setAfterUpdate('');
$this->addLog($id, '');
DB::commit();
} catch (Exception $exception) {
DB::rollBack();
// 返回错误
$this->setValidatorFailResponse($exception->getMessages());
}
return response($this->res, $this->res['httpCode']);
}
public function syncStock(Request $request, $id)
{
$businessGoodsSku = BusinessGoodsSku::find($id);
[$goodsCode, $skuCode] = explode('_', $businessGoodsSku->external_sku_id);
$sku = GoodsSku::query()->where('sku_code', $skuCode)
->whereHas('goods', function ($query) use ($goodsCode) {
$query->where('goods_code', $goodsCode);
})
->first();
if (empty($sku)) {
$this->setValidatorFailResponse('未找到对应的商品,请核实后再次同步或删除此平台商品');
} else {
event(new StockUpdateEvent($sku));
$this->res['message'] = '库存同步请求发送成功,具体结果查看日志';
}
return response($this->res, $this->res['httpCode']);
}
}

View File

@ -7,6 +7,7 @@ use App\Exports\GoodsSkusExport;
use App\Http\Controllers\Controller;
use App\Http\Requests\GoodsRequest;
use App\Http\Requests\GoodsSkuRequest;
use App\Imports\InventoryImport;
use App\Models\BusinessOrderItem;
use App\Models\Goods;
use App\Models\Log;
@ -37,7 +38,13 @@ class GoodsSkusController extends Controller
public function index(Request $request)
{
$goods = Goods::query()->filter()->get()->toArray();
$goodsCode = $skuCode = '';
if ($externalSkuId = $request->get('external_sku_id')) {
[$goodsCode, $skuCode] = explode('_', $externalSkuId);
}
$goods = Goods::query()->filter()->when($goodsCode, function ($query, $goodsCode) {
return $query->where('goods_code', $goodsCode);
})->get()->toArray();
$goodsIds = array_column($goods, 'id');
// 状态变更时间查询,日志
$ids = [];
@ -54,6 +61,9 @@ class GoodsSkusController extends Controller
->when($ids, function ($query, $ids) {
return $query->whereIn('id', $ids);
})
->when($skuCode, function ($query, $skuCode) {
return $query->where('sku_code', $skuCode);
})
->filter()
->with(['goods' => function ($query) {
$query->with(['type:id,name', 'brand:id,name']);
@ -460,4 +470,26 @@ class GoodsSkusController extends Controller
ob_end_clean();
return Excel::download(new GoodsSkusExport($type), $type . '.xlsx');
}
public function inventoryImport(Request $request)
{
if (!$request->hasFile('inventoryFile')) {
$this->res = [
'httpCode' => 404,
'errorCode' => 404404,
'errorMessage' => 'not found inventory file',
];
}
try {
$import = new InventoryImport();
$path = $request->file('inventoryFile');
Excel::import($import, $path);
$this->addLog(0, 'import', 'inventory');
} catch (ValidationException $exception) {
$this->setValidatorFailResponse($exception->validator->getMessageBag()->getMessages());
}
return response($this->res, $this->res['httpCode']);
}
}

View File

@ -30,12 +30,12 @@ class GoodsSkusImport implements ToCollection, SkipsEmptyRows
* @throws ValidationException
* @throws Exception
*/
public function collection(Collection $rows)
public function collection(Collection $collection)
{
unset($rows[0], $rows[1]);
$rows = $rows->toArray();
unset($collection[0], $collection[1]);
$collection = $collection->toArray();
$types = $brands = $goodsCodes = [];
foreach ($rows as &$row) {
foreach ($collection as &$row) {
$row = array_map(static function ($v) {
return trim($v);
}, $row);
@ -43,7 +43,7 @@ class GoodsSkusImport implements ToCollection, SkipsEmptyRows
$brands[] = $row[2];
$goodsCodes[] = $row[3];
}
$validator = Validator::make($rows, [
$validator = Validator::make($collection, [
'*.0' => ['required', 'string', 'max:191'],
'*.1' => ['required', 'string', 'max:191', 'exists:goods_types,name'],
'*.2' => ['string', 'max:191', 'exists:goods_brands,name'],
@ -64,7 +64,7 @@ class GoodsSkusImport implements ToCollection, SkipsEmptyRows
$hasGoods = Goods::query()->whereIn('goods_code', $goodsCodes)->get(['id', 'goods_code'])->toArray();
$hasGoods = ArrayUtils::index($hasGoods, 'goods_code');
$newGoods = $skus = [];
foreach ($rows as $row) {
foreach ($collection as $row) {
$sku = [
'goods_id' => $row[3],
'title' => $row[4],

View File

@ -0,0 +1,75 @@
<?php
namespace App\Imports;
use App\Events\StockUpdateEvent;
use App\Models\DailyStockRecord;
use App\Models\Goods;
use App\Models\GoodsSku;
use App\Utils\DateTimeUtils;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToCollection;
use App\Utils\ArrayUtils;
class InventoryImport implements ToCollection, SkipsEmptyRows
{
/**
* @throws Exception
*/
public function collection(Collection $collection)
{
unset($collection[0]);
$collection = $collection->toArray();
$goodsCodes = [];
foreach ($collection as &$row) {
$row = array_map(static function ($v) {
return trim($v);
}, $row);
$goodsCodes[] = $row[0];
}
unset($row);
$hasGoods = Goods::query()->whereIn('goods_code', $goodsCodes)->get(['id', 'goods_code'])->toArray();
$hasGoods = ArrayUtils::index($hasGoods, 'goods_code');
$updateIds = [];
$day = DateTimeUtils::getToday();
$dateTime = date('Y-m-d H:i:s');
DB::beginTransaction();
try {
foreach ($collection as $row) {
if (!isset($hasGoods[$row[0]])) {
continue;
}
$goodsSku = GoodsSku::query()
->where('goods_id', $hasGoods[$row[0]]['id'])
->where('sku_code', $row[4])
->first(['id']);
if (empty($goodsSku)) {
Log::warning(json_encode($row, 256) . '=====库存导入未找到');
continue;
}
$updateIds[] = $goodsSku->id;
DailyStockRecord::where('sku_id', $goodsSku->id)->where('day', $day)->update([
'inventory' => $row[6],
'inventory_time' => $dateTime
]);
}
DB::commit();
} catch (Exception $exception) {
DB::rollBack();
// 返回错误
throw $exception;
}
$onSkuIds = GoodsSku::query()
->where('stock', '>', 0)
->where('status', '<>', 0)
->pluck('id')
->toArray();
if ($downSkuIds = array_diff($onSkuIds, $updateIds)) {
event(new StockUpdateEvent($downSkuIds));
}
}
}

View File

@ -19,14 +19,43 @@ class BusinessGoodsSku extends Model
* @var mixed
*/
public $goods_id;
/**
* @var mixed
*/
public $sku_id;
/**
* @var mixed
*/
public $external_sku_id;
protected $hidden = [
'self_sku_id',
'activity_no',
'goods_desc',
'goods_image_list',
'is_activity_delete',
'limit_buy',
'market_price',
'update_time',
'goods_purchase_price',
'price_in_fen',
'quantity',
'goods_purchase_price',
'price_in_fen',
'quantity',
'quantity_type',
'reserve_quantity',
'sold_quantity',
'spec_list',
'spec_name',
'thumb_url',
'total_quantity',
'updated_at',
'create_time'
];
/**
* 不可批量赋值的属性。为空则所有熟悉都可以批量赋值
*

View File

@ -31,6 +31,9 @@ class MenusTableSeeder extends Seeder
['parent_id' => $id, 'code' => 'SYSTEM_LOG', 'name' => '系统日志', 'seq' => 2],
]);
// 平台
DB::table('menus')->insertGetId(['parent_id' => 0, 'code' => 'PLAT', 'name' => '平台', 'seq' => 4]);
$id = DB::table('menus')->insertGetId(['parent_id' => 0, 'code' => 'PLAT', 'name' => '平台', 'seq' => 4]);
DB::table('menus')->insert([
['parent_id' => $id, 'code' => 'PLAT_GOODS_LIST', 'name' => '货品列表', 'seq' => 0],
]);
}
}

34
resources/frontend/src/api/plat.js vendored Normal file
View File

@ -0,0 +1,34 @@
import http from "@/util/http.js";
// 平台页面请求
// 平台商品列表
export function platGoodsList(params) {
return http({
url: "/api/plat_goods",
method: "get",
params,
});
}
export function updateSyncStatus(id, params) {
return http({
url: "/api/plat_goods/" + id,
method: "patch",
params,
});
}
export function deletePlatGoods(id) {
return http({
url: "/api/plat_goods/" + id,
method: "delete",
});
}
export function syncStock(id) {
return http({
url: "/api/plat/sync/" + id + "/stock/",
method: "post",
});
}

View File

@ -7,12 +7,6 @@ import "element-ui/lib/theme-chalk/index.css";
import "@/css/style.css";
import "./router/index2";
// import Router from 'vue-router'
// const routerPush = Router.prototype.push
// Router.prototype.push = function push(location) {
// return routerPush.call(this, location).catch(error=> error)
// }
Vue.use(ElementUI);
Vue.config.productionTip = false;

View File

@ -60,6 +60,11 @@ const list = [
path: "/",
redirect: "GOODS_LIST",
},
{
path: "PLAT_GOODS_LIST",
name: "货品列表",
component: () => import("../views/plat/goodsList.vue"),
},
],
},
];

View File

@ -4,7 +4,7 @@
<el-button type="primary" @click="handAdd">新增</el-button>
<!-- 列表 -->
<div class="table" style="margin-top: 20px">
<div class="table" style="margin-top: 10px">
<el-table ref="multipleTable" :data="tableData" tooltip-effect="dark" style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column prop="name" label="商品品牌"> </el-table-column>

View File

@ -5,6 +5,10 @@
<el-card :body-style="{ padding: '20px 20px 0 20px' }">
<div class="goods">
<el-form ref="form" :inline="true" :model="form">
<el-form-item label="商品编码:">
<el-input v-model="form.external_sku_id" placeholder="商品编码" style="width: 100px">
</el-input>
</el-form-item>
<el-form-item label="商品名称:">
<el-input v-model="form.goods_title" placeholder="商品名称" style="width: 100px">
</el-input>
@ -51,17 +55,22 @@
</div>
</el-card>
<el-card style="margin-top: 20px">
<el-card style="margin-top: 10px">
<div>
<!-- 表格头部操作 -->
<div>
<span>全部商品({{ total }})</span>
<div class="btn">
<el-button type="primary" plain @click="addNewgoods">新建商品</el-button>
<el-button type="primary" plain @click="update()">上新</el-button>
<el-button type="primary" plain @click="onCount()">库存盘点</el-button>
<el-upload ref="myUpload" action="/api/inventory/goods_skus" :multiple="false"
name="inventoryFile" :show-file-list="false" :on-success="inventorySuccess"
:on-error="inventoryError" style="display:inline-block;margin: 0 10px 0 10px;">
<el-button type="primary" plain>盘点导入</el-button>
</el-upload>
<el-button type="primary" plain @click="addNewgoods">新建商品</el-button>
<el-button type="primary" plain @click="handleImport()">导入商品</el-button>
<el-button type="primary" plain @click="handleExport()">表格导出</el-button>
<el-button type="primary" plain @click="onCount()">库存盘点</el-button>
</div>
</div>
@ -69,7 +78,7 @@
<el-table ref="multipleTable" :data="tableData" class="table" tooltip-effect="dark" style="width: 100%"
@selection-change="handleSelectionChange" max-height="1500">
<!-- 多选框 -->
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column type="selection"></el-table-column>
<el-table-column label="商品信息" width="300">
<template slot-scope="scope">
<div class="commodityimg">
@ -93,7 +102,7 @@
</div>
</template>
</el-table-column>
<el-table-column label="规格" prop="title"> </el-table-column>
<el-table-column label="规格" prop="title" width="130"></el-table-column>
<el-table-column label="品牌">
<template slot-scope="scope">
<div>
@ -106,7 +115,7 @@
<el-table-column prop="yesterday_num" sortable label="1T">
</el-table-column>
<el-table-column sortable label="0T" min-width="80">
<el-table-column sortable label="0T">
<template slot-scope="scope">
<div v-if="isShow">
<el-input v-model="scope.row.arrived_today_num11"></el-input>
@ -128,7 +137,7 @@
</template>
</el-table-column>
<el-table-column prop="reference_price" sortable label="售价" min-width="80">
<el-table-column prop="reference_price" sortable label="售价">
<template slot-scope="scope">
<div v-if="scope.row.id === id">
<el-input v-model="scope.row.reference_price" @blur="reference_priceBlur(scope.row)">
@ -142,9 +151,9 @@
</div>
</template>
</el-table-column>
<el-table-column prop="num" sortable label="总量" min-width="80">
<el-table-column prop="num" sortable label="总量">
</el-table-column>
<el-table-column prop="reserve" sortable label="预留" min-width="80">
<el-table-column prop="reserve" sortable label="预留">
<template slot-scope="scope">
<div v-if="scope.row.id === id1">
<el-input v-model="scope.row.reserve" @blur="reservebBlur(scope.row)"></el-input>
@ -157,12 +166,12 @@
</template>
</el-table-column>
<el-table-column sortable label="订单" min-width="80">
<el-table-column sortable label="订单">
<template slot-scope="scope">
<div>
<span>{{ scope.row.order_goods_num }}</span>
</div>
<el-popover placement="right-start" width="200" trigger="hover"
<el-popover placement="right-start" trigger="hover"
v-if="scope.row.order_detail.length !== 0">
<div>
<span v-for="(j, index) in scope.row.order_detail" :key="index">
@ -184,11 +193,14 @@
<div v-else>
{{ scope.row.daily.loss_num }}
</div>
<el-popover placement="right-start" width="220" trigger="click" @hide="noBubbles">
<p>损耗:</p>
<el-input v-model="scope.row.daily.loss_num"></el-input>
<el-radio-group v-model="radio">
<el-radio disabled>原因:</el-radio>
<el-popover placement="right-start" trigger="click" @hide="noBubbles" width="264">
<div>
<span>损耗数量: </span>
<el-input v-model="scope.row.daily.loss_num" style="width: 200px;"></el-input>
</div>
<div style="margin-top: 10px;">
<span>原因: </span>
<el-radio-group v-model="radio" style="width: 220px;">
<el-radio label="48h以上">48h以上</el-radio>
<el-radio label="到货错误">到货错误</el-radio>
<el-radio label="灰霉">灰霉</el-radio>
@ -196,11 +208,16 @@
<el-radio label="花朵">花朵</el-radio>
<el-radio label="其他">其他</el-radio>
</el-radio-group>
<div class="list_btn">
<el-button type="primary" @click="onLoss(scope.row)">保存</el-button>
</div>
<el-button slot="reference" class="btn11" @click="loss(scope.row.id)"><img
src="../../css/img/编辑.png" alt="" /></el-button>
<div style="margin-top: 10px;">
<el-button type="primary" @click="onLoss(scope.row)" size="mini">保存</el-button>
<!-- <el-button size="mini" type="primary" plain @click="closeLossPopover()">取消
</el-button> -->
</div>
<el-button slot="reference" class="btn11" @click="loss(scope.row.id)">
<img src="../../css/img/编辑.png" alt="" />
</el-button>
</el-popover>
</template>
</el-table-column>
@ -212,7 +229,7 @@
<div v-if="stock">
<el-input v-model="scope.row.daily.inventory"></el-input>
</div>
<el-popover placement="right-start" width="100" trigger="hover" :content="
<el-popover placement="right-start" trigger="hover" :content="
scope.row.daily.inventory_time
? scope.row.daily.inventory_time
: ''
@ -225,55 +242,12 @@
</el-table-column>
<el-table-column prop="status" label="状态"> </el-table-column>
<el-table-column label="操作" width="100">
<el-table-column label="操作" width="130">
<template slot-scope="scope">
<div>
<el-button type="text" @click="ejectstock(scope.row)">库存</el-button>
</div>
<div>
<el-button type="text" @click="handleEdit(scope.row.goods_id, scope.row.id)">编辑
</el-button>
</div>
<div>
<el-button type="text" @click="handleEdit(scope.row.goods_id, scope.row.id)">编辑</el-button>
<el-button type="text" @click="goodslog(scope.row)">记录</el-button>
</div>
<!-- 点击库存按钮弹出框 -->
<el-dialog title="库存修改" :visible.sync="ejectstock1" width="30%"
:close-on-click-modal="false">
<el-table :data="ommodityInventory" tooltip-effect="dark" style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column prop="two_days_ago_num" label="2天前库存">
<template slot-scope="scope">
<div>
{{ scope.row.two_days_ago_num }}
<el-input v-model="scope.row.two_days_ago_num"></el-input>
</div>
</template>
</el-table-column>
<el-table-column prop="yesterday_num" label="1天前库存">
<template slot-scope="scope">
<div>
{{ scope.row.yesterday_num }}
<el-input v-model="scope.row.yesterday_num"></el-input>
</div>
</template>
</el-table-column>
<el-table-column sortable label="今日到货">
<template slot-scope="scope">
<div>
{{ scope.row.daily.arrived_today_num }}
<el-input v-model="scope.row.daily.arrived_today_num"></el-input>
</div>
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="cancelStock()"> </el-button>
<el-button type="primary" @click="oldStock()"> </el-button>
</span>
</el-dialog>
<!-- <el-button type="text" @click="deleteSku(scope.row)">删除</el-button> -->
</template>
</el-table-column>
</el-table>
@ -294,6 +268,46 @@
</div>
</el-card>
<!-- 点击库存按钮弹出框 -->
<el-dialog title="库存修改" :visible.sync="ejectstock1" width="30%" :close-on-click-modal="false">
<el-table :data="ommodityInventory" tooltip-effect="dark" style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column prop="two_days_ago_num" label="2天前库存">
<template slot-scope="scope">
<div>
<el-input v-model="scope.row.two_days_ago_num" :disabled="true">
</el-input>
<el-input v-model="scope.row.two_days_ago_num"></el-input>
</div>
</template>
</el-table-column>
<el-table-column prop="yesterday_num" label="1天前库存">
<template slot-scope="scope">
<div>
<el-input v-model="scope.row.yesterday_num" :disabled="true"></el-input>
<el-input v-model="scope.row.yesterday_num"></el-input>
</div>
</template>
</el-table-column>
<el-table-column sortable label="今日到货">
<template slot-scope="scope">
<div>
<el-input v-model="scope.row.daily.arrived_today_num" :disabled="true">
</el-input>
<el-input v-model="scope.row.daily.arrived_today_num"></el-input>
</div>
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="cancelStock()"> </el-button>
<el-button type="primary" @click="oldStock()"> </el-button>
</span>
</el-dialog>
<!-- 参考售价弹出确认框 -->
<el-dialog :visible.sync="dialogVisible3" width="20%" :close-on-click-modal="false">
<span>您确定要修改吗?</span>
@ -420,6 +434,7 @@ export default {
], //
//
form: {
external_sku_id: "",
goods_title: "", //
type_id: "", // id
brand_id: "", // id
@ -554,6 +569,7 @@ export default {
//
handleReChoose() {
this.form = {
external_sku_id: "",
goods_title: "", //
type_id: "", // id
brand_id: "", // id
@ -693,8 +709,7 @@ export default {
id: this.ommodityInventory[0].id,
yesterday_num: this.ommodityInventory[0].yesterday_num,
two_days_ago_num: this.ommodityInventory[0].two_days_ago_num,
arrived_today_num:
this.ommodityInventory[0].daily.arrived_today_num,
arrived_today_num: this.ommodityInventory[0].daily.arrived_today_num,
},
];
let stockpatch = {
@ -771,6 +786,11 @@ export default {
});
},
//
deleteSku(rowData) {
},
//
getSTime(val) {
this.form.keyword_value = val.join(" - ");
@ -887,6 +907,18 @@ export default {
this.brand = res.data.data;
});
},
inventorySuccess(response) {
this.$message({
message: response.message,
type: "success",
});
},
inventoryError(err) {
this.$message({
message: res.errorMessage,
type: "error",
});
}
},
watch: {

View File

@ -4,7 +4,7 @@
<el-button type="primary" @click="handAdd">新增</el-button>
<!-- 列表 -->
<div class="table" style="margin-top: 20px">
<div class="table" style="margin-top: 10px">
<el-table ref="multipleTable" :data="tableData" tooltip-effect="dark" style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column prop="name" label="商品种类"> </el-table-column>

View File

@ -13,9 +13,8 @@
<template slot="title">
<span>{{ item.name }}</span>
</template>
<el-menu-item :index="items.code" :key="items.id" v-for="items in item.children">{{
items.name
}}
<el-menu-item :index="children.code" :key="children.id"
v-for="children in item.children">{{ children.name }}
</el-menu-item>
</el-submenu>
</div>
@ -187,65 +186,6 @@ export default {
};
</script>
<style scoped lang="scss">
.table {
background-color: #fff;
ul {
li {
padding: 20px 10px;
.Navigation {
display: flex;
span {
padding: 5px 30px;
border: 1px solid #dcdfe6;
font-size: 14px;
font-weight: 500;
color: #303133;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
.tab {
margin-right: 10px;
flex-shrink: 0;
}
.red {
color: #5470c6;
border: 1px solid #5470c6;
}
.closure {
display: inline-block;
text-align: center;
cursor: pointer;
width: 15px;
height: 15px;
line-height: 15px;
background-color: #ddd;
color: #000;
border-radius: 50%;
font-size: 12px;
}
.red_1 {
background-color: #5470c6;
color: #fff;
}
}
}
li:nth-child(2) {
overflow-x: auto;
}
display: flex;
}
}
.width {
transition: all 0.3s;
opacity: 0;
@ -262,16 +202,9 @@ export default {
height: 100vh;
}
.el-header {
background-color: #b3c0d1;
color: #333;
text-align: center;
}
.el-aside {
background-color: #d3dce6;
color: #333;
text-align: center;
overflow-x: hidden;
}
@ -301,10 +234,8 @@ export default {
}
.box-card {
background-color: #fff;
min-height: calc(100vh - 120px);
margin: 10px;
padding: 20px;
}
.conent {
@ -353,9 +284,6 @@ export default {
border: none;
}
// .el-menu-item {
// margin: 0 20px 10px;
// }
.el-menu-item:hover {
outline: 0 !important;
background: #5470c6 !important;
@ -371,18 +299,4 @@ export default {
.el-menu-item-group__title {
padding: 0 0 !important;
}
.table {
margin-top: 20px;
}
.block {
margin-top: 30px;
}
.from-btn {
display: flex;
justify-content: space-around;
align-content: center;
}
</style>

View File

@ -49,7 +49,7 @@
</el-card>
<!-- 表格 -->
<el-card style="margin-top: 20px" class="box-card">
<el-card style="margin-top: 10px" class="box-card">
<el-table :data="tableData" border style="width: 100%">
<el-table-column prop="id" label="序号" width="75"> </el-table-column>
<el-table-column prop="module" label="模块" width="70"> </el-table-column>

View File

@ -5,19 +5,35 @@
<el-form ref="form" :inline="true" :model="form">
<el-form-item label="查询类别:">
<el-select v-model="form.targetField" placeholder="全部">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="操作用户">
<el-select v-model="form.userId" placeholder="输入操作用户">
<el-option v-for="item in options1" :key="item.id" :label="item.name" :value="item.id">
<el-option
v-for="item in options1"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="操作时间:">
<el-date-picker v-model="value1" type="datetimerange" range-separator="-" start-placeholder=""
end-placeholder="止" value-format="yyyy-MM-dd HH:mm:ss">
<el-date-picker
v-model="value1"
type="datetimerange"
range-separator="-"
start-placeholder="起"
end-placeholder="止"
value-format="yyyy-MM-dd HH:mm:ss"
>
</el-date-picker>
</el-form-item>
<el-form-item>
@ -27,7 +43,7 @@
</el-card>
<!-- 表格 -->
<el-card style="margin-top: 20px">
<el-card style="margin-top: 10px">
<el-table :data="tableData" style="width: 100%" border>
<el-table-column prop="id" label="序号" width="70"> </el-table-column>
<el-table-column prop="created_at" label="时间" width="200">
@ -41,15 +57,21 @@
<el-table-column prop="user.name" label="操作人" width="100">
</el-table-column>
</el-table>
</el-card>
<!-- 分页功能 -->
<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
@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>

View File

@ -0,0 +1,222 @@
<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="店铺">
<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-input v-model="form.goods_name" 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>
<el-button type="primary" @click="handleChoose()">筛选</el-button>
<el-button plain @click="handleReChoose()">重置筛选</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card style="margin-top: 10px">
<el-table 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="category_name" label="分类名称"></el-table-column>
<el-table-column prop="goods_name" label="商品名称"></el-table-column>
<el-table-column prop="external_sku_id" label="编码"></el-table-column>
<el-table-column prop="created_at" label="下载时间"></el-table-column>
<el-table-column label="同步">
<template slot-scope="scope">
<el-switch v-model="scope.row.is_sync" active-color="#13ce66" inactive-color="#ff4949"
:active-value="1" :inactive-value="0" active-text="是" inactive-text="否"
@change="syncChange(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button v-show="scope.row.is_sync && scope.row.external_sku_id" @click="syncStock(scope.row)" type="primary">
同步库存</el-button>
<el-button @click="deleteGoods(scope.row)" type="danger">删除</el-button>
</template>
</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 { platGoodsList, updateSyncStatus, deletePlatGoods, syncStock } from "../../api/plat";
import { storeList } from "../../api/shop";
export default {
data() {
return {
form: {
external_sku_id: "",
goods_name: "",
shop_id: "",
},
tableData: [],
Paginationdata: {}, //
current_page: 1, //
per_page: 15, //
shops: [],
};
},
mounted() {
//
this.getPlatGoodsList();
this.getShopsList();
},
methods: {
//
getPlatGoodsList(params = {}) {
params.page = this.current_page;
params.per_page = this.per_page;
platGoodsList(params).then((res) => {
this.tableData = res.data.data;
this.Paginationdata = res.data.meta;
});
},
getShopsList() {
let page = {
page: 0,
per_page: 999,
};
storeList(page).then((res) => {
this.shops = res.data.data;
});
},
//
handleSizeChange(val) {
//
this.per_page = val;
this.getPlatGoodsList();
},
handleCurrentChange(val) {
//
this.current_page = val;
this.getPlatGoodsList();
},
//
handleChoose() {
this.form = {
...this.form,
page: this.current_page,
per_page: this.per_page,
};
//
const newObj = filterParams(this.form);
function filterParams(obj) {
const _newPar = {};
for (const key in obj) {
// 0
if (
(obj[key] === 0 || obj[key]) &&
obj[key].toString().replace(/(^\s*)|(\s*$)/g, "") !== ""
) {
//
_newPar[key] = obj[key];
}
}
//
return _newPar;
}
this.getPlatGoodsList(newObj);
},
//
handleReChoose() {
this.form = {
external_sku_id: "",
goods_name: "",
shop_id: "",
};
this.getPlatGoodsList();
},
//
syncChange(rowData) {
updateSyncStatus(rowData.id, { is_sync: rowData.is_sync }).then((res) => {
if (200 === res.status) {
this.$message({
message: res.data.message,
type: "success",
});
} else {
this.$message.error(res.data.errorMessage);
}
});
},
//
deleteGoods(rowData) {
this.$alert(rowData.shop.name + ' 店铺下载的 ' + rowData.goods_name, '确认从系统删除?', {
showCancelButton: true,
cancelButtonText: '取消',
confirmButtonText: '确定',
callback: action => {
if ('confirm' === action) {
deletePlatGoods(rowData.id).then((res) => {
if (200 === res.status) {
this.getPlatGoodsList();
this.$message({
message: res.data.message,
type: "success",
});
} else {
this.$message.error(res.data.errorMessage);
}
});
}
}
});
},
//
syncStock(rowData) {
this.$alert(rowData.shop.name + ' 店铺下的 ' + rowData.goods_name, '确认同步库存?', {
showCancelButton: true,
cancelButtonText: '取消',
confirmButtonText: '确定',
callback: action => {
if ('confirm' === action) {
syncStock(rowData.id).then((res) => {
this.$message({
message: 200 === res.status ? res.data.message : res.data.errorMessage,
});
});
}
}
});
}
},
};
</script>
<style lang="scss" scoped>
.block {
margin-top: 20px;
}
</style>

View File

@ -3,7 +3,7 @@
<!-- 新增按钮 -->
<el-button type="primary" @click="handAdd">新增</el-button>
<div class="table" style="margin-top: 20px">
<div class="table" style="margin-top: 10px">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="id" label="ID" width="180"> </el-table-column>
<el-table-column prop="name" label="店铺名称" width="180">

View File

@ -21,7 +21,7 @@
<el-button type="primary" @click="dialogVisible2 = true">新增</el-button>
<!-- 角色列表 -->
<div class="table" style="margin-top: 20px">
<div class="table" style="margin-top: 10px">
<el-table :data="tableList" style="width: 100%">
<el-table-column prop="id" label="ID"> </el-table-column>
<el-table-column prop="name" label="角色名称"> </el-table-column>

View File

@ -75,7 +75,7 @@
<el-button type="primary" @click="dialogVisible = true">新增</el-button>
<!-- 用户列表 -->
<div class="table" style="margin-top: 20px">
<div class="table" style="margin-top: 10px">
<template>
<el-table :data="tableList" style="width: 100%">
<el-table-column prop="id" label="ID"></el-table-column>

View File

@ -2,7 +2,7 @@ module.exports = {
lintOnSave: false,
publicPath: "./", // 配置打包之后的相对路径
devServer: {
open: true, // 设置浏览器自动打开项目
open: false, // 设置浏览器自动打开项目
port: 8080, // 开发服务器运行端口号
overlay: {
warnings: false,
@ -13,7 +13,7 @@ module.exports = {
"/api": {
// target: 'http://doc.ii090.com/mock/267/',
// target: "http://erp.staging.miaoxuan66.cn",
target: "http://erp.chutang66.com",
target: "http://172.31.68.32:81",
changeOrigin: true, // 开启代理
pathRewrite: {
// 重命名

View File

@ -57,6 +57,11 @@ return [
'name' => '店铺订单',
'parent_id' => 2,
],
'goods_sku.inventory' => [
'id' => 29,
'name' => '盘点导入',
'parent_id' => 2,
],
'GOODS_TYPE' => [
'id' => 3,
'name' => '商品种类',
@ -252,14 +257,24 @@ return [
'name' => '平台',
'parent_id' => 0,
],
'plat_goods.index' => [
'PLAT_GOODS_LIST' => [
'id' => 120,
'name' => '货品列表',
'parent_id' => 12,
],
'plat_goods.index' => [
'id' => 1200,
'name' => '货品列表',
'parent_id' => 120,
],
'plat_goods.update' => [
'id' => 121,
'name' => '同步更新设置',
'parent_id' => 12,
'id' => 1201,
'name' => '同步库存',
'parent_id' => 120,
],
'plat_goods.destroy' => [
'id' => 1202,
'name' => '删除',
'parent_id' => 120,
],
];

View File

@ -1 +0,0 @@
{}

View File

@ -32,6 +32,8 @@ Route::middleware(['auth:api', 'check.permissions'])->group(function () {
Route::resource('goods_skus', 'Goods\GoodsSkusController', ['only' => ['index', 'show', 'update', 'store']]);
Route::patch('batch/goods_skus', [GoodsSkusController::class, 'batchUpdate'])->name('goods_sku.batch_update');
Route::patch('single/goods_skus/{id}', [GoodsSkusController::class, 'updateField'])->name('goods_sku.single_update');
// 盘点导入
Route::post('inventory/goods_skus', [GoodsSkusController::class, 'inventoryImport'])->name('goods_sku.inventory');
// 店铺
Route::resource('shops', 'Shop\ShopsController', ['only' => ['index', 'store', 'show', 'update', 'destroy']]);
Route::get('count/orders/num', [ShopsController::class, 'countOrdersNumWithSkuCode'])->name('goods_sku.orders_num');
@ -44,8 +46,11 @@ Route::middleware(['auth:api', 'check.permissions'])->group(function () {
// 'store', 'show', 'update', 'destroy'
]]);
Route::post('upload', [UploadController::class, 'store'])->name('upload.file');
// 平台
Route::resource('plat_goods', 'Business\BusinessGoodsSkusController', ['only' => ['index', 'update', 'destroy']]);
Route::post('plat/sync/{id}/stock', [BusinessGoodsSkusController::class, 'syncStock'])->name('plat.sync.stock');
});
// 登录
Route::post('/auth/login', [LoginController::class, 'login'])->name('auth.login');
// 菜单
@ -53,10 +58,8 @@ Route::resource('menus', 'Menu\MenusController', ['only' => ['index',
// 'store', 'show', 'update', 'destroy'
]])->middleware('auth:api');
// 获取平台列表
Route::get('shop_platforms', [ShopsController::class, 'getPlatList'])->name('plat.list')->middleware('auth:api');
// 妙选商城数据推送
Route::post('business', [ShopsController::class, 'business'])->name('shop.put.business');
// 平台
Route::resource('plat_goods', 'Business\BusinessGoodsSkusController', ['only' => ['index', 'update']]);
Route::post('plat/sync/stock', [BusinessGoodsSkusController::class, 'syncStock'])->name('plat.sync.stock');